二叉樹的實現與操作(C語言實現)
二叉樹的定義:
上一篇的樹的通用表示法太過於複雜,由此這裡採用了孩子兄弟表示法來構建二叉樹。
孩子兄弟表示法:
每個結點包含一個數據指標和兩個結點指標
--->資料指標:指向保存於樹中的資料
--->孩子結點指標:指向第一個孩子
--->兄弟結點指標:指向第一個右兄弟
二叉樹是由 n( n>=0 ) 個結點組成的有限集合,該集合或者為空,或者是由一個根結點加上兩棵分別稱為左子樹和右子樹的、互不相交的二叉樹組成。
特殊的二叉樹:
定義1:滿二叉樹(Full Binary Tree)
如果二叉樹中所有分支結點的度數都為2,且葉子結點都在同一層次上,則稱做這類二叉樹為滿二叉樹
定義2:完全二叉樹
如果一顆具有N個結點的高度為K的二叉樹,它的每一個結點都與高度為K的滿二叉樹中的編號為1---N的結點一一對應,則稱這課二叉樹為完全二叉樹(從上到下從左到右編號)。
注:完全二叉樹的葉結點僅僅出現在最下面二層,
最下面的葉結點一定出現在左邊;
倒數第二層的葉結點一定出現在右邊
完全二叉樹中度為1的結點只有左孩子
同樣結點數的二叉樹,完全二叉樹的高度最小
二叉樹的深層性質
性質1:
在二叉樹的第i層最多有2i-1個結點。(i>=1)
性質2:
深度為K的二叉樹最多有2k-1個結點(k>=0)
性質3:
對任何一顆二叉樹,如果其葉結點有n0個,度為2的結點的非葉結點有
性質4:
具有n個結點的完全二叉樹的高度為[log2n]+1
性質5:
一顆有n個結點的二叉樹(高度為[log2n]+1),按層次對結點進行編號(從上到下,從左到右),對任意結點i有:
如果i=1,則結點i是二叉樹的根,
如果i>1,則其雙親結點為[i/2]
如果2i<=n,則結點i的左孩子為2i
如果2i>n,則結點i無左孩子,
如果2i+1<=n,則結點i的右孩子為2i+1,
如果2i+1>n,則結點i無右孩子
以下是程式碼:
標頭檔案:
#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
原始檔:
#include "stdafx.h"
#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)
{
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)
{
int ret = 0;
if( root != NULL )
{
ret = recursive_count(root->left) + 1 + recursive_count(root->right);
}
return ret;
}
//計算樹的高度
static int recursive_height(BTreeNode* root)
{
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)
{
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()
{
TBTree* ret = (TBTree*)malloc(sizeof(TBTree));
if( ret != NULL )
{
ret->count = 0;
ret->root = NULL;
}
return ret;
}
void BTree_Destroy(BTree* tree)
{
free(tree);
}
void BTree_Clear(BTree* tree)
{
TBTree* btree = (TBTree*)tree;
if( btree != NULL )
{
btree->count = 0;
btree->root = NULL;
}
}
//tree 目標樹 node 要插入結點 pos 要插入位置 count 移動步數 flag 插入位置是左還是右
int BTree_Insert(BTree* tree, BTreeNode* node, BTPos pos, int count, int flag)
{
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) )
{
//位置最低位與1進行按位與運算,得知是往左走還是往右走
bit = pos & 1;
//表示位置的十六進位制向右移動一位
pos = pos >> 1;
//parent用來掛要插入的結點
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;
}
//刪除與插入基本類似,只不過將要刪除的結點的父結點的left或者right指標以及所有的子節點置為NULL而已
BTreeNode* BTree_Delete(BTree* tree, BTPos pos, int count)
{
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)
{
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)
{
TBTree* btree = (TBTree*)tree;
BTreeNode* ret = NULL;
if( btree != NULL )
{
ret = btree->root;
}
return ret;
}
int BTree_Height(BTree* tree)
{
TBTree* btree = (TBTree*)tree;
int ret = 0;
if( btree != NULL )
{
ret = recursive_height(btree->root);
}
return ret;
}
int BTree_Count(BTree* tree)
{
TBTree* btree = (TBTree*)tree;
int ret = 0;
if( btree != NULL )
{
ret = btree->count;
}
return ret;
}
int BTree_Degree(BTree* tree)
{
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)
{
TBTree* btree = (TBTree*)tree;
if( btree != NULL )
{
recursive_display(btree->root, pFunc, 0, gap, div);
}
}
主函式:
// 二叉樹.cpp : 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include "BTree.h"
#include <iostream>
struct Node //資料結點
{
BTreeNode header;
char v;
};
void printf_data(BTreeNode* node) //列印樹
{
if( node != NULL )
{
printf("%c", ((struct Node*)node)->v);
}
}
int _tmain(int argc, _TCHAR* 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, '-');
//以下是刪除結點位置在0x00的結點後,樹的整體狀態
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);
system("pause");
return 0;
}
執行結構:
Height: 4
Degree: 2
Count: 6
Position At (0x02, 2): E
Full Tree:
A
----B
--------D
--------E
------------F
------------
----C
After Delete B:
Height: 2
Degree: 1
Count: 2
Full Tree:
A
----
----C
After Clear:
Height: 0
Degree: 0
Count: 0
請按任意鍵繼續. . .
如有錯誤,望不吝指出呀。