树的类型有很多,这里我们只讲二叉树。
一、二叉树的基本概念
1、什么是二叉树
在计算机科中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”和“右子树”,左子树和右子树同时也是二叉树。二叉树的子树有左右之分,并且次序不能任意颠倒。其中,起始的节点叫做根节点,整棵树只有一个根节点,除了根节点之外的每个节点有且仅有一个父节点;
其中没有任何子节点的节点叫做叶子节点,叶子节点有父节点但是没有子节点;
除了根节点和叶子节点之外,剩下的节点叫做枝节点,枝节点有父节点也有子节点。
如果该二叉树中每层节点数均达到最大值,且所有的枝节点都有两个子节点,那么该二叉树就叫做满二叉树。
如果除了最后一层之外,各层节点数均达到最大值,并且最后一层的节点都连续集中在左边,则叫做完全二叉树。
如果除了最后一层之外,各层节点数均达到最大值,并且最后一层的节点都连续集中在左边,则叫做完全二叉树。
下面使用 ProcessOn 画的图形
(1)二叉树的一般形式:
根节点、枝节点和叶节点
父节点和子节点
左子节点和右子节点
左子树和右子树
大小和高度(深度)
(2)满二叉树
每层节点数均达到最大值,
所有枝节点均有左右子树
(3)完全二叉树
除最下层外,各层节点数均达到最大值,
最下层的节点都连续集中在左边。
二、基本特征
二叉树具有递归嵌套式的空间结构特征,因此采用递归的方法处理二叉树问题,可以使得算法变得更加简洁。
递归我们之前有总结过的,参看:数据结构与算法 -- 再论递归
处理的一般形式:
处理(二叉树)
{
if(二叉树是否为空,如果为空) { 直接处理;}
else
{
处理根节点;
处理左子树; => 使用递归的方法处理 小二叉树
处理右子树; => 使用递归的方法处理 小二叉树
}
}
三、二叉树的存储结构
(1)采用顺序结构进行存储
一般情况下,从上到下、从左到右,依次存放所有的节点,对于非完全二叉树来说,需要采用虚节点补成完全二叉树。
一般情况下,从上到下、从左到右,依次存放所有的节点,对于非完全二叉树来说,需要采用虚节点补成完全二叉树。
代码实现说明:
创建二叉树,将字符放到数组下标,首元素存储字符个数。左子树插入根节点下标的2n,右子树插入根节点下标的2n+1,然后使用递归。前/中/后遍历,对应的DLR/LDR/LRD。
示例一:
参看:
顺序存储二叉树
#include <stdio.h>
#define MAX_NODE_SIZE 100 //二叉树的最大节点数
#define SqBiTree_TYPE char
SqBiTree_TYPE t [MAX_NODE_SIZE+1]; //0号单元节点个数
//创建二叉树
void creat_tree(void)
{
int i=0;
char ch;
while((ch=getchar())!='#')
{
i++;
// printf ("i = %d\n", i);
t[i]=ch;
}
t[0]=i;
}
//获取给定结点(位置)的左孩子的结点位置
int LeftChild_locate(int node)
{
if ((2 * node) > t[0])
return -1;
else
return 2 * node;
}
//获取给定结点(位置)的右孩子的结点位置
int RightChild_locate(int node)
{
if ((2 * node+1) > t[0])
return -1;
else
return 2 * node+1;
}
//层序遍历
void level_order(void)
{
int i = 0;
for(i=1;i<=t[0];i++)
if(t[i]!='#')
printf ("%c ", t[i]);
}
//前序遍历
void pre_order(int i)
{
if(t[0]<=0)
printf ("空树!\n");
else
{
if(t[i]!='#')
printf ("%c ", t[i]);
if(LeftChild_locate(i)!=-1) //如果左子结点存在,递归
pre_order(LeftChild_locate(i));
if(RightChild_locate(i)!=-1) //如果右子结点存在,递归
pre_order(RightChild_locate(i));
}
}
//中序遍历
void mid_order(int i)
{
if(t[0]<=0)
printf ("空树!\n");
else
{
if(LeftChild_locate(i)!=-1) //如果左子结点存在,递归
mid_order(LeftChild_locate(i));
if(t[i]!='#')
printf ("%c ", t[i]);
if(RightChild_locate(i)!=-1) //如果右子结点存在,递归
mid_order(RightChild_locate(i));
}
}//后序遍历
void back_order(int i)
{
if(t[0]<=0)
printf ("空树!\n");
else
{
if(LeftChild_locate(i)!=-1) //如果左子结点存在,递归
back_order(LeftChild_locate(i));
if(RightChild_locate(i)!=-1) //如果右子结点存在,递归
back_order(RightChild_locate(i));
if(t[i]!='#')
printf ("%c ", t[i]);
}
}
int main (void)
{
printf ("创建二叉树\n");
//创建顺序二叉树
creat_tree();
//层序遍历
printf ("层序遍历\n");
level_order();
printf ("\n");
//前序遍历
printf ("前序遍历\n");
pre_order(1);
printf ("\n");
//中序遍历
printf ("中序遍历\n");
mid_order(1);
printf ("\n");
//后续遍历
printf ("后序遍历\n");
back_order(1);
printf ("\n");
return 0;
}
输出结果:
创建二叉树
12345#
层序遍历
1 2 3 4 5
前序遍历
1 2 4 5 3
中序遍历
4 2 5 1 3
后序遍历
4 5 2 3 1
参看:二叉树顺序存储的实现
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100/*存储空间初始分配量*/
#define MAX_TREE_SIZE 100/*定义树的最大节点数*/
typedef int status;
typedef int elemtype;
typedef struct position {
int level;
int order;
} position;
typedef elemtype sqbitree[MAXSIZE];
elemtype null=0;/*设0表示空*/
status visit(elemtype c) {
printf("%d ",c);
return OK;
}
status initbitree(sqbitree T) {
int i=0;
for(i=0; i<MAX_TREE_SIZE; i++)
T[i]=null;/*初始化时将所有节点置为空*/
return OK;
}
/*创建二叉树*/
status createbitree(sqbitree T) {
int i=0;
printf("请按层序输入结点的值(整型),0表示空结点,输999结束。结点数≤%d:\n",MAX_TREE_SIZE);
while(i<10) {
T[i]=i+1;
/*T[(i+1)/2-1]是T[i]的双亲节点*/
if(i&&!T[(i+1)/2-1]&&T[i]) {
printf("产生了没有双亲节点的新节点\n");
return ERROR;
}
i++;
}
/*其余节点置空*/
while(i<MAX_TREE_SIZE) {
T[i]=null;
i++;
}
return OK;
}
/*判断二叉树为空*/
status emptybitree(sqbitree T) {
if(!T[0])
return TRUE;
else
return FALSE;
}
/*求二叉树深度*/
status depthbitree(sqbitree T) {
int i,j=-1;
/*从最后一个节点开始,找到第一个不为空的节点*/
for(i=MAX_TREE_SIZE-1; i>=0; i--)
if(T[i])
break;
i++;
do {
j++;
} while(i>=pow(2,j));
return j;
}
/*返回二叉树的根节点*/
status root(sqbitree T,elemtype *e) {
if(emptybitree(T)) {
printf("二叉树为空\n");
return ERROR;
} else {
*e=T[0];
return OK;
}
}
/*给二叉树中第e层序对节点赋新值value*/
status refresh(sqbitree T,position e,elemtype value) {
/*将e转换成数组下标,这个公式画出示意图很容易就能理解*/
int i=(int)(pow(2,e.level-1)+e.order-2);
/*情况一:给叶子赋空但双亲为空,返回ERROR*/
if(!value&&!T[(i+1)/2-1])
return ERROR;
/*情况二:给双亲赋空但叶子不为空,返回ERROR*/
if(!value&&T[i*2+1]||T[i*2+2])
return ERROR;
T[i]=value;
return OK;
}
/*返回一个节点的左孩子*/
elemtype leftchild(sqbitree T,elemtype e){
int i=0;
if(!T[0])
return ERROR;
for(i=0;i<MAX_TREE_SIZE;i++){
if(T[i]==e)
return T[i*2+1];
}
return ERROR;
}
/*返回一个节点的右孩子*/
elemtype rightchild(sqbitree T,elemtype e) {
int i=0;
if(!T[0]) {
printf("空树\n");
return null;
}
for(i=0; i<MAX_TREE_SIZE; i++) {
if(T[i]==e)
return T[i*2+2];
}
return ERROR;/*没找到*/
}
/*返回一个节点的左兄弟,若e是T的左孩子或无左兄弟,则返回"空"*/
elemtype leftslibing(sqbitree T,elemtype e) {
int i=0;
if(!T[0]) {
printf("空树\n");
return null;
}
for(i=0; i<MAX_TREE_SIZE; i++)
if(T[i]==e&&i%2==0)/*i为偶数,*则为右子孙,减一即可得到左兄弟*//*此外,这个地方写i%2==0h和!i%2的结果不一样,正在思考原因*/
return T[i-1];
return null;
}
/*回一个节点的右兄弟,若e是T的左孩子或无左兄弟,则返回"空"*/
elemtype rightslibing(sqbitree T,elemtype e) {
int i=0;
if(!T[0]) {
printf("空树\n");
return null;
}
for(i=0; i<MAX_TREE_SIZE; i++) {
if(T[i]==e&&i%2)/*i为奇数,*则为左子孙,减一即可得到右兄弟*/
return T[i+1];
}
return null;
}
/*返回双亲*/
elemtype parent(sqbitree T,elemtype e){
int i=0;
for(i=0;i<MAX_TREE_SIZE;i++){
if(T[i]==e)
return T[(i+1)/2-1];
}
}
/*遍历二叉树*/
/*前序遍历*/
status preorder(sqbitree T,int i){
visit(T[i]);/*先访问根节点,再递归访问左子树和右子树*/
if(T[2*i+1])
preorder(T,2*i+1);
if(T[2*i+2])
preorder(T,2*i+2);
}
status pretraverse(sqbitree T){
if(emptybitree(T))
return ERROR;
else{
preorder(T,0);/*从0开始递归*/
printf("\n");
}
return OK;
}
/*中序遍历二叉树*/
void InTraverse(sqbitree T,int e)
{
if(T[2*e+1]!=null) /* 左子树不空 */
InTraverse(T,2*e+1);
visit(T[e]);
if(T[2*e+2]!=null) /* 右子树不空 */
InTraverse(T,2*e+2);
}
status InOrderTraverse(sqbitree T)
{
if(!emptybitree(T)) /* 树不空 */
InTraverse(T,0);
printf("\n");
return OK;
}
/*后序遍历二叉树*/
status lastorder(sqbitree T,int i){
if(T[2*i+1])
lastorder(T,2*i+1);
if(T[2*i+2])
lastorder(T,2*i+2);
visit(T[i]);
}
status lasttraverse(sqbitree T){
if(emptybitree(T))
return ERROR;
else{
lastorder(T,0);
}
printf("\n");
}
int main(void) {
status i;
position p;
elemtype e;
sqbitree T;
initbitree(T);
createbitree(T);
printf("建立二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",emptybitree(T),depthbitree(T));
printf("对二叉树做前序遍历:");
pretraverse(T);
printf("对二叉树做中序遍历:");
InOrderTraverse(T);
printf("对二叉树做后序遍历:");
lasttraverse(T);
e=50;
printf("修改层序为3,本层序号为2的节点的值,输入新值为%d\n",e);
p.level=3;
p.order=2;
refresh(T,p,50);
printf("对二叉树做前序遍历:");
pretraverse(T);
printf("节点50的双亲为%d,左右孩子分别为%d %d,左右兄弟为%d %d\n",parent(T,e),leftchild(T,e),rightchild(T,e),leftslibing(T,e),rightslibing(T,e));
initbitree(T);
printf("清空二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",emptybitree(T),depthbitree(T));
root(T,&e);
}
编译:gcc test.c -lm
输出结果:
请按层序输入结点的值(整型),0表示空结点,输999结束。结点数≤100:
建立二叉树后,树空否?0(1:是 0:否) 树的深度=4
对二叉树做前序遍历:1 2 4 8 9 5 10 3 6 7
对二叉树做中序遍历:8 4 9 2 10 5 1 6 3 7
对二叉树做后序遍历:8 9 4 10 5 2 6 7 3 1
修改层序为3,本层序号为2的节点的值,输入新值为50
对二叉树做前序遍历:1 2 4 8 9 50 10 3 6 7
节点50的双亲为2,左右孩子分别为10 0,左右兄弟为4 0
清空二叉树后,树空否?1(1:是 0:否) 树的深度=0
二叉树为空
(2)采用链式结构进行存储
一般情况下,每个节点包括三个部分,其中一个是存储数据的内存空间,另外两个则用于存储左右子节点的地址。
一般情况下,每个节点包括三个部分,其中一个是存储数据的内存空间,另外两个则用于存储左右子节点的地址。
二、遍历方式
(1)前序遍历(DLR - Data Left Right)
对于从根开始的每一棵子树,先处理根节点中的数据,再处理它的左子树,最后处理它的右子树,又叫做先根遍历
对于从根开始的每一棵子树,先处理根节点中的数据,再处理它的左子树,最后处理它的右子树,又叫做先根遍历
(2)中序遍历(LDR - Left Data Right)=> 重点掌握
对于从根开始的每一棵子树,先处理它的左子树,再处理它的根节点中数据,最后处理它的右子树,又叫做中根遍历
(3)后序遍历(LRD - Left Right Data)
对于从根开始的每一棵子树,先处理它的左子树,再处理它的右子树,最后处理它的根节点数据,又叫做后根遍历
对于从根开始的每一棵子树,先处理它的左子树,再处理它的根节点中数据,最后处理它的右子树,又叫做中根遍历
(3)后序遍历(LRD - Left Right Data)
对于从根开始的每一棵子树,先处理它的左子树,再处理它的右子树,最后处理它的根节点数据,又叫做后根遍历
三、有序二叉树
1、有序二叉树介绍
BST 是 Binary Search Tree 的缩写,翻译为二叉搜索树,或有序二叉树,是二叉树的一种,它的定义如下:
(1)或者是一颗空树
(2)或者是具有下列性质的二叉树:
若左子树非空,则左子树上所有节点的值均小于它的根节点的值
若右子树非空,则右子树上所有节点的值均大于它的根节点的值
左右子树也分别为有序二叉树
基于有序二叉树的排序和查找,可获得O(logN)级的平均时间复杂度。
BST 在查找一个节点或者插入一个节点时,具有极大的优势,速度非常快,是一种基础性数据结构,广泛应用于更加抽象的集合,关联数组等数据结构。
2、有序二叉树用途
(1)排序
无论以何种顺序构建有序二叉树,其中序遍历的结果一定是一个有序序列。
(2)搜索
若搜索目标与根节点的值相等,则搜索成功,否则用搜索目标和根节点的值比较大小。
若搜索目标小于根节点的值,则在根节点的左子树中继续搜索,否则在根节点的右子树中继续搜索。
以递归的方式重复以上过程,直到搜索成功,或因子树不存在而宣告失败。
基于有序二叉树的搜索,可达到对数级的平均时间复杂度。
3、链式有序二叉树实现
代码实现说明:
插入节点时,判断二叉树是否为空,如果为空就直接插入即可,如果二叉树不为空,则使用根节点与新节点比较大小,如果新节点小于根节点,则插入到左子树中,如果新节点大于根节点,则插入到右子树中。插入节点的函数为递归函数。如下图所示:
删除节点时,先将左子树合并到右子树中,将要删除的节点地址单独保存,将连接目标节点的指针指向合并出来的右子树,删除目标节点。
中序遍历,先遍历左子树、遍历根节点,遍历右子树
(1)链式有序二叉树(示例一)
//编程实现有序二叉数的基本操作
#include <stdio.h>
#include <stdlib.h>
//定义节点的数据类型
typedef struct Node
{
int data;//存储的具体内容
struct Node* left;//左子树的地址
struct Node* right;//右子树的地址
}Node;
//定义二叉数的数据类型
typedef struct
{
int cnt;//记录节点的个数
Node* root;//指向跟节点的指针
}Tree;
//插入新节点后,组成有序二叉数
void insertData(Tree* pt,int data);
//创建新节点
Node* create_node(int data);//指针
//插入节点的递归函数
void insert(Node** pRoot,Node* pn);
//采用中序方法遍历二叉数
void travelData(Tree* pt);
//递归遍历函数
void travel(Node* pn);
//清空二叉数中所有的节点
void clearData(Tree* pt);
//清空的递归函数
void clear(Node** pRoot);
//查找指定的元素所在的地址
Node** findData(Tree* pt,int data);
//查找的递归函数
Node** find(Node** pRoot,int data);
//删除指定的元素
void delData(Tree* pt,int data);
//修改二叉数指定元素的值
void modifyData(Tree* pt,int data,int newData);
//判断二叉数是否为空
int empty(Tree* pt);
//判断二叉数是否为满
int full(Tree* pt);
//计算节点的个数
int size(Tree* pt);
//获取根节点元素值
int get_root(Tree* pt);
int main()
{
//创建二叉数,并且初始化
Tree tree;
tree.root=NULL;
tree.cnt=0;
insertData(&tree,50);//50
travelData(&tree);
insertData(&tree,10);//10 50
travelData(&tree);
insertData(&tree,30);//10 30 50
travelData(&tree);
insertData(&tree,40);//10 30 40 50
travelData(&tree);
insertData(&tree,20);//10 20 30 40 50
travelData(&tree);
insertData(&tree,70);//10 20 30 40 50 70
travelData(&tree);
insertData(&tree,60);//10 20 30 40 50 60 70
travelData(&tree);
printf("----------------------\n");
delData(&tree,30);//10 20 40 50 60 70
travelData(&tree);
delData(&tree,50);//10 20 40 60 70
travelData(&tree);
delData(&tree,80);//10 20 40 60 70
travelData(&tree);
printf("-----------------------\n");
modifyData(&tree,20,80);
travelData(&tree);
printf("二叉数中根节点元素是:%d\n",get_root(&tree));
printf("二叉数中节点个数是:%d\n",size(&tree));
printf("%s\n",empty(&tree)?"二叉树为空":"二叉树未空");
printf("%s\n",full(&tree)?"二叉树为满":"二叉树未满");
printf("--------------------------------\n");
printf("二叉数已清空\n");
clearData(&tree);
travelData(&tree);
return 0;
}
//修改二叉数指定元素的值
void modifyData(Tree* pt,int data,int newData)
{
//1.删除指定元素的节点
delData(pt,data);
//插入新元素值
insertData(pt,newData);
}
//判断二叉数是否为空
int empty(Tree* pt)
{
return NULL==pt->root;
}
//判断二叉数是否为满
int full(Tree* pt)
{
return 0;
}
//计算节点的个数
int size(Tree* pt)
{
return pt->cnt;
}
//获取根节点元素值
int get_root(Tree* pt)
{
return empty(pt)?-1:pt->root->data;
}
//清空二叉数中所有的节点
void clearData(Tree* pt)
{
//调用递归函数进行清空 址传递
clear(&pt->root);
pt->cnt=0;
}
//清空的递归函数
void clear(Node** pRoot)
{
if(*pRoot!=NULL)
{
//1.清空左子树
clear(&(*pRoot)->left);
//2.清空右子树
clear(&(*pRoot)->right);
//3.清空根节点
free(*pRoot);
*pRoot=NULL;
}
}
//查找指定的元素所在的地址
Node** findData(Tree* pt,int data)
{
//调用递归函数实现查找
return find(&pt->root,data);
}
//查找的递归函数
Node** find(Node** pRoot,int data)
{
//1.判断二叉数是否为空
if(NULL==*pRoot)
{
return pRoot;//查找失败
}
//2.判断根节点是否和目标元素相等
else if(data==(*pRoot)->data)
{
return pRoot;//查找成功
}
//3.如果目标元素小于根节点,则去左子树中进行查找
else if(data < (*pRoot)->data)
{
return find(&(*pRoot)->left,data);
}
//4.如果目标元素大于根节点,则去右子数中进行查找
else
{
return find(&(*pRoot)->right,data);
}
}
//删除指定的元素
void delData(Tree* pt,int data)
{
//1.查找目标元素所在的地址
Node** p=findData(pt,data);
//2.根据返回值进行判断,如果查找失败,则删除失败,函数结束
if(NULL==*p)
{
printf("元素%d不存在,删除失败\n",data);
return;
}
//3.如果查找成功,先将左子树合并到右子树中
if((*p)->left != NULL)
{
insert(&(*p)->right,(*p)->left);
}
//4.将要删除的节点地址单独保存
Node* q=*p;
//5.将连接目标节点的指针指向合并出来的右子树
*p=(*p)->right;
//6.删除目标节点,个数减1
free(q);
q=NULL;
pt->cnt--;
}
//采用中序方法遍历二叉数
void travelData(Tree* pt)
{
//调用递归函数进行遍历
travel(pt->root);
printf("\n");
}
//递归遍历函数 中序遍历
void travel(Node* pn)
{
if(pn!=NULL)
{
//1.遍历左子树
travel(pn->left);
//2.遍历根节点
printf("%d ",pn->data);
//3.遍历右子树
travel(pn->right);
}
}
//插入节点的递归函数
void insert(Node** pRoot,Node* pn)//二级指针
{
//1.判断二叉数是否为空,如果为空,直接插入即可
if(NULL==*pRoot)
{
//Node** pRoot=&root;
//*pRoot=root;
*pRoot=pn;
return;
}
//2. 如果二叉数不为空,则使用根节点与新节点比较大小
//2.1如果新节点小于根节点,则插入到左子树中
if(pn->data < (*pRoot)->data)
{
insert(&(*pRoot)->left,pn);
}
//2.2如果新节点大于根节点,则插入到右子树中
else
{
insert(&(*pRoot)->right,pn);
}
}
//创建新节点
Node* create_node(int data)//指针
{
Node* pn=(Node*)malloc(sizeof(Node));
pn->data=data;
pn->left=NULL;
pn->right=NULL;
return pn;
}
//插入新节点后,组成有序二叉数
void insertData(Tree* pt,int data)
{
//1.创建新建点
//2.插入新节点到二叉数中
insert(&pt->root,create_node(data));
//3.节点的个数加1
pt->cnt++;
}
输出结果:
50
10 50
10 30 50
10 30 40 50
10 20 30 40 50
10 20 30 40 50 70
10 20 30 40 50 60 70
----------------------
10 20 40 50 60 70
10 20 40 60 70
元素80不存在,删除失败
10 20 40 60 70
-----------------------
10 40 60 70 80
二叉数中根节点元素是:70
二叉数中节点个数是:5
二叉树未空
二叉树未满
--------------------------------
二叉数已清空
(2)链式有序二叉树(示例二)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
/* 节点 */
typedef struct BsTreeNode {
int data; /* 数据 */
struct BsTreeNode* left; /* 左子树 */
struct BsTreeNode* right; /* 右子树 */
} BSTREE_NODE;
/* 二叉树 */
typedef struct BsTree {
BSTREE_NODE* root; /* 树根 */
size_t size; /* 大小 */
} BSTREE;
/* 初始化为空树 */
void bstree_init (BSTREE* bstree);
/* 释放剩余节点并恢复到初始状态 */
void bstree_deinit (BSTREE* bstree);
/* 插入 */
void bstree_insert (BSTREE* bstree, int data);
/* 删除 */
int bstree_erase (BSTREE* bstree, int data);
/* 删除所有匹配数据 */
void bstree_remove (BSTREE* bstree, int data);
/* 清空 */
void bstree_clear (BSTREE* bstree);
/* 更新 */
void bstree_update (BSTREE* bstree, int old,
int new);
/* 判断是否存在 */
int bstree_exist (BSTREE* bstree, int data);
/* 中序遍历 */
void bstree_travel (BSTREE* bstree);
/* 大小 */
size_t bstree_size (BSTREE* bstree);
/* 高度 */
size_t bstree_height (BSTREE* bstree);
/* 测试用例 */
int main (void) {
BSTREE bstree;
bstree_init (&bstree);
bstree_insert (&bstree, 50);
bstree_insert (&bstree, 70);
bstree_insert (&bstree, 20);
bstree_insert (&bstree, 60);
bstree_insert (&bstree, 40);
bstree_insert (&bstree, 30);
bstree_insert (&bstree, 10);
bstree_insert (&bstree, 90);
bstree_insert (&bstree, 80);
/*
srand (time (NULL));
int i;
for (i = 0; i < 20; ++i)
bstree_insert (&bstree, rand () % 1000);
*/
bstree_travel (&bstree);
printf ("%u, %u\n", bstree_size (&bstree),
bstree_height (&bstree));
bstree_erase (&bstree, 60);
bstree_travel (&bstree);
bstree_insert (&bstree, 50);
bstree_insert (&bstree, 50);
bstree_travel (&bstree);
bstree_remove (&bstree, 50);
bstree_travel (&bstree);
bstree_insert (&bstree, 40);
bstree_insert (&bstree, 40);
bstree_travel (&bstree);
bstree_update (&bstree, 40, 85);
bstree_travel (&bstree);
printf ("%d, %d\n", bstree_exist (&bstree, 40),
bstree_exist (&bstree, 85));
bstree_deinit (&bstree);
return 0;
}
/* 创建节点 */
static BSTREE_NODE* create_node (int data) {
BSTREE_NODE* node = malloc (
sizeof (BSTREE_NODE));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
/* 销毁节点 */
static void destroy_node (BSTREE_NODE* node) {
free (node);
}
/* 将参数node的目标节点插入到以参数root的目标节点为
根的子树中 */
static void insert (BSTREE_NODE* node,
BSTREE_NODE** root) {
if (! *root)
*root = node;
else if (node)
if (node->data < (*root)->data)
insert (node, &(*root)->left);
else
insert (node, &(*root)->right);
}
/* 返回以参数root的目标所指向的节点为根的子树中,
数值与参数data相匹配的节点的父节点中,指向该
节点的指针型成员变量的地址 */
static BSTREE_NODE** find (int data,
BSTREE_NODE** root) {
if (! *root)
return root;
if (data < (*root)->data)
return find (data, &(*root)->left);
if ((*root)->data < data)
return find (data, &(*root)->right);
return root;
}
/* 销毁以参数root的目标节点为根的子树 */
static void clear (BSTREE_NODE** root) {
if (*root) {
clear (&(*root)->left);
clear (&(*root)->right);
destroy_node (*root);
*root = NULL;
}
}
/* 中序遍历以参数root的目标节点为根的子树 */
static void travel (BSTREE_NODE* root) {
if (root) {
travel (root->left);
printf ("%d ", root->data);
travel (root->right);
}
}
/* 返回以参数root的目标节点为根的子树的高度 */
static size_t height (BSTREE_NODE* root) {
if (root) {
size_t lh = height (root->left);
size_t rh = height (root->right);
return (lh > rh ? lh : rh) + 1;
}
return 0;
}
/* 初始化为空树 */
void bstree_init (BSTREE* bstree) {
bstree->root = NULL;
bstree->size = 0;
}
/* 释放剩余节点并恢复到初始状态 */
void bstree_deinit (BSTREE* bstree) {
clear (&bstree->root);
bstree->size = 0;
}
/* 插入 */
void bstree_insert (BSTREE* bstree, int data) {
insert (create_node (data), &bstree->root);
++bstree->size;
}
/* 删除 */
int bstree_erase (BSTREE* bstree, int data) {
BSTREE_NODE** node = find (data, &bstree->root);
if (*node) {
/* 将匹配节点的左子树插入其右子树 */
insert ((*node)->left, &(*node)->right);
BSTREE_NODE* temp = *node;
/* 用匹配节点的右子树的根节点取代匹配节点 */
*node = (*node)->right;
/* 删除匹配节点 */
destroy_node (temp);
--bstree->size;
return 1;
}
return 0;
}
/* 删除所有匹配数据 */
void bstree_remove (BSTREE* bstree, int data) {
while (bstree_erase (bstree, data));
}
/* 清空 */
void bstree_clear (BSTREE* bstree) {
bstree_deinit (bstree);
}
/* 更新 */
void bstree_update (BSTREE* bstree, int old,
int new) {
while (bstree_erase (bstree, old))
bstree_insert (bstree, new);
}
/* 判断是否存在 */
int bstree_exist (BSTREE* bstree, int data) {
return *find (data, &bstree->root) != NULL;
}
/* 中序遍历 */
void bstree_travel (BSTREE* bstree) {
travel (bstree->root);
printf ("\n");
}
/* 大小 */
size_t bstree_size (BSTREE* bstree) {
return bstree->size;
}
/* 高度 */
size_t bstree_height (BSTREE* bstree) {
return height (bstree->root);
}
输出结果:
10 20 30 40 50 60 70 80 90
9, 4
10 20 30 40 50 70 80 90
10 20 30 40 50 50 50 70 80 90
10 20 30 40 70 80 90
10 20 30 40 40 40 70 80 90
10 20 30 70 80 85 85 85 90
0, 1