6. 蛤蟆的数据结构进阶六之二叉树排序树

6. 蛤蟆的数据结构进阶六之二叉树排序树

本篇名言:“有些人因为贪婪,想得更多的东西,却把现在所有的也失掉了。 --
伊索”

关于理论知识已经在上篇中进行描述,这篇我们主要来看下如何是实现二叉排序树。

欢迎转载,转载请标明出处:

1.  二叉排序树的定义

 二叉排序树(BinarySort Tree)又称二叉查找(搜索)树(Binary Search Tree)。其定义为:二叉排序树或者是空树,或者是满足如下性质的二叉树:

①若它的左子树非空,则左子树上所有结点的值均小于根结点的值;

②若它的右子树非空,则右子树上所有结点的值均大于根结点的值;

③左、右子树本身又各是一棵二叉排序树。

  上述性质简称二叉排序树性质(BST性质),故二叉排序树实际上是满足BST性质的二叉树。

2.  代码实现

2.1         定义结构体

如下结构体

typedef
struct

{

KeyTypekey;                                               //关键字域

}
ElemType;

typedef
struct
BiTNode               //定义二叉树二叉链表

{

ElemType  data;

struct BiTNode*lchild, *rchild;

}BiTNode,*BiTree,*SElemType;

typedef
struct

{

SElemType*base;

SElemType*top;

intstacksize;

}SqStack;

定义元素类型。

定义二叉树二叉链表。

最后定义一个堆栈。

2.2         main

运行过程中,输入节点数值为:{45 30 59 24 10 55 40 53 28 49 12 5037 62 90 88 93},

每次输入调用SearchBST函数来判断是否存在概述,如果存在则提示而不进行插入。如果不存在则调用InsertBST函数实现将数值插入到二叉树中。

然后调用ShowBST 函数来输出二叉树。

然后输入一个关键词进行删除,然后显示删除后的二叉树。

然后调用函数PreOrderTraverse来进行先序遍历,调用函数InOrderTraverse来进行中序遍历,调用函数PostOrderTraverse来进行后续遍历。调用函数ClearBiTree来清空二叉树,调用函数ClearBiTree来销毁二叉树。

PS:先序遍历也叫做先根遍历前序遍历,可记做根左右(二叉树父结点向下先左后右)。

中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。

后序遍历首先遍历左子树,然后遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。

2.3         SearchBST

输入参数为二叉树指针,关键值,根节点,以及另一个二叉树变量地址p用于接受返回值。

查找关键字,指针p返回。

首先判断二叉树是否为空,为空则直接返回FALSE。

不会空,判断关键值是否和二叉树的中值相等。

如果相等则返回二叉树指针,并返回OK。

否则则进行递归调用。小于根节点则从左子树开始递归,否则从右子树开始递归。

2.4         InsertBST

输入参数为二叉树指针是元素。

也再一次判断是会否存在相同元素,如果存在退出。

否则,则分配一个空间,这个该值为输入的元素。

然后设置左右子节点为NULL。

接着判断是否是根节点,如果是则将钙元素设置为根。

否则,判断是大于叶子节点,设置为左或者右。

2.5         ShowBST

判断二叉树是否为空,不会空则递归调用ShowBST,从右节点开始输出,然后是中间,最后是左节点。

2.6         DeleteBST

输入二叉树指针和关键词。

如果二叉树为空则返回。

判断是否和当前指针的data相等,相等则调用DELETE函数进行删除。

否则判断是否小于当前指针的data,小于则递归从左子节点继续删除。

然后从右子节点继续删。

2.7         Delete

先判断右子树是否为空,如果右子树为空,那么释放中节点,保留左子树(此时并不知道左子树是否为空)。

如果右子树不为空,左子树也为空,那么释放中节点,保留右子树。

如果都不为空,从左子树的右节点开始,找到左子树的最右叶子节点。

将当前值设置为该值,因为其左子树的最右叶子节点,肯定比左子树大,而比右子树小的。

2.8         PreOrderTraverse

排序需要用到堆栈了。

先调用InitStack函数来初始化堆栈,得到堆栈地址。

判断堆栈是否为空或者p是否为空。(p的初始值为二叉树)

如果不为空则进行压栈,然后调用Visit函数来输出节点,然后取p的左节点。

如果p为空,调用Pop函数从堆栈弹出一个值。取右节点。

以此循环。

2.9         Visit

函数来输出节点的值。

2.10   Push

如果空间还有空间,则直接返回栈顶指针。如果不够,怎将堆栈进行重新分配。

2.11   Pop

如果到栈底,则返回ERROR。

否则返回栈顶元素。

2.12   InOrderTraverse

中序遍历,类似先序遍历。

先一直压栈左节点数,直到左节点数为空。

然后弹出一个,输出值,再去弹出值的右节点数。

2.13   PostOrderTraverse

后序遍历。

P初始化为二叉树指针。

相比前序和中序遍历,略微复杂一点。

使用两个堆栈S和SS。

将右节点一致压栈到两个堆栈,直到为空。

然后从S堆栈弹出一个,获取该弹出值的左节点。继续上个查找右节点的操作。直到p为空,且堆栈S为空。

然后从堆栈SS中挨个输出值。

2.14   ClearBiTree

将二叉树的根节点幅值为NULL。

2.15   ClearBiTree

2.16   InitStack

分配堆栈。返回堆栈基地址。

将堆栈底和堆栈顶放在同一个地址。

3.  源码

#include
"stdio.h"

#include
"stdlib.h"

#define
KeyType
int

#define
EQ(a,b)((a)==(b))

#define
LT(a,b)((a)< (b))

#define
LQ(a,b)((a)<=(b))

#define
TRUE 1

#define
FALSE 0

#define
STACK_INIT_SIZE100

#define
OVERFLOW-1

#define
OK 1

#define
STACKINCREMENT10

#define
ERROR-1

typedef
struct

{

KeyTypekey;                                                //关键字域

}
ElemType;

typedef
struct
BiTNode               //定义二叉树二叉链表

{

ElemType  data;

struct BiTNode*lchild, *rchild;

}BiTNode,*BiTree,*SElemType;

typedef
struct

{

SElemType*base;

SElemType*top;

intstacksize;

}SqStack;

int DestroyBiTree(BiTree&T)
//销毁树

{

if(T!=NULL)

free(T);

return0;

}

int ClearBiTree(BiTree&T)
//清空树

{

if(T!=NULL)

{

T->lchild=NULL;

T->rchild=NULL;

T=NULL;

}

return0;

}

int SearchBST(BiTree
T,KeyType
key,BiTree
f,BiTree&p)   //查找关键字,指针p返回

{

if(!T)

{

p=f;

return FALSE;

}

else if
EQ(key,T->data.key)

{

p=T;

return TRUE;

}

else if
LT(key,T->data.key)

returnSearchBST(T->lchild,key,T,p);

else

returnSearchBST(T->rchild,key,T,p);

}

int InsertBST(BiTree&T,ElemType
e)  
//插入节点元素

{

BiTrees,p;

if(!SearchBST(T,e.key,NULL,p))

{

s=(BiTree)malloc(sizeof(BiTNode));

s->data=e;

s->lchild=s->rchild=NULL;

if(!p)

T=s;

else if
LT(e.key,p->data.key)

p->lchild=s;

else

p->rchild=s;

return TRUE;

}

else return
FALSE;

}

int ShowBST(BiTree
T,int
nlayer)     
//显示树形二叉排序树

{

inti;

if(T==NULL)

return FALSE;

ShowBST(T->rchild,nlayer+1);

for(i=0;i<nlayer;i++)

printf("    ");

printf("%d\n",T->data);

ShowBST(T->lchild,nlayer+1);

return OK;

}

int Visit(ElemType
e) 
//Visit函数

{

printf("%d",e.key);

return OK;

}

int InitStack(SqStack&S)  //构造空栈

{

S.base=(SElemType*)malloc(STACK_INIT_SIZE *sizeof(SElemType));

if(!S.base)exit(OVERFLOW);

S.top=S.base;

S.stacksize=STACK_INIT_SIZE;

return OK;

}//InitStack

int Push(SqStack&S,
SElemType
e)  //插入元素e为新栈顶

{

if(S.top-S.base>=S.stacksize)

{

S.base=(SElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));

if(!S.base)exit(OVERFLOW);

S.top=S.base+S.stacksize;

S.stacksize+=STACKINCREMENT;

}

*S.top++=e;

return OK;

}//Push

int Pop(SqStack&S,SElemType&e) //删除栈顶,应用e返回其值

{

if(S.top==S.base) 
return
ERROR;

e=*--S.top;

return OK;

}//Pop

int StackEmpty(SqStack
S)         
//判断是否为空栈

{

if(S.base==S.top)return
TRUE;

return FALSE;

}

int PreOrderTraverse(BiTree
T,int(*Visit)(ElemTypee)) 
//先序遍历,运用栈

{

SqStackS;

BiTreep;

InitStack(S);

p=T;

while(p||!StackEmpty(S))

{

if(p)

{

Push(S,p);

if(!Visit(p->data))return
ERROR;

p=p->lchild;

}

else

{

Pop(S,p);

p=p->rchild;

}

}

return OK;

}

int InOrderTraverse(BiTree
T,
int(*Visit)(ElemTypee)) 
//中序遍历,运用栈

{

SqStackS;

BiTreep;

InitStack(S);

p=T;

while(p||!StackEmpty(S))

{

if(p)

{

Push(S,p);

p=p->lchild;

}

else

{

Pop(S,p);

if(!Visit(p->data))return
ERROR;

p=p->rchild;

}

}

return OK;

}

int PostOrderTraverse(BiTree
T,int(*Visit)(ElemTypee))
//后序遍历,运用栈

{

SqStackS,SS;

BiTree p;

InitStack(S);

InitStack(SS);

p=T;

while(p||!StackEmpty(S))

{

if(p)

{

Push(S,p);

Push(SS,p);

p=p->rchild;

}

else

{

if(!StackEmpty(S))

{

Pop(S,p);

p=p->lchild;

}

}

}

while(!StackEmpty(SS))

{

Pop(SS,p);

if(!Visit(p->data))return
ERROR;

}

return OK;

}

int Delete(BiTree&p)
// 三种删除节点的操作实现

{

BiTreeq,s;

if(!p->rchild)   
//右子树为空

{

q=p;

p=p->lchild;

free(q);

}

else if(!p->lchild)   
//左子树为空

{

q=p;

p=p->rchild;

free(q);

}

else

{

q=p;

s=p->lchild;

while(s->rchild)

{

q=s;

s=s->rchild;

}

p->data=s->data;

if(q!=p)

q->rchild=s->lchild;

else

q->lchild=s->lchild;

deletes;

}

return TRUE;

}

int DeleteBST(BiTree&T,KeyType
key)
//实现二叉排序树的删除操作

{

if(!T)

return FALSE;

else

{

if (EQ(key,T->data.key))      
//T->data.key等于key

returnDelete(T);

else if (LT(key,T->data.key))  
//T->data.key是否小于key

returnDeleteBST(T->lchild,key);

else

returnDeleteBST(T->rchild,key);

}

return0;

}

void main ()

{

inti,nlayer;

ElemTypek,d;

BiTree  BT,p;

BT=NULL;

p=NULL;

nlayer=1;

printf("请输入插入的二叉树节点的数值(输入数字0结束节点赋值):\n");

scanf("%d",&k.key);

for(i=0;k.key!=NULL;i++)

{

if(!SearchBST(BT,k.key,NULL,p))        
//查找关键字

{

InsertBST(BT,k);                   
//二叉树节点数值插入

scanf("%d",&k.key);

}

else

{

printf("输入数据重复!\n");

return ;

}

}

printf("二叉排序树树形输出为:\n");

ShowBST(BT,nlayer);                       
//树形显示二叉排序树

printf("请输入删除的数据:");

scanf("%d",&d.key);

DeleteBST(BT,d.key);                      
//删除关键字

ShowBST(BT,nlayer);

printf("先序遍历为:");                   
//先序遍历、中序遍历、后序遍历

PreOrderTraverse(BT,Visit);

printf("\n中序遍历为:");

InOrderTraverse(BT,Visit);

printf("\n后序遍历为:");

PostOrderTraverse(BT,Visit);

printf("\n清空该二叉排序树.\n");           
//清空二叉树

ClearBiTree(BT);

ShowBST(BT,nlayer);

printf("\n销毁该二叉排序树.\n");            //销毁二叉树

ClearBiTree(BT);

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-23 13:44:14

6. 蛤蟆的数据结构进阶六之二叉树排序树的相关文章

19. 蛤蟆的数据结构进阶十九外部排序相关概念

19. 蛤蟆的数据结构进阶十九外部排序相关概念 本篇名言:"一个人最怕不老实,青年人最可贵的是老实作风. "老实 " 就是不自欺欺人,做到不欺骗人家容易,不欺骗自己最难. "老实作风 " 就是脚踏实地,不占便宜.世界上没有便宜的事,谁想占便宜水就会吃亏. --徐特立" 之前我们学习的排序都是内部排序的,接下去来看下外部排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47

16. 蛤蟆的数据结构进阶十六排序实现之基数排序

16. 蛤蟆的数据结构进阶十六排序实现之基数排序 本篇名言:"社会犹如一条船 ,每人都要有掌舵的准备.--易卜生" 我们来看下基数排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47760601 1.  基数排序 基数排序(radix sort)属于"分配式排序"(distributionsort),又称"桶子法"(bucket sort)或bin sort,顾名思义,

8. 蛤蟆的数据结构进阶八哈希表相关概念

8. 蛤蟆的数据结构进阶八哈希表相关概念 本篇名言:"作家当然必须挣钱才能生活,写作,但是他决不应该为了挣钱而生活,写作.--马克思" 前些笔记我们学习了二叉树相关.现在我们来看下哈希表.这篇先来看下哈希表的相关概念 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47347273 1.  哈希表的概念 哈希表(HashTable)也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构.它通过把关键

7. 蛤蟆的数据结构进阶七平衡二叉树

7. 蛤蟆的数据结构进阶七平衡二叉树 本地名言:"金钱的贪求(这个毛病,目前我们大家都犯得很凶)和享乐的贪求,促使我们成为它们的奴隶,也可以说,把我们整个身心投入深渊.唯利是图,是一种痼疾,使人卑鄙,但贪求享乐,更是一种使人极端无耻,不可救药的毛病. --郎加纳斯" 我们来看下传说中的平衡二叉树,为什么说他传说中呢?因为蛤蟆接触ORACLE数据库比较多,而ORACLE数据中用到最多的索引就是平衡二叉树,所以嘛. 欢迎转载,转载请标明出处:http://write.blog.csdn.n

5. 蛤蟆的数据结构进阶五动态查询

5. 蛤蟆的数据结构进阶五动态查询 本篇名言:"判断一个人,不是根据他自己的表白或对自己的看法,而是根据他的行动. --列宁" OK,我们接下去来看下动态查询. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47284473 1.  动态查找表 动态查找表:若在查找过程中可以将查找表中不存在的数据元素插入,或者从查找表中删除某个数据元素,则称这类查找表为动态查找表.动态查找表在查找过程中查找表可能会发生变化.对动态

17. 蛤蟆的数据结构进阶十七排序实现之归并排序

17. 蛤蟆的数据结构进阶十七排序实现之归并排序 本篇名言:"人生不是一种享乐 ,而是一桩十分沉重的工作.-- 列夫 . 托尔斯泰" 我们来看下归并排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47790163 1.  归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个

15. 蛤蟆的数据结构进阶十五排序实现之堆排序

15. 蛤蟆的数据结构进阶十五排序实现之堆排序 本篇名言:"谁要是游戏人生 ,他就一事无成 ; 谁不能主宰自己 ,永远是一个奴隶.--歌德" 继续来看下堆排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47733553 1.  堆排序 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种.可以利用数组的特点快速定位指定索引的元素.堆分为大根堆和小根堆,是完全二叉树

14. 蛤蟆的数据结构进阶十四排序实现之简单选择排序

14. 蛤蟆的数据结构进阶十四排序实现之简单选择排序 本篇名言:"即是我们是一支蜡烛也应该 " 蜡烛成灰泪始干 " 即使我们只是一根火柴也要在关键时刻有一次闪耀即使我们死后尸骨都腐烂了解也要变成磷火在荒野中燃烧. -- 艾青" 继续来看什么是简单选择排序. 欢迎转载,转载请标明出处: 1.  简单选择排序 设所排序序列的记录个数为n.i取1,2,-,n-1,从所有n-i+1个记录(Ri,Ri+1,-,Rn)中找出排序码最小的记录,与第i个记录交换.执行n-1趟后就完

9. 蛤蟆的数据结构进阶九哈希表实现

9. 蛤蟆的数据结构进阶九哈希表实现 本篇名言:"人们所努力追求的庸俗的目标 --我总觉得都是可鄙的. -- 爱因思坦" 上篇我们看了哈希表的相关定义和概念,这篇来看下如何来实现. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47362781 1.  代码实现 1.1             Main 函数定义哈希元素数组 10个元素. 定义哈希表变量. 调用InitHashTable构造一个空的哈希表. 然后循