数据结构笔记-----树
树的定义
树操作的实现
文件树
树的存储结构
GTree.h
<strong><span style="font-size:18px;">#ifndef _GTREE_H_ #define _GTREE_H_ typedef void GTree; typedef void GTreeData; typedef void (GTree_Printf)(GTreeData*); GTree* GTree_Create(); void GTree_Destroy(GTree* tree); void GTree_Clear(GTree* tree); int GTree_Insert(GTree* tree, GTreeData* data, int pPos); GTreeData* GTree_Delete(GTree* tree, int pos); GTreeData* GTree_Get(GTree* tree, int pos); GTreeData* GTree_Root(GTree* tree); int GTree_Height(GTree* tree); int GTree_Count(GTree* tree); int GTree_Degree(GTree* tree); void GTree_Display(GTree* tree, GTree_Printf* pFunc, int gap, char div); #endif </span></strong>
GTree.c
<strong><span style="font-size:18px;">#include <stdio.h> #include <malloc.h> #include "GTree.h" #include "LinkList.h" typedef struct _tag_GTreeNode GTreeNode; struct _tag_GTreeNode { GTreeData* data; GTreeNode* parent; LinkList* child; }; typedef struct _tag_TLNode TLNode; struct _tag_TLNode { LinkListNode header; GTreeNode* node; }; static void recursive_display(GTreeNode* node, GTree_Printf* pFunc, int format, int gap, char div) { //数据 int i = 0; if( (node != NULL) && (pFunc != NULL) ) { for(i=0; i<format; i++) { printf("%c", div); } //符号 pFunc(node->data); printf("\n"); for(i=0; i<LinkList_Length(node->child); i++) { TLNode* trNode = (TLNode*)LinkList_Get(node->child, i); recursive_display(trNode->node, pFunc, format + gap, gap, div); } } } static void recursive_delete(LinkList* list, GTreeNode* node) { if( (list != NULL) && (node != NULL) ) { GTreeNode* parent = node->parent; int index = -1; int i = 0; for(i=0; i<LinkList_Length(list); i++) { TLNode* trNode = (TLNode*)LinkList_Get(list, i); if( trNode->node == node ) { LinkList_Delete(list, i); free(trNode); index = i; break; } } if( index >= 0 )//从父结点删除 { if( parent != NULL ) { for(i=0; i<LinkList_Length(parent->child); i++) { TLNode* trNode = (TLNode*)LinkList_Get(parent->child, i); if( trNode->node == node ) { LinkList_Delete(parent->child, i); free(trNode); break; } } } while( LinkList_Length(node->child) > 0 )//将孩子们也删掉 { TLNode* trNode = (TLNode*)LinkList_Get(node->child, 0); recursive_delete(list, trNode->node); } LinkList_Destroy(node->child); free(node); } } } static int recursive_height(GTreeNode* node) { int ret = 0; if( node != NULL ) { int subHeight = 0; int i = 0; for(i=0; i<LinkList_Length(node->child); i++) { TLNode* trNode = (TLNode*)LinkList_Get(node->child, i); subHeight = recursive_height(trNode->node); if( ret < subHeight ) { ret = subHeight; } } ret = ret + 1; } //加上根结点 return ret; } static int recursive_degree(GTreeNode* node) { int ret = -1; if( node != NULL ) { int subDegree = 0; int i = 0; ret = LinkList_Length(node->child); for(i=0; i<LinkList_Length(node->child); i++) { TLNode* trNode = (TLNode*)LinkList_Get(node->child, i); subDegree = recursive_degree(trNode->node); if( ret < subDegree ) { ret = subDegree; } } } return ret; } GTree* GTree_Create() { return LinkList_Create(); } void GTree_Destroy(GTree* tree) { GTree_Clear(tree); LinkList_Destroy(tree); } void GTree_Clear(GTree* tree) { GTree_Delete(tree, 0); } int GTree_Insert(GTree* tree, GTreeData* data, int pPos) { LinkList* list = (LinkList*)tree; int ret = (list != NULL) && (data != NULL) && (pPos < LinkList_Length(list)); if( ret ) { TLNode* trNode = (TLNode*)malloc(sizeof(TLNode)); TLNode* cldNode = (TLNode*)malloc(sizeof(TLNode)); TLNode* pNode = (TLNode*)LinkList_Get(list, pPos); GTreeNode* cNode = (GTreeNode*)malloc(sizeof(GTreeNode)); ret = (trNode != NULL) && (cldNode != NULL) && (cNode != NULL); if( ret ) { cNode->data = data; cNode->parent = NULL; cNode->child = LinkList_Create(); trNode->node = cNode; cldNode->node = cNode; LinkList_Insert(list, (LinkListNode*)trNode, LinkList_Length(list)); if( pNode != NULL ) { cNode->parent = pNode->node; LinkList_Insert(pNode->node->child, (LinkListNode*)cldNode, LinkList_Length(pNode->node->child)); } } else { free(trNode); free(cldNode); free(cNode); } } return ret; } GTreeData* GTree_Delete(GTree* tree, int pos) { TLNode* trNode = (TLNode*)LinkList_Get(tree, pos); GTreeData* ret = NULL; if( trNode != NULL ) { ret = trNode->node->data; recursive_delete(tree, trNode->node); } return ret; } GTreeData* GTree_Get(GTree* tree, int pos) { TLNode* trNode = (TLNode*)LinkList_Get(tree, pos); GTreeData* ret = NULL; if( trNode != NULL ) { ret = trNode->node->data; } return ret; } GTreeData* GTree_Root(GTree* tree) { return GTree_Get(tree, 0); } int GTree_Height(GTree* tree) { TLNode* trNode = (TLNode*)LinkList_Get(tree, 0); int ret = 0; if( trNode != NULL ) { ret = recursive_height(trNode->node); } return ret; } int GTree_Count(GTree* tree) { return LinkList_Length(tree); } int GTree_Degree(GTree* tree) { TLNode* trNode = (TLNode*)LinkList_Get(tree, 0); int ret = -1; if( trNode != NULL ) { ret = recursive_degree(trNode->node); } return ret; } void GTree_Display(GTree* tree, GTree_Printf* pFunc, int gap, char div) { TLNode* trNode = (TLNode*)LinkList_Get(tree, 0); if( (trNode != NULL) && (pFunc != NULL) ) { recursive_display(trNode->node, pFunc, 0, gap, div); } } </span></strong>
main.c
<strong><span style="font-size:18px;">#include <stdio.h> #include "GTree.h" /* run this program using the console pauser or add your own getch, system("pause") or input loop */ void printf_data(GTreeData* data) { printf("%c", (int)data); } int main(int argc, char *argv[]) { GTree* tree = GTree_Create(); int i = 0; GTree_Insert(tree, (GTreeData*)'A', -1); GTree_Insert(tree, (GTreeData*)'B', 0); GTree_Insert(tree, (GTreeData*)'C', 0); GTree_Insert(tree, (GTreeData*)'D', 0); GTree_Insert(tree, (GTreeData*)'E', 1); GTree_Insert(tree, (GTreeData*)'F', 1); GTree_Insert(tree, (GTreeData*)'H', 3); GTree_Insert(tree, (GTreeData*)'I', 3); GTree_Insert(tree, (GTreeData*)'J', 3); printf("Tree Height: %d\n", GTree_Height(tree)); printf("Tree Degree: %d\n", GTree_Degree(tree)); printf("Full Tree:\n"); GTree_Display(tree, printf_data, 2, ' '); printf("Get Tree Data:\n"); for(i=0; i<GTree_Count(tree); i++) { printf_data(GTree_Get(tree, i)); printf("\n"); } printf("Get Root Data:\n"); printf_data(GTree_Root(tree)); printf("\n"); GTree_Delete(tree, 3); printf("After Deleting D:\n"); GTree_Display(tree, printf_data, 2, '-'); GTree_Clear(tree); printf("After Clearing Tree:\n"); GTree_Display(tree, printf_data, 2, '.'); GTree_Destroy(tree); return 0; }</span></strong>
小结
二叉树定义
另一种树结构模型
孩子兄弟表示法
实现较简单
小结
思考:
二叉树的深层性质
小结
理解和掌握二叉树的深层次特性有助于我们设计出更加精巧高效的算法
创建二叉树
指路法定位结点
二叉树存储结构
二叉树的操作
二叉树结构的实现
BTree.h
<strong><span style="font-size:18px;">#ifndef _BTREE_H_ #define _BTREE_H_ #define BT_LEFT 0 #define BT_RIGHT 1 typedef void BTree; typedef unsigned long long BTPos; typedef struct _tag_BTreeNode BTreeNode; struct _tag_BTreeNode { BTreeNode* left; BTreeNode* right; }; typedef void (BTree_Printf)(BTreeNode*); BTree* BTree_Create(); void BTree_Destroy(BTree* tree); void BTree_Clear(BTree* tree); int BTree_Insert(BTree* tree, BTreeNode* node, BTPos pos, int count, int flag); BTreeNode* BTree_Delete(BTree* tree, BTPos pos, int count); BTreeNode* BTree_Get(BTree* tree, BTPos pos, int count); BTreeNode* BTree_Root(BTree* tree); int BTree_Height(BTree* tree); int BTree_Count(BTree* tree); int BTree_Degree(BTree* tree); void BTree_Display(BTree* tree, BTree_Printf* pFunc, int gap, char div); #endif </span></strong>
<strong><span style="font-size:18px;"></pre><p></p><p>BTree.c</p><pre name="code" class="objc">#include <stdio.h> #include <malloc.h> #include "BTree.h" typedef struct _tag_BTree TBTree; struct _tag_BTree { int count; BTreeNode* root; }; static void recursive_display(BTreeNode* node, BTree_Printf* pFunc, int format, int gap, char div) // O(n) { int i = 0; if( (node != NULL) && (pFunc != NULL) ) { for(i=0; i<format; i++) { printf("%c", div); } pFunc(node); printf("\n"); if( (node->left != NULL) || (node->right != NULL) ) { recursive_display(node->left, pFunc, format + gap, gap, div); recursive_display(node->right, pFunc, format + gap, gap, div); }//利用递归来实现空的地方预留位置 } else { for(i=0; i<format; i++) { printf("%c", div); } printf("\n"); } } static int recursive_count(BTreeNode* root) // O(n) { int ret = 0; if( root != NULL ) { ret = recursive_count(root->left) + 1 + recursive_count(root->right); } return ret; } static int recursive_height(BTreeNode* root) // O(n) { int ret = 0; if( root != NULL ) { int lh = recursive_height(root->left); int rh = recursive_height(root->right); ret = ((lh > rh) ? lh : rh) + 1; } return ret; } static int recursive_degree(BTreeNode* root) // O(n) { int ret = 0; if( root != NULL ) { if( root->left != NULL ) { ret++; } if( root->right != NULL ) { ret++; } if( ret == 1 ) { int ld = recursive_degree(root->left); int rd = recursive_degree(root->right); if( ret < ld ) { ret = ld; } if( ret < rd ) { ret = rd; } } } return ret; } BTree* BTree_Create() // O(1) { TBTree* ret = (TBTree*)malloc(sizeof(TBTree)); if( ret != NULL ) { ret->count = 0; ret->root = NULL; } return ret; } void BTree_Destroy(BTree* tree) // O(1) { free(tree); } void BTree_Clear(BTree* tree) // O(1) { TBTree* btree = (TBTree*)tree; if( btree != NULL ) { btree->count = 0; btree->root = NULL; } } int BTree_Insert(BTree* tree, BTreeNode* node, BTPos pos, int count, int flag) // O(n) { TBTree* btree = (TBTree*)tree; int ret = (btree != NULL) && (node != NULL) && ((flag == BT_LEFT) || (flag == BT_RIGHT)); int bit = 0; if( ret ) { BTreeNode* parent = NULL; BTreeNode* current = btree->root; node->left = NULL; node->right = NULL; while( (count > 0) && (current != NULL) ) { bit = pos & 1; pos = pos >> 1; parent = current; if( bit == BT_LEFT ) { current = current->left; } else if( bit == BT_RIGHT ) { current = current->right; } count--; } if( flag == BT_LEFT ) { node->left = current; } else if( flag == BT_RIGHT ) { node->right = current; } if( parent != NULL ) { if( bit == BT_LEFT ) { parent->left = node; } else if( bit == BT_RIGHT ) { parent->right = node; } } else { btree->root = node; } btree->count++; } return ret; } BTreeNode* BTree_Delete(BTree* tree, BTPos pos, int count) // O(n) { TBTree* btree = (TBTree*)tree; BTreeNode* ret = NULL; int bit = 0; if( btree != NULL ) { BTreeNode* parent = NULL; BTreeNode* current = btree->root; while( (count > 0) && (current != NULL) ) { bit = pos & 1; pos = pos >> 1; parent = current; if( bit == BT_LEFT ) { current = current->left; } else if( bit == BT_RIGHT ) { current = current->right; } count--; } if( parent != NULL ) { if( bit == BT_LEFT ) { parent->left = NULL; } else if( bit == BT_RIGHT ) { parent->right = NULL; } } else { btree->root = NULL; } ret = current; btree->count = btree->count - recursive_count(ret); } return ret; } BTreeNode* BTree_Get(BTree* tree, BTPos pos, int count) // O(n) { TBTree* btree = (TBTree*)tree; BTreeNode* ret = NULL; int bit = 0; if( btree != NULL ) { BTreeNode* current = btree->root; while( (count > 0) && (current != NULL) ) { bit = pos & 1; pos = pos >> 1; if( bit == BT_LEFT ) { current = current->left; } else if( bit == BT_RIGHT ) { current = current->right; } count--; } ret = current; } return ret; } BTreeNode* BTree_Root(BTree* tree) // O(1) { TBTree* btree = (TBTree*)tree; BTreeNode* ret = NULL; if( btree != NULL ) { ret = btree->root; } return ret; } int BTree_Height(BTree* tree) // O(n) { TBTree* btree = (TBTree*)tree; int ret = 0; if( btree != NULL ) { ret = recursive_height(btree->root); } return ret; } int BTree_Count(BTree* tree) // O(1) { TBTree* btree = (TBTree*)tree; int ret = 0; if( btree != NULL ) { ret = btree->count; } return ret; } int BTree_Degree(BTree* tree) // O(n) { TBTree* btree = (TBTree*)tree; int ret = 0; if( btree != NULL ) { ret = recursive_degree(btree->root); } return ret; } void BTree_Display(BTree* tree, BTree_Printf* pFunc, int gap, char div) // O(n) { TBTree* btree = (TBTree*)tree; if( btree != NULL ) { recursive_display(btree->root, pFunc, 0, gap, div); } }</span></strong>
main.c
<strong><span style="font-size:18px;">#include <stdio.h> #include <stdlib.h> #include "BTree.h" /* run this program using the console pauser or add your own getch, system("pause") or input loop */ struct Node { BTreeNode header; char v; }; void printf_data(BTreeNode* node) { if( node != NULL ) { printf("%c", ((struct Node*)node)->v); } } int main(int argc, char *argv[]) { BTree* tree = BTree_Create(); struct Node n1 = {{NULL, NULL}, 'A'}; struct Node n2 = {{NULL, NULL}, 'B'}; struct Node n3 = {{NULL, NULL}, 'C'}; struct Node n4 = {{NULL, NULL}, 'D'}; struct Node n5 = {{NULL, NULL}, 'E'}; struct Node n6 = {{NULL, NULL}, 'F'}; BTree_Insert(tree, (BTreeNode*)&n1, 0, 0, 0); BTree_Insert(tree, (BTreeNode*)&n2, 0x00, 1, 0); BTree_Insert(tree, (BTreeNode*)&n3, 0x01, 1, 0); BTree_Insert(tree, (BTreeNode*)&n4, 0x00, 2, 0); BTree_Insert(tree, (BTreeNode*)&n5, 0x02, 2, 0); BTree_Insert(tree, (BTreeNode*)&n6, 0x02, 3, 0); printf("Height: %d\n", BTree_Height(tree)); printf("Degree: %d\n", BTree_Degree(tree)); printf("Count: %d\n", BTree_Count(tree)); printf("Position At (0x02, 2): %c\n", ((struct Node*)BTree_Get(tree, 0x02, 2))->v); printf("Full Tree: \n"); BTree_Display(tree, printf_data, 4, '-'); BTree_Delete(tree, 0x00, 1); printf("After Delete B: \n"); printf("Height: %d\n", BTree_Height(tree)); printf("Degree: %d\n", BTree_Degree(tree)); printf("Count: %d\n", BTree_Count(tree)); printf("Full Tree: \n"); BTree_Display(tree, printf_data, 4, '-'); BTree_Clear(tree); printf("After Clear: \n"); printf("Height: %d\n", BTree_Height(tree)); printf("Degree: %d\n", BTree_Degree(tree)); printf("Count: %d\n", BTree_Count(tree)); BTree_Display(tree, printf_data, 4, '-'); BTree_Destroy(tree); return 0; }</span></strong>
小结
遍历二叉树
前序遍历
中序遍历
后序遍历
层次遍历
代码
<strong><span style="font-size:18px;">void pre_order_traversal(BTreeNode* root) { if( root != NULL ) { printf("%c, ", ((struct Node*)root)->v); pre_order_traversal(root->left); pre_order_traversal(root->right); } } void middle_order_traversal(BTreeNode* root) { if( root != NULL ) { middle_order_traversal(root->left); printf("%c, ", ((struct Node*)root)->v); middle_order_traversal(root->right); } } void post_order_traversal(BTreeNode* root) { if( root != NULL ) { post_order_traversal(root->left); post_order_traversal(root->right); printf("%c, ", ((struct Node*)root)->v); } } void level_order_traversal(BTreeNode* root) { //利用队列完成层次 遍历 if( root != NULL ) { LinkQueue* queue = LinkQueue_Create(); if( queue != NULL ) { LinkQueue_Append(queue, root); while( LinkQueue_Length(queue) > 0 ) { struct Node* node = (struct Node*)LinkQueue_Retrieve(queue); printf("%c, ", node->v); LinkQueue_Append(queue, node->header.left); LinkQueue_Append(queue, node->header.right); } } LinkQueue_Destroy(queue); } } </span></strong>
小结
线索化二叉树
代码
<strong><span style="font-size:18px;">//方法 1 void thread_via_left(BTreeNode* root, BTreeNode** pp) { //参数传递,传递局部变量,用二级指针 if( (root != NULL) && (pp != NULL) ) { if( *pp != NULL ) { (*pp)->left = root; *pp = NULL; } if( root->left == NULL ) { *pp = root; } thread_via_left(root->left, pp); thread_via_left(root->right, pp); } } //方法 2 利用线性表 void thread_via_list(BTreeNode* root, SeqList* list) { if( (root != NULL) && (list != NULL) ) { SeqList_Insert(list, (SeqListNode*)root, SeqList_Length(list)); thread_via_list(root->left, list); thread_via_list(root->right, list); } }</span></strong>
霍夫曼树
最初的解决方案
存在的问题
另一种编码方式
精妙之处
怎么得到?
霍夫曼树
霍夫曼树的应用
小结
思考:
<strong><span style="font-size:18px;">1.二叉树定义 typedef struct BTreeNodeElement_t_ { void *data; } BTreeNodeElement_t; typedef struct BTreeNode_t_ { BTreeNodeElement_t *m_pElemt; struct BTreeNode_t_ *m_pLeft; struct BTreeNode_t_ *m_pRight; } BTreeNode_t;</span></strong>
<strong><span style="font-size:18px;">2.比较两个二叉树结构和数据是否同时相同,即两个一模一样的树 与上面的不同之处在于:在比较结构是否相同之后,需要比较当前节点的数据是否一致。 算法是一致的,只需要添加一行代码即可。 (1)递归方式: bool BTreeCompare( BTreeNode_t *pRoot1, BTreeNode_t *pRoot2) { //如果都为空树,则相同 if( pRoot1 == NULL && pRoot2 == NULL ) return true; //如果一个为空,一个不为空,则不相同 if( ( pRoot1 != NULL && pRoot2 == NULL ) || ( pRoot1 == NULL && pRoot2 != NULL ) ) return false; //比较当前节点中的数据 if( pRoot1->m_pElemt != pRoot2->m_pElemt) return false; //如果都不为空,则 需要比较左右子树后,再根据比较结果断定 bool leftCmp = BTreeCompare( pRoot1->m_pLeft, pRoot2->m_pLeft); bool rightCmp = BTreeCompare( pRoot1->m_pRight, pRoot2->m_pRight); return ( leftCmp && rightCmp ); } (2)非递归方式 bool BTreeCompare(BTreeNode_t *pRoot1, BTreeNode_t *pRoot2) { if( pRoot1 == NULL && pRoot2 == NULL ) return false; queue <BTreeNode_t *> que1; queue <BTreeNode_t *> que2; que1.push(pRoot1); que2.push(pRoot2); int curLevelNodeTotal1 = 0; int curLevelNodeTotal2 = 0; bool flag = true; //作为比较不一致时跳出标识 while( ( !que1.empty()) && ( !que2.empty())) //当两个队列均不为空时,才进行比较 { curLevelNodeTotal1 = que1.size(); //获取树1的当前层节点总数 curLevelNodeTotal2 = que2.size(); //获取树2的当前层节点总数 if( curLevelNodeTotal1 != curLevelNodeTotal2){ flag = false;//当前层节点总数都不一致,不需要比较了,直接跳出 break; } int cnt1 = 0;//遍历本层节点时的计数器 int cnt2 = 0; while( cnt1 < curLevelNodeTotal1 && cnt2 < curLevelNodeTotal2){ ++cnt1; ++cnt2; pRoot1 = que1.front(); que1.pop(); pRoot2 = que2.front(); que2.pop(); //比较当前节点中数据是否一致 if( pRoot1->m_pElemt != pRoot2->m_pElemt ){ flag = false; break; } //判断pRoot1和pRoot2左右节点结构是否相同 if( ( pRoot1->m_pLeft != NULL && pRoot2->m_pLeft == NULL ) || ( pRoot1->m_pLeft == NULL && pRoot2->m_pLeft != NULL ) || ( pRoot1->m_pRight != NULL && pRoot2->m_pRight == NULL ) || ( pRoot1->m_pRight == NULL && pRoot2->m_pRight != NULL ) ){ flag = false; break; } //将左右节点入队 if( pRoot1->m_pLeft != NULL ) que1.push( pRoot1->m_pLeft); if( pRoot1->m_pRight != NULL ) que1.push( pRoot1->m_pRight); if( pRoot2->m_pLeft != NULL ) que2.push( pRoot2->m_pLeft); if( pRoot2->m_pRight != NULL ) que2.push( pRoot2->m_pRight); } if( flag == false ) break; } //如果比较标志为false,则不相同 if( flag == false ){ while( !que1.empty() ) que1.pop(); while( !que2.empty()) que2.pop(); return false; } return true; }</span></strong>
树应用编译器的开发和数据库的开发