C语言总结——二叉树

来源:互联网 发布:足球数据分析师 编辑:程序博客网 时间:2024/06/03 21:48

这是借鉴了大牛们的二叉树算法,加上我自己对代码调试的整理出来的。

其中有一篇写得很好,很全:http://blog.csdn.net/luckyxiaoqiang/article/details/7518888

下面分别对二叉树的操作函数做了一定的汇总

list.h

#ifndef _LINUX_LIST_H__#define _LINUX_LIST_H__//#define NULL(void*)0x0#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)/** * container_of - cast a member of a structure out to the containing structure * @ptr:        the pointer to the member. * @type:       the type of the container struct this is embedded in. * @member:     the name of the member within the struct. * */#define container_of(ptr, type, member) ({                      \const typeof( ((type *)0)->member ) *__mptr = (ptr);    \(type *)( (char *)__mptr - offsetof(type,member) );})/******************************************struct student{    int num;    int date;    int height;    int weight;    struct list_head list;};struct student *tmp_student;struct list_head *pos;tmp_student = list_entry(pos,struct student,list);0x00000000->|----|struct num|----|struct date|----|struct height|----|struct weight0x0000000F->|----|struct listconst typeof( ((struct student *)0)->list ) *__mptr = (pos):0x0000000F((size_t) &((struct student *)0)->list):0x0000000F-0x00000000=F(struct student *)( (char *)__mptr - offsetof(struct student,list) ):0x0000000F-F=0x00000000*******************************************/struct list_head {struct list_head *next, *prev;};static inline void INIT_LIST_HEAD(struct list_head *list){list->next = list;list->prev = list;}/* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */static inline void __list_add(struct list_head *new,      struct list_head *prev,      struct list_head *next){next->prev = new;new->next = next;new->prev = prev;prev->next = new;}/** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */static inline void list_add(struct list_head *new, struct list_head *head){__list_add(new, head, head->next);}/** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */static inline void list_add_tail(struct list_head *new, struct list_head *head){__list_add(new, head->prev, head);}/* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */static inline void __list_del(struct list_head * prev, struct list_head * next){next->prev = prev;prev->next = next;}static inline void list_del(struct list_head *entry){__list_del(entry->prev, entry->next);entry->next = NULL;entry->prev = NULL;}/** * list_empty - tests whether a list is empty * @head: the list to test. */static inline int list_empty(const struct list_head *head){return head->next == head;}/** * list_entry - get the struct for this entry * @ptr:the &struct list_head pointer. * @type:the type of the struct this is embedded in. * @member:the name of the list_struct within the struct. */#define list_entry(ptr, type, member) \container_of(ptr, type, member)/** * list_for_each-iterate over a list * @pos:the &struct list_head to use as a loop cursor. * @head:the head for your list. *NULL!=pos:add by qinfan */#define list_for_each(pos, head) \for (pos = (head)->next; pos != (head)&&NULL!=pos; pos = pos->next)#endif

qftree.h

/*******************************************************************Author:qinfan*Date:2015.03.18*File:qftree.h******************************************************************/#ifndef _QF_TREE_H__#define _QF_TREE_H__#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include "list.h"typedef struct tree_node{int data;struct tree_node *left;struct tree_node *right;}TreeNode;typedef struct list_node{TreeNode *pTnode;struct list_head list;}ListNode;typedef struct queue{    int itemNum;    ListNode *head;    ListNode *tail;}Queue;/*********************二叉树操作函数集**************************************//*创建二叉树节点*/TreeNode *creatTreeNode(int date);/*插入节点到二叉树中,创建一颗查找二叉树,中序遍历就是按照顺序显示*/int insertSeekTree(TreeNode *pNode, TreeNode *pRoot);/*求二叉树的节点个数*/int getTreeNodeNum(TreeNode * pRoot);/*求二叉树的深度*/int getTreeDepth(TreeNode * pRoot);/*求叶子节点的个数*/int getLeafNodeNum(TreeNode * pRoot);/*比较两颗二叉树是否相等*/int CompareTree(TreeNode* tree1,TreeNode* tree2);/*创建一颗完全二叉树*/TreeNode *creatCompleteTree(int start, int end);/*插入节点到一颗完全二叉树*/int  insertCompleteTree(TreeNode *pNode, TreeNode *pRoot);/*先序遍历*/void preorderTraverse(TreeNode *pRoot);/*中序遍历*/void inorderTraverse(TreeNode *pRoot);/*后序遍历*/void postorderTraverse(TreeNode *pRoot);/*按层遍历二叉树,采用队列的方式*/void layerTraverse(TreeNode *pRoot);/*按层遍历二叉树,采用递归的方式*/void levelTraverseIn(TreeNode *pRoot);/*销毁二叉树*/void destroyTree(TreeNode *pRoot);/*********************队列操作函数集*************************************//*构造一个空队列*/Queue *InitQueue();/*判断队列是否为空*/int IsQueueEmpty(Queue *pQueue);/*销毁一个队列*/void DestroyQueue(Queue *pQueue);/*返回队列大小*/int GetQueueSize(Queue *pQueue);/*返回队头元素*/ListNode *GetQueueHead(Queue *pQueue);/*返回队尾元素*/ListNode *GetQueueTail(Queue *pQueue);/*初始化链表*/void initList(struct list_head *pList);/*将新元素入队*/int EnQueue(struct list_head *pList, Queue *pQueue, TreeNode *pTreeNode);/*队头元素出队*/int DeQueue(struct list_head *pList, Queue *pQueue, TreeNode *pTreeNode);/*打印队列中的数值*/static void Print(void *pItem);/*遍历队列并对各数据项调用show函数*/void QueueTraverse(struct list_head *pList, Queue *pQueue,void (*show)(void *pItem));/******************************************************************************************/#endif

qftree.c

/*******************************************************************Author:qinfan*Date:2015.03.18*File:qftree.c******************************************************************/#include "qftree.h"/******************************************************************************************/TreeNode *creatTreeNode(int date){TreeNode *pNode=(TreeNode*)malloc(sizeof(TreeNode));assert(pNode);memset(pNode, 0, sizeof(TreeNode));pNode->data = date;return pNode;}int  insertSeekTree(TreeNode *pNode, TreeNode *pRoot){assert(pNode);assert(pRoot);/*判断传入的指针是否合法*/if(pRoot->data >= pNode->data){/*小在左*/if(!pRoot->left){pRoot->left = pNode;}else{insertSeekTree(pNode, pRoot = pRoot->left);}}else if(pRoot->data < pNode->data){/*大再右*/if(!pRoot->right){pRoot->right = pNode;}else{insertSeekTree(pNode, pRoot = pRoot->right);}}else{printf("ERROR:-----%s-----pNode=%p-----pRoot=%p-----data=%d-----%d-----\n", __FUNCTION__, pNode, pRoot, pNode->data,__LINE__);}return 0;}int getTreeNodeNum(TreeNode * pRoot){if(!pRoot)return 0;// 递归出口return getTreeNodeNum(pRoot->left) + getTreeNodeNum(pRoot->right) + 1;}int getTreeDepth(TreeNode * pRoot){if(!pRoot)return 0;// 递归出口int depthLeft = getTreeDepth(pRoot->left);int depthRight = getTreeDepth(pRoot->right);return depthLeft > depthRight ? (depthLeft + 1) : (depthRight + 1); }int getLeafNodeNum(TreeNode * pRoot){if(!pRoot)return 0;// 递归出口if((!pRoot->left)&&(!pRoot->right))return 1;int LeftLeafNodeNum = getLeafNodeNum(pRoot->left);int RightLeafNodeNum = getLeafNodeNum(pRoot->right);return (LeftLeafNodeNum+RightLeafNodeNum); }int CompareTree(TreeNode* tree1,TreeNode* tree2){if(NULL == tree1&& NULL == tree2)return 1;if(tree1&& tree2){if(tree1->data == tree2->data)return CompareTree(tree1->left, tree2->left) &&CompareTree(tree1->right, tree2->right);}return 0;}TreeNode *creatCompleteTree(int start, int end){printf("start=%d, end=%d\n", start, end);if(start > end)return NULL;TreeNode *pRoot = creatTreeNode(start);pRoot->left = (2*start <= end)?creatCompleteTree(2*start, end):NULL;pRoot->right = ((2*start+1) <= end)?creatCompleteTree(2*start+1, end):NULL;return pRoot;}int insertCompleteTree(TreeNode *pNode, TreeNode *pRoot){assert(pNode);assert(pRoot);/*判断传入的指针是否合法*/if(!pRoot->left){/*如果该树只有根节点插入即可*/pRoot->left = pNode;}else if(!pRoot->right){pRoot->right= pNode;}else{/*如果不是満二叉树,找到第一个有一个子树为空的节点即可否则,则需要找到最下一层的最左结点。利用完全二叉树的性质,首先判断左子树的最右结点与右子树的最右结点高度,如果相等,只需要插入到左子树即可,否则插入右子树。*/int leftCount = 0;int rightCount = 0;TreeNode *tmp = pRoot->left;while(tmp){leftCount++;tmp = tmp->right;}tmp = pRoot->right;while(tmp){rightCount++;tmp = tmp->right;}if(leftCount == rightCount){return insertCompleteTree(pNode, pRoot->left);}else{return insertCompleteTree(pNode, pRoot->right);}}return 0;}void preorderTraverse(TreeNode *pRoot){if(!pRoot)return;printf("preorderTraverse:%d\n", pRoot->data);preorderTraverse(pRoot->left);preorderTraverse(pRoot->right);}void inorderTraverse(TreeNode *pRoot){if(!pRoot)return;inorderTraverse(pRoot->left);printf("inorderTraverse:%d\n", pRoot->data);inorderTraverse(pRoot->right);}void postorderTraverse(TreeNode *pRoot){if(!pRoot)return;postorderTraverse((pRoot->left));postorderTraverse((pRoot->right));printf("postorderTraverse:%d\n", pRoot->data);}void layerTraverse(TreeNode *pRoot){Queue *pQueue = NULL;TreeNode getQueueItemDate;ListNode *pListNode = NULL;struct list_head pList;memset(&pList, 0, sizeof pList);memset(&getQueueItemDate, 0, sizeof getQueueItemDate);pQueue = InitQueue();initList(&pList);EnQueue(&pList, pQueue, pRoot);while(!IsQueueEmpty(pQueue)){memset(&getQueueItemDate, 0, sizeof getQueueItemDate);DeQueue(&pList, pQueue, &getQueueItemDate);printf("-----%s-----getQueueItemDate=%d-----%d-----\n", __FUNCTION__,getQueueItemDate.data,__LINE__);/*头结点出队后,左右节点依次入队*/if(getQueueItemDate.left)EnQueue(&pList, pQueue, getQueueItemDate.left);if(getQueueItemDate.right)EnQueue(&pList, pQueue, getQueueItemDate.right);QueueTraverse(&pList, pQueue, Print);}DestroyQueue(pQueue);return;}static int levelTraverse(TreeNode *pRoot, int level){if (!pRoot || level < 0)return 0;if (0 == level) {/*如果指定的Tree是空的,那么就直接返回0,当返回0的时候,我们就结束循环,说明没有节点可以打印了。存在重复访问的情况,就是第0层访问的次数最多,第1层次之。所以这个递归的方法不是很有效的方法。*/printf("levelTraverse:%d\n", pRoot->data);return 1;}return levelTraverse(pRoot->left, level - 1) + levelTraverse(pRoot->right, level - 1);}void levelTraverseIn(TreeNode *pRoot){int i = 0; while(1)if (!levelTraverse(pRoot, i++))break;}void destroyTree(TreeNode *pRoot){if(!pRoot)return;destroyTree(pRoot->left);destroyTree(pRoot->right);printf("destroyTree:%d\n", pRoot->data);free(pRoot);pRoot = NULL;}/******************************************************************************************/Queue *InitQueue(){Queue *pQueue = (Queue *)malloc(sizeof(Queue));assert(pQueue);memset(pQueue, 0, sizeof(Queue));return pQueue;}int IsQueueEmpty(Queue *pQueue){if(NULL == pQueue->head&&\   NULL == pQueue->tail&&\   0 == pQueue->itemNum)return 1;elsereturn 0;}void DestroyQueue(Queue *pQueue){assert(pQueue);free(pQueue);}int GetQueueSize(Queue *pQueue){return pQueue->itemNum;}ListNode *GetQueueHead(Queue *pQueue){if(!IsQueueEmpty(pQueue))return pQueue->head;elsereturn NULL;}ListNode *GetQueueTail(Queue *pQueue){if(!IsQueueEmpty(pQueue))return pQueue->tail;elsereturn NULL;}ListNode *creatListNode(TreeNode *pTreeNode){ListNode *pListNode = (ListNode*)malloc(sizeof(ListNode));assert(pListNode);memset(pListNode, 0, sizeof(ListNode));pListNode->pTnode = pTreeNode;return pListNode;}void initList(struct list_head *pList){assert(pList);INIT_LIST_HEAD(pList);return;}int EnQueue(struct list_head *pList, Queue *pQueue, TreeNode *pTreeNode){assert(pList);assert(pQueue);assert(pTreeNode);ListNode *pListNode = creatListNode(pTreeNode);if(pListNode != NULL){/*从队尾插入*/list_add_tail( &pListNode->list, pList);if(IsQueueEmpty(pQueue)){pQueue->head = pListNode;}pQueue->tail = pListNode;pQueue->itemNum++;}return 0;}int DeQueue(struct list_head *pList, Queue *pQueue, TreeNode *pTreeNode){assert(pList);assert(pQueue);ListNode *getListNode = NULL;ListNode *pListNode = pQueue->head;if(!IsQueueEmpty(pQueue)&&pTreeNode){/*因为要free空间,所有要把数据转移*/memcpy(pTreeNode, pListNode->pTnode, sizeof(TreeNode));list_del(&pListNode->list);free(pListNode);if(pList->next){/*取出头结点*/getListNode = list_entry(pList->next, ListNode, list);}pQueue->itemNum--;if(pQueue->itemNum==0){pQueue->head = NULL;pQueue->tail = NULL;}else{/*让队列的头指针重新赋值*/pQueue->head = getListNode;}}return 0;}static void Print(void *pItem){TreeNode *tmp = (TreeNode*)pItem;printf("-----%s-----%d-----%d-----\n", __FUNCTION__,tmp->data,__LINE__);}void QueueTraverse(struct list_head *pList, Queue *pQueue,void (*show)(void *pItem)){#if 0ListNode *pListNode = pQueue->head;struct list_head *pos = NULL;int i = pQueue->itemNum;while(i--){show(pListNode->pTnode);list_for_each(pos, pList)pListNode = list_entry(pos, ListNode, list);}#elseListNode *pListNode = pQueue->head;struct list_head *pos = NULL;list_for_each(pos, pList){pListNode = list_entry(pos, ListNode, list);show(pListNode->pTnode);}#endif}/******************************************************************************************/

qfmain.c

/*******************************************************************Author:qinfan*Date:2015.03.18*File:qfmain.c******************************************************************/#include "qftree.h"/******************************************************************************************/int main(int argc, char *argv[]){int i = 0;int inputNum = 0;int treeSize = 0;TreeNode *pRoot = NULL;TreeNode *pNode = NULL;printf("Create a tree size you want:");scanf("%d", &treeSize);inputNum = rand()%100;printf("inputNum=%d\n", inputNum);pRoot = creatTreeNode(inputNum);/*创建根节点*/for(i=1; i<treeSize; i++){inputNum = rand()%100;printf("inputNum=%d\n", inputNum);pNode = creatTreeNode(inputNum);insertSeekTree(pNode, pRoot);}printf("getTreeNodeNum=%d\n", getTreeNodeNum(pRoot));printf("getTreeDepth=%d\n", getTreeDepth(pRoot));printf("getLeafNodeNum=%d\n", getLeafNodeNum(pRoot));printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);preorderTraverse(pRoot);printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);inorderTraverse(pRoot);printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);postorderTraverse(pRoot);printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);destroyTree(pRoot);printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);pRoot = creatCompleteTree(1, 10);preorderTraverse(pRoot);printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);pNode = creatTreeNode(50);insertCompleteTree(pNode, pRoot);inorderTraverse(pRoot);TreeNode *pRoot1 = creatCompleteTree(1, 10);printf("CompareTree=%d\n", CompareTree(pRoot, pRoot));/*1*/printf("CompareTree1=%d\n", CompareTree(pRoot, pRoot1));/*0*/printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);levelTraverseIn(pRoot);printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);layerTraverse(pRoot);printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);destroyTree(pRoot);destroyTree(pRoot1);printf("-----%s-----%s-----%s-----%s-----%d-----\n", __FILE__, __DATE__,__TIME__,__FUNCTION__,__LINE__);return 0;}

在这里补充一句,为了检测内存是否泄漏,使用valgrind 工具
valgrind --tool=memcheck --leak-check=full ./a.out

如果为以下打印,说明内存没有泄露

==5720== ==5720== HEAP SUMMARY:==5720==     in use at exit: 0 bytes in 0 blocks==5720==   total heap usage: 43 allocs, 43 frees, 516 bytes allocated==5720== ==5720== All heap blocks were freed -- no leaks are possible==5720== ==5720== For counts of detected and suppressed errors, rerun with: -v==5720== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

或者

valgrind --track-fds=yes --leak-check=full --undef-value-errors=yes ./a.out

==5728== ==5728== FILE DESCRIPTORS: 3 open at exit.==5728== Open file descriptor 2: /dev/pts/6==5728==    <inherited from parent>==5728== ==5728== Open file descriptor 1: /dev/pts/6==5728==    <inherited from parent>==5728== ==5728== Open file descriptor 0: /dev/pts/6==5728==    <inherited from parent>==5728== ==5728== ==5728== HEAP SUMMARY:==5728==     in use at exit: 0 bytes in 0 blocks==5728==   total heap usage: 43 allocs, 43 frees, 516 bytes allocated==5728== ==5728== All heap blocks were freed -- no leaks are possible==5728== ==5728== For counts of detected and suppressed errors, rerun with: -v==5728== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)



0 0
原创粉丝点击