查找中二叉排序树的构造c语言,数据结构——二叉搜索树(Binary Search Tree)C语言实现...

前言

把二叉搜索树的相关内容又复习了一遍,但是对于代码的理解还是不到位,决定整理一篇文章,把代码部分吃透。主要代码实现来源于浙大MOOC何钦铭老师的视频,本文还参考了csdn博主wwxy261的文章,比较巧的是这位博主也采用了浙大MOOC的代码。

1.二叉搜索树(Binary Search Tree)介绍

二叉搜索树,可以为空,如果不空,应该满足以下性质:

非空左子树所有键值小于其根节点的键值,

非空右子树所有键值大于其根节点的键值

左右子树都是二叉搜索树

2.二叉搜索树的结构定义

二叉搜索树的结构在这里采用二叉链表实现。为了便于比较结点键值大小,我们将结点Data类型设置为int型。本次实验主要采用指针操作,注意BinTree是定义好的结点TNode类型指针。

typedef int ElementType;

typedef struct TNode *Position;

typedef Position BinTree;

struct TNode

{

ElementType Data;

BinTree Left;

BinTree Right;

};

复制代码

3.创建二叉搜索树

创建二叉搜索树的基本操作是插入操作,

其接口定义为BinTree Insert( BinTree BST, ElementType X );

其核心步骤是:如果传入的是空指针,我们就申请空间,添加数据,将新结点赋给根指针并返回;如果传入的元素比根元素小,我们就将根元素的左孩子作为新的根节点,递归调用Insert到新结点去寻找位置插入并返回给新根;同理,传入元素比根元素大,就把根元素的右孩子作为新根结点。

插入操作代码如下所示:

/*--------将X插入二叉搜索树BST并返回结果树的根结点指针-------*/

BinTree Insert( BinTree BST, ElementType X ){

if( !BST ){ /* 若原树为空,生成并返回一个结点的二叉搜索树 */

BST = (BinTree)malloc(sizeof(struct TNode));

BST->Data = X;

BST->Left = BST->Right = NULL;

}

else { /* 开始找要插入元素的位置 */

if( X < BST->Data )

BST->Left = Insert( BST->Left, X ); /*递归插入左子树*/

else if( X > BST->Data )

BST->Right = Insert( BST->Right, X ); /*递归插入右子树*/

/* else X已经存在,什么都不做 */

}

return BST;

}

复制代码

下面展示三个结点的插入过程,注意在此过程中根节点是不发生变化的(画图前我犯的错误就是误以为BST会发生变化),事实上每次递归会让BST指向下一层的孩子,如图中波浪线所示,这个会随着递归的深度增加而不断变长。所以我们以后有能力时,不得不考虑这所造成的性能问题。

33b355f88945e062cbe321b850a0d293.png

创建二叉搜索树代码如下所示:

int a[10] = {5, 8, 6, 2, 4, 1, 0, 10, 9, 7};

BinTree BST;

BST = NULL;

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

BST = Insert(BST, a[i]);

复制代码

4.删除二叉搜索树中的一个结点

删除接口定义为BinTree Delete( BinTree BST, ElementType X ),将从二叉搜索树中删除键值为X的元素,做好调整,返回树的根结点指针;如果X不在树中,则打印Not Found,返回树的根结点指针。

其核心思想分为三种情况:

删除的是叶子结点,直接删除,再修改其父结点指针指向NULL

删除的结点只有一个孩子结点,将指向被删除结点的指针置为指向被删除结点的孩子

删除的结点有左右两颗子树:用一个结点替代被删除元素,如右子树的最小元素或左子树的最大元素。特点:右子树的最小元素或左子树的最大元素一定不是有两个儿子

代码如下所示:

BinTree Delete( BinTree BST, ElementType X ){

Position Tmp;

if( !BST )

printf("Not Found!");

else {

if( X < BST->Data )

BST->Left = Delete( BST->Left, X ); /* 从左子树递归删除 */

else if( X > BST->Data )

BST->Right = Delete( BST->Right, X ); /* 从右子树递归删除 */

else { /* BST就是要删除的结点 */

/* 如果被删除结点有左右两个子结点 */

if( BST->Left && BST->Right ) {

/* 从右子树中找最小的元素填充删除结点 */

Tmp = FindMin( BST->Right );

BST->Data = Tmp->Data;

/* 从右子树中删除最小元素 */

BST->Right = Delete( BST->Right, BST->Data );

}

else { /* 被删除结点有一个或无子结点 */

Tmp = BST;

if( !BST->Left ) /* 只有右孩子或无子结点 */

BST = BST->Right;

else if ( !BST->Right ) /* 只有左孩子 */

BST = BST->Left;

free( Tmp );

}

}

}

return BST;

}复制代码

下面花了一个简单的示意图,但是画的不太好,恐怕不能很快理解。但是画图确实可以提高理解能力,建议自己动手画一下。

0cd43910911554972fd9fba629240a58.pngDelete

5.二叉搜索树其他操作

接口定义:

Position FindMax (BinTree BST)找到最大元素的位置并返回该指针

Position FindMin (BinTree BST)找到最小元素的位置并返回该指针

Position Find (ElementType x, BinTree BST)递归查找元素,返回指针

Position iterFind (ElementType x, BinTree BST)迭代查找元素,返回指针

代码如下:

//迭代查找最大值的位置

Position FindMax (BinTree BST){

if (BST) {

while (BST->Right) { //沿着右分支查找 直到右结点

BST = BST->Right;

}

}

return BST;

}

//递归查找最小值

Position FindMin (BinTree BST){

if (!BST) return NULL; //空二叉树,返回空

else if (!BST->Left)

return BST; //找到最左叶结点,并返回

else

return FindMin(BST->Left); //沿着左分支继续查找

}

//尾递归实现二叉搜索树查找,效率不高,尾递归都可以改为循环迭代实现

Position Find (ElementType x, BinTree BST){

if ( !BST ) return NULL; //查找失败

if ( x > BST->Data ) //x比当前元素大,到右子树去查找

return Find(x, BST->Right);

else if ( x < BST->Data) //x比当前元素小,到左子树去查找

return Find(x, BST->Left);

else

return BST; //查找成功

}

//迭代实现查找

//查找效率取决于树的高度

Position iterFind (ElementType x, BinTree BST){

while (BST) {

if ( x > BST->Data ) //x比当前元素大,到右子树去查找

BST = BST->Right;

else if ( x < BST->Data) //x比当前元素小,到左子树去查找

BST = BST->Left;

else

return BST; //查找成功

}

return NULL;

}复制代码

6.测试

测试代码如下:

int main(int argc, char const *argv[]){

//测试数据:

int a[10] = {5, 8, 6, 2, 4, 1, 0, 10, 9, 7};

BinTree BST, MinPos, MaxPos, Temp;

int i;

BST = NULL;

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

BST = Insert(BST, a[i]);

printf("\nPreOrder:\n");

PreOrderTraversal(BST);

printf("\nInOrder:\n");

InOrderTraversal(BST);

MaxPos = FindMax(BST);

MinPos = FindMin(BST);

printf("\nThe Largest number in BST is %d \n",MaxPos->Data);

printf("\nThe Smallest number in BST is %d \n",MinPos->Data);

int Y = 6;

Temp = Find(Y,BST);

if( Temp == NULL )

printf("%d is Not Found!\n",Y);

else

printf("Find %d!\n",Y);

int Z = 9;

BST = Delete(BST,Z);

printf("\nInOrder:\n");

InOrderTraversal(BST);

return 0;

}复制代码

7.总结

二叉搜索树的时间复杂度取决于二叉树的形状,但二叉树的形状是不可确定的。我们可以知道最坏时间复杂度是O(n),最坏情况的二叉搜索树是一颗斜树,甚至可以看成一个链表。

为了方便读者快速上手代码,决定贴出自己的渣渣github库.希望考研复试顺利,有时间可以继续更下去ヾ(◍°∇°◍)ノ゙!

本文使用 mdnice 排版

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值