資料結構與演算法學習--二叉樹及二叉搜尋樹
阿新 • • 發佈:2018-12-02
可以看下以前對數的總結https://blog.csdn.net/sjin_1314/article/details/8507490
下面是二叉樹的遍歷,建立及銷燬的函式實現,層次遍歷依賴佇列;佇列實現可以去github上檢視https://github.com/jin13417/algo/tree/master/c-cpp/23_binarytree/tree
/************************************************************************* > File Name: binarytree.c > Author: jinshaohui > Mail:
[email protected] > Time: 18-11-12 > Desc: ************************************************************************/ #include<assert.h> #include<string.h> #include<stdlib.h> #include<stdio.h> #include"list_queue.h" typedef struct _treenode { int data; struct _treenode *lchild; struct _treenode *rchild; }Tnode,Tree; void binarytree_create(Tree **Root) { int a = 0; printf("\r\n輸入節點數值((當輸入為100時,當前節點建立完成))):"); scanf("%d",&a); if (a == 100) { *Root = NULL; } else { *Root = (Tnode *)malloc(sizeof(Tnode)); if (*Root == NULL) { return; } (*Root)->data = a; printf("\r\n create %d 的左孩子:",a); binarytree_create(&((*Root)->lchild)); printf("\r\n create %d 的右孩子:",a); binarytree_create(&((*Root)->rchild)); } return ; } void binarytree_destory(Tree *root) { if (root == NULL) { return; } binarytree_destory(root->lchild); binarytree_destory(root->rchild); free(root); } /*先序遍歷:根結點--》左子樹---》右子樹*/ void binarytree_preorder(Tree *root) { if (root == NULL) { return; } printf(" %d ",root->data); binarytree_preorder(root->lchild); binarytree_preorder(root->rchild); return; } /*中序遍歷:左子樹--》跟節點---》右子樹*/ void binarytree_inorder(Tree *root) { if (root == NULL) { return; } binarytree_inorder(root->lchild); printf(" %d ",root->data); binarytree_inorder(root->rchild); return; } /*後序遍歷:左子樹---》右子樹-》根節點*/ void binarytree_postorder(Tree *root) { if (root == NULL) { return; } binarytree_postorder(root->lchild); binarytree_postorder(root->rchild); printf(" %d ",root->data); return; } void binarytree_levelorder(Tree * root) { list_queue *queue = NULL; Tnode * node = NULL; if(root == NULL) { return; } queue = list_queue_create(); /*根節點先入隊*/ list_queue_enqueue(queue,(void *)root); while(!list_queue_is_empty(queue)) { list_queue_dequeue(queue,(void *)&node); printf(" %d ",node->data); if(node->lchild != NULL) { list_queue_enqueue(queue,(void *)node->lchild); } if(node->rchild != NULL) { list_queue_enqueue(queue,(void *)node->rchild); } } free(queue); } /*列印葉子節點*/ void binarytree_printfleaf(Tree *root) { if (root == NULL) { return; } if ((root->lchild == NULL) && (root->rchild == NULL)) { printf(" %d ",root->data); } else { binarytree_printfleaf(root->lchild); binarytree_printfleaf(root->rchild); } } /*列印葉子的個數*/ int binarytree_getleafnum(Tree*root) { if (root == NULL) { return 0; } if ((root->lchild == NULL) && (root->rchild == NULL)) { return 1; } return binarytree_getleafnum(root->lchild) + binarytree_getleafnum(root->rchild); } /*列印數的高度*/ int binarytree_gethigh(Tree *root) { int lhigh = 0; int rhigh = 0; if (root == NULL) { return 0; } lhigh = binarytree_gethigh(root->lchild); rhigh = binarytree_gethigh(root->rchild); return ((lhigh > rhigh)?(lhigh + 1):(rhigh + 1)); } int main() { Tree *root = NULL; setenv("MALLOC_TRACE","1.txt",1); mtrace(); printf("\r\n建立二叉樹:"); binarytree_create(&root); printf("\r\n先序遍歷二叉樹:"); binarytree_preorder(root); printf("\r\n中序遍歷二叉樹:"); binarytree_inorder(root); printf("\r\n後序遍歷二叉樹:"); binarytree_postorder(root); printf("\r\n層次遍歷二叉樹:"); binarytree_levelorder(root); printf("\r\n列印二叉樹葉子節點:"); binarytree_printfleaf(root); printf("\r\n列印二叉樹葉子節點個數:%d",binarytree_getleafnum(root)); printf("\r\n列印二叉樹高度:%d",binarytree_gethigh(root)); binarytree_destory(root); muntrace(); return 0; }
二叉搜尋樹
定義:二叉查詢樹(Binary Search Tree),又被稱為二叉搜尋樹。設x為二叉查詢樹中的一個結點,x節點包含關鍵字key,節點x的key值記為key[x]。如果y是x的左子樹中的一個結點,則key[y] <= key[x];如果y是x的右子樹的一個結點,則key[y] >= key[x]。
在二叉查詢樹中:
(01) 若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
(02) 任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
(03) 任意節點的左、右子樹也分別為二叉查詢樹。
(04) 沒有鍵值相等的節點(no duplicate nodes)。
在實際應用中,二叉查詢樹的使用比較多。下面,用C語言實現二叉查詢樹。
/*************************************************************************
> File Name: binarysearchtree.h
> Author: jinshaohui
> Mail: [email protected]
> Time: 18-11-12
> Desc:
************************************************************************/
#ifndef __BINARY_SEARCH_TREE__
#define __BINARY_SEARCH_TREE__
typedef int mytype;
typedef struct _bstree_node
{
mytype data;
struct _bstree_node *lchild;
struct _bstree_node *rchild;
}bstree_node;
typedef struct _bstree
{
int size;
int (*compare)(mytype key1,mytype key2);
int (*destory)(mytype data);
bstree_node *root;
}bstree;
typedef int (*compare_fuc)(mytype key1,mytype key2);
typedef int (*destory_fuc)(mytype data);
#define bstree_is_empty(tree) (tree->size == 0)
bstree *bstree_create(compare_fuc compare,destory_fuc destory);
#endif
/*************************************************************************
> File Name: binarysearchtree.c
> Author: jinshaohui
> Mail: [email protected]
> Time: 18-11-12
> Desc:
************************************************************************/
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include"binarysearchtree.h"
bstree *bstree_create(compare_fuc compare,destory_fuc destory)
{
bstree *tree = NULL;
tree = (bstree*)malloc(sizeof(bstree));
if (tree == NULL)
{
return NULL;
}
tree->size = 0;
tree->compare = compare;
tree->destory = destory;
tree->root = NULL;
return tree;
}
bstree_node *bstree_search(bstree *tree,mytype data)
{
bstree_node *node = NULL;
int res = 0;
if ((tree == NULL) || (bstree_is_empty(tree)))
{
return NULL;
}
node = tree->root;
while(node != NULL)
{
res = tree->compare(data,node->data);
if(res == 0)
{
return node;
}
else if (res > 0)
{
node = node->rchild;
}
else
{
node = node->lchild;
}
}
return NULL;
}
int bstree_insert(bstree * tree, mytype data)
{
bstree_node *node = NULL;
bstree_node *tmp = NULL;
int res = 0;
if (tree == NULL)
{
return -1;
}
node = (bstree_node *)malloc(sizeof(bstree_node));
if (node == NULL)
{
return -2;
}
node->data = data;
node->lchild = NULL;
node->rchild = NULL;
/*如果二叉樹為空,直接掛到根節點*/
if (bstree_is_empty(tree))
{
tree->root = node;
tree->size++;
return 0;
}
tmp = tree->root;
while(tmp != NULL)
{
res = tree->compare(data,tmp->data);
if (res > 0) /*去右孩子查詢*/
{
if (tmp->rchild == NULL)
{
tmp->rchild = node;
tree->size++;
return 0;
}
tmp = tmp->rchild;
}
else /*去左孩子查詢*/
{
if(tmp->lchild == NULL)
{
tmp->lchild = node;
tree->size++;
return 0;
}
tmp = tmp->lchild;
}
}
return -3;
}
int bstree_delete(bstree *tree,mytype data)
{
bstree_node *node = NULL;/*要刪除的節點*/
bstree_node *pnode = NULL;/*要刪除節點的父節點*/
bstree_node *minnode = NULL;/*要刪除節點的父節點*/
bstree_node *pminnode = NULL;/*要刪除節點的父節點*/
mytype tmp = 0;
int res = 0;
if ((tree == NULL) || (bstree_is_empty(tree)))
{
return -1;
}
node = tree->root;
while ((node != NULL) && ((res = tree->compare(data,node->data)) != 0))
{
pnode = node;
if(res > 0)
{
node = node->rchild;
}
else
{
node = node->lchild;
}
}
/*說明要刪除的節點不存在*/
if (node == NULL)
{
return -2;
}
/*1、如果要刪除node有2個子節點,需要找到右子樹的最小節點minnode,
* 更新minnode和node節點資料,這樣minnode節點就是要刪除的節點
* 再更新node和pnode節點指向要刪除的節點*/
if ((node->lchild != NULL) && (node->rchild != NULL))
{
minnode = node->rchild;
pminnode = node;
while(minnode->lchild != NULL)
{
pminnode = minnode;
minnode = minnode->lchild;
}
/*node 節點和minnode節點資料互換*/
tmp = node->data;
node->data = minnode->data;
minnode->data = tmp;
/*更新要刪除的節點和其父節點*/
node = minnode;
pnode = pminnode;
}
/*2、當前要刪除的節點只有左孩子或者右孩子時,直接父節點的直向刪除的節點*/
if (node->lchild != NULL)
{
minnode = node->lchild;
}
else if (node->rchild != NULL)
{
minnode = node->rchild;
}
else
{
minnode = NULL;
}
if (pnode == NULL)/*當要刪除的時根節點時,*/
{
tree->root = minnode;
}
else if (pnode->lchild == node)
{
pnode->lchild = minnode;
}
else
{
pnode->rchild = minnode;
}
tree->size--;
free (node);
return 0;
}
/*採用遞迴方式刪除節點*/
void bstree_destory_node(bstree *tree,bstree_node *root)
{
if (root == NULL)
{
return;
}
bstree_destory_node(tree,root->lchild);
bstree_destory_node(tree,root->rchild);
free(root);
}
/*二叉搜尋樹銷燬*/
void bstree_destory(bstree *tree)
{
bstree_destory_node(tree,tree->root);
free(tree);
return;
}
/*中序遍歷列印樹節點*/
void bstree_inorder_node(bstree_node *root)
{
bstree_node *node = NULL;
if (root == NULL)
{
return;
}
bstree_inorder_node(root->lchild);
printf(" %d ",root->data);
bstree_inorder_node(root->rchild);
return;
}
void bstree_dump(bstree *tree)
{
bstree_node *node = NULL;
if ((tree == NULL) || (bstree_is_empty(tree)))
{
printf("\r\n 當前樹是空樹");
}
printf("\r\nSTART-----------------%d------------\r\n",tree->size);
bstree_inorder_node(tree->root);
printf("\r\nEND---------------------------------",tree->size);
}
int bstree_compare(mytype key1,mytype key2)
{
if (key1 == key2)
{
return 0;
}
else if (key1 > key2)
{
return 1;
}
else
{
return -1;
}
}
int main()
{
bstree *tree = NULL;
bstree_node *node = NULL;
mytype data = 0;
int res = 0;
setenv("MALLOC_TRACE","1.txt",1);
mtrace();
tree = bstree_create(bstree_compare,NULL);
assert(tree != NULL);
while(1)
{
printf("\r\n插入一個數字,輸入100時退出:");
scanf("%d",&data);
if(data == 100)break;
res = bstree_insert(tree,data);
printf("\r\n %d 插入%s成功",data,(res != 0)?("不"):(" "));
}
bstree_dump(tree);
while(1)
{
printf("\r\n查詢一個數字,輸入100時退出:");
scanf("%d",&data);
if(data == 100)break;
node = bstree_search(tree,data);
printf("\r\n %d %s存在樹中",data,(node == NULL)?("不"):(" "));
}
bstree_dump(tree);
while(1)
{
printf("\r\n刪除一個數字,輸入100時退出:");
scanf("%d",&data);
if(data == 100)break;
res = bstree_delete(tree,data);
printf("\r\n %d 刪除%s成功",data,(res != 0)?("不"):(" "));
bstree_dump(tree);
}
bstree_destory(tree);
muntrace();
return 0;
}
思考:1、什麼樣的二叉樹適合使用陣列來儲存
完全二叉樹,堆排序就是一種完全二叉樹使用陣列來處理的。
2、散列表和二叉搜尋樹對比