二叉查找树

二叉查找树(BST:Binary Search Tree)是一种特殊的二叉树,它改善了二叉树节点查找的效率。二叉查找树有以下性质:

(1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值
(2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值
(3)左、右子树也分别为二叉排序树
(4)没有键值相等的节点

二叉查找树节点的定义:

 typedef struct BSTreeNode
{
int data;
struct BSTreeNode *left;//左子树
struct BSTreeNode *right;//右子树
}BSTree;

跟普通二叉树的节点定义相同

因为查找节点和插入节点都是在已经构建好二叉查找树的前提下才能进行的,在删除节点的时候才涉及到调整二叉树的操作,所以这里先以前序遍历的顺序直接输入一个二叉查找树,代码如下

 /* 创建二叉查找树(数据以前序遍历顺序输入)*/
BSTree *Create_BSTreeNode(BSTree *nod)
{
int num; scanf_s("%d", &num, );
if (num == ) /* 假定输入的数据都为正数,以0作为NULL的标志 */
{
return NULL;
}
else
{
if ((nod = (BSTree *)malloc(sizeof(BSTree))) == NULL)
{
printf("内存空间不足");
exit();
}
nod->data = num;
nod->left = Create_BSTreeNode(nod->left);
nod->right = Create_BSTreeNode(nod->right); return nod;
}
} /* 前序遍历二叉树,并打印 */
void PreOrder_Traverse(BSTree *nod, int level)
{
if (nod == NULL)
{
return ;
} printf("data = %d level = %d\n", nod->data, level);
PreOrder_Traverse(nod->left, level + );
PreOrder_Traverse(nod->right, level + );
}

1、查找节点(递归实现)

若根结点的关键字等于查找的关键字,查找成功,若小于根结点的关键字的值,递归查找左子树,若大于根结点的关键字的值,递归查找右子树,若子树为空,则查找失败,查找的操作较为简单,实现代码如下

 /* 查找特定值 */
void SearchData(int targ, BSTree *nod)
{
if (nod != NULL)
{
if (nod->data == targ)
{
printf("查找值存在,值为%d\n", nod->data);
}
else if (nod->data > targ)
{
SearchData(targ, nod->left); //递归查找左子树
}
else if (nod->data < targ)
{
SearchData(targ, nod->right); //递归查找右子树
}
}
else if (nod == NULL)
{
printf("查找值不存在\n");
}
}

通过 BST 查找节点,理想情况下我们需要检查的节点数可以减半。如下图中的 BST 树,包含了 15 个节点。从根节点开始执行查找算法,第一次比较决定我们是移向左子树还是右子树,对于任意一种情况,一旦执行这一步,我们需要访问的节点数就减少了一半,从 15 降到了 7。同样,下一步访问的节点也减少了一半,从 7 降到了 3,以此类推,根据这一特点,查找算法的时间复杂度应该是 O(log­2n)

(图片来源:https://www.cnblogs.com/gaochundong/p/binary_search_tree.html)

对于 BST 查找算法来说,其十分依赖于树中节点的拓扑结构,也就是节点间的布局关系,当 BST 树中的节点以扇形结构散开时,对它的插入、删除和查找操作最优的情况下可以达到亚线性的运行时间 O(log2n),

因为当在 BST 中查找一个节点时,每一步比较操作后都会将节点的数量减少一半。尽管如此,如果拓扑结构像下图中的样子时,运行时间就会退减到线性时间 O(n)。因为每一步比较操作后还是需要逐个比较其余的节点,

也就是说,在这种情况下,在 BST 中查找节点与在数组(Array)中查找就基本类似了。

因此,BST 算法查找时间依赖于树的拓扑结构。最佳情况是 O(log­2n),而最坏情况是 O(n)

测试用例:

查找:以前序遍历顺序输入一个二叉查找树(0作为NULL标志)

2、插入节点(递归实现)

新插入的结点一定是一个新添加的叶子结点,如下图

虽然上面两种插入结果得到的二叉树都符合二叉查找树的性质,但是不满足“新插入的结点一定是一个新添加的叶子结点因为有了这个特点插入的操作变得相对简单,实现代码如下

 /* 添加新节点 */
BSTree *AddNewNode(BSTree *cur, int NewData)
{
if (cur == NULL)
{
if ((cur = (BSTree *)malloc(sizeof(BSTree))) == NULL) //创建新节点
{
printf("内存不足");
exit();
}
cur->data = NewData;
cur->left = NULL;
cur->right = NULL; return cur;
}
if (NewData > cur->data)
{
cur->right = AddNewNode(cur->right, NewData);
}
else if (NewData < cur->data)
{
cur->left = AddNewNode(cur->left, NewData);
}
else if (NewData == cur->data)
{
printf("不允许插入重复值\n");
exit();
} return cur;
}

测试用例:

插入:以前序遍历顺序输入一个二叉查找树

3、删除节点

删除节点的操作相对查找和插入要相对复杂一些,主要考虑以下三种情况(前两种情况操作较为简单,第三种较为复杂)

在删除操作前先用要找到待删除节点的位置(这里使用的递归,也可以改成迭代)

情形一:删除叶子节点

因为删除叶子节点不会破坏BST的结构,删除叶子节点的操作较为简单,步骤如下

1、判断待删除节点的左右子树是否为空,如果都为空那么就是叶子节点

2、判断待删除节点是待删除节点父节点的右子树还是左子树,将对应的指针赋值NULL

3、free待删除节点

实现代码:

 /* 删除节点 */
/* cur为待删除节点, parent为待删除节点的父节点 */
void DeletNode(BSTree *parent, BSTree *cur, int DelData)
{
BSTree *SNode = NULL; //后继节点
BSTree *PSNode = NULL; //后继节点的父节点 if (cur == NULL)
{
printf("删除节点不存在\n");
exit();
}
else if (DelData > cur->data)
{
DeletNode(cur, cur->right, DelData);
}
else if (DelData < cur->data)
{
DeletNode(cur, cur->left, DelData);
}
else if(DelData == cur->data)
{
if (cur->left == NULL && cur->right == NULL) //待删除节点为叶子节点
{
if (parent->left == cur) //如果该节点是父节点的左子树
{
parent->left = NULL;
}
else if (parent->right == cur) //如果该节点是父节点的右子树
{
parent->right = NULL;
}
}

 因为删除节点这个子函数我是用的不带返回值的递归实现的,导致if else语句很多,后面我把删除节点这个子函数改成带返回值的递归,看起来要舒服不少,代码如下,有兴趣的读者可以看一下

 /* 删除节点 */
/* cur为待删除节点, parent为待删除节点的父节点 */
BSTree *DeletNode(BSTree *parent, BSTree *cur, int DelData)
{
BSTree *SNode = NULL; //后继节点
BSTree *PSNode = NULL; //后继节点的父节点
BSTree *temp = NULL; //临时保存待释放节点的子树,避免free后找不到左右子树 if (cur == NULL)
{
printf("删除节点不存在\n");
exit();
}
else if (DelData > cur->data)
{
cur->right = DeletNode(cur, cur->right, DelData);
}
else if (DelData < cur->data)
{
cur->left = DeletNode(cur, cur->left, DelData);
}
else if (DelData == cur->data)
{
if (cur->left == NULL && cur->right == NULL) //待删除节点为叶子节点
{
free(cur);
return NULL;
}

带返回值的递归实现

情形二:删除带有一个子节点的节点

(图片来源:https://www.cnblogs.com/songwenjie/p/8973217.html)

上图写了四种,但对待删除节点来说只有两种,只有左子树,或只有右子树,两种情况的处理方式基本相同,都是将待删除节点的左/右子树 赋值给 待删除节点的父节点的左/右子树

实现代码:

 else if(cur->left != NULL && cur->right == NULL)    //待删除节点只有左子树
{
if (parent->left == cur)
{
parent->left = cur->left;
}
else if (parent->right == cur)
{
parent->right = cur->left;
}
free(cur); //释放待删除节点
}
else if(cur->left == NULL && cur->right != NULL) //待删除节点只有右子树
{
if (parent->left == cur)
{
parent->left = cur->right;
}
else if (parent->right == cur)
{
parent->right = cur->right;
}
free(cur); //释放待删除节点
}
 else if(cur->left != NULL && cur->right == NULL)    //待删除节点只有左子树
{
temp = cur->left;
free(cur); return temp;;
}
else if(cur->left == NULL && cur->right != NULL) //待删除节点只有右子树
{
temp = cur->right;
free(cur); return cur->right;
}

带返回值的递归实现

情形三:删除带两个节点的节点

因为删除节点会有破坏 BST 正确结构的风险,删除带两个节点的节点操作显得较为复杂,首先需要找到待删除节点的 后继节点 和 该后继节点的父节点,(一个节点的后继节点是指,这个节点在中序遍历序列中的下一个节点,相应的,前驱节点是指这个节点在中序遍历序列中的上一个节点),删除节点的后继节点一定是删除节点右子树的最左侧节点,这篇随笔采用的方式是后继节点替代待删除节点的方式而不是前驱节点替代删除节点,需要考虑的情况如下

1、后继节点为待删除节点的子节点

在后继节点为待删除节点的子节点的前提下,该后继节点有右子树和没有右子树的操作是相同的,都是将 后继节点 替代 待删除节点,并将待删除节点的左子树 赋值给 后继节点的左子树

实现代码:

 else if(cur->left != NULL && cur->right != NULL)    //待删除节点既有左子树也有右子树
{
SNode = SearchSuccessorNode(cur->right); //搜索后继节点
PSNode = SearchParentofSNode(cur->right, cur->right); //搜索后继节点的父节点 if (cur->right == SNode) //后继节点为待删除节点的右子树(后继节点有右子树和没有右子树的操作相同)
{
if (parent->left == cur)
{
parent->left = SNode;
SNode->left = cur->left; free(cur);
}
else if (parent->right == cur)
{
parent->right = SNode;
SNode->left = cur->left; free(cur);
}
}
 else if(cur->left != NULL && cur->right != NULL)    //待删除节点既有左子树也有右子树
{
SNode = SearchSuccessorNode(cur->right); //搜索后继节点
PSNode = SearchParentofSNode(cur->right, cur->right); //搜索后继节点的父节点 if (cur->right == SNode) //后继节点为待删除节点的右子树(后继节点有右子树和没有右子树的操作相同)
{
SNode->left = cur->left;
free(cur); return SNode;
}

带返回值的递归实现

2、后继节点不为待删除节点的子节点

这里后继节点还要在分为后继节点有子节点没有子节点的情况

(1)后继节点没有右子节点

根据实现代码来标注上面的节点

删除后:

实现代码:

 else if (cur->right != SNode && SNode->right == NULL)    //后继节点不为待删除节点的右子树,并且该后继节点没有右子树
{
if (parent->left == cur)
{
parent->left = SNode;
SNode->left = cur->left;
SNode->right = cur->right;
PSNode->left = NULL; free(cur);
}
else if (parent->right == cur)
{
parent->right = SNode;
SNode->left = cur->left;
SNode->right = cur->right;
PSNode->left = NULL; free(cur);
}
}
 else if (cur->right != SNode && SNode->right == NULL)    //后继节点不为待删除节点的右子树,并且该后继节点没有右子树
{
SNode->left = cur->left;
SNode->right = cur->right;
PSNode->left = NULL;
free(cur); return SNode;
}

带返回值的递归实现

(2)后继节点有右子节点

删除后:

与上面的后继节点没有右子节点相比需要增加一个操作,需要将后继节点的右子树 赋值给 后继节点的父节点的左子树

实现代码:

 else if (cur->right != SNode && SNode->right != NULL)    //后继节点不为待删除节点的右子树,并且该后继节点有右子树
{
if (parent->left == cur)
{
parent->left = SNode;
PSNode->left = SNode->right; //后继节点的右子树作为后继节点父节点的左子树
SNode->left = cur->left;
SNode->right = cur->right; free(cur);
}
else if (parent->right == cur)
{
parent->right = SNode;
PSNode->left = SNode->right; //后继节点的右子树作为后继节点父节点的左子树
SNode->left = cur->left;
SNode->right = cur->right; free(cur);
}
}
 else if (cur->right != SNode && SNode->right != NULL)    //后继节点不为待删除节点的右子树,并且该后继节点有右子树
{ PSNode->left = SNode->right; //后继节点的右子树作为后继节点父节点的左子树
SNode->left = cur->left;
SNode->right = cur->right;
free(cur); return SNode;
}

带返回值的递归实现

测试数据:

一、“后继节点是删除节点的子节点”(因为后继节点有无子树的操作相同,这里只测试没有子树的情况)

二、“后继节点不是删除节点的子节点,且后继节点没有右子树”

三、“后继节点不是删除节点的子节点,且后继节点有右子树”

完整代码:(注:对free(cur)的位置进行了调整)

 #include <stdio.h>
#include <stdlib.h>
#include <conio.h> #define LEFT 1
#define RIGHT 2 typedef struct BSTreeNode
{
int data;
struct BSTreeNode *left;//左子树
struct BSTreeNode *right;//右子树
}BSTree; BSTree *Create_BSTreeNode(BSTree *nod); //创建二叉查找树
void PreOrder_Traverse(BSTree *nod, int level); //前序遍历二叉树,并打印
void SearchData(int targ, BSTree *nod); //查找特定值
BSTree *AddNewNode(BSTree *cur, int NewData); //添加新的节点
void DeletNode(BSTree *parent, BSTree *cur, int DelData); //删除节点
BSTree *SearchSuccessorNode(BSTree *nod); //搜索后继节点
BSTree *SearchParentofSNode(BSTree *Pnod, BSTree *nod); //搜索后继节点的父节点 int main()
{
BSTree *nod = NULL;
//int num;
int key;
//int del; nod = Create_BSTreeNode(nod);
PreOrder_Traverse(nod, ); //printf("输出查找数据\n");
//scanf_s("%d", &num, 1);
//SearchData(num, nod); printf("输出新插入数据\n");
scanf_s("%d", &key, );
nod = AddNewNode(nod, key); //printf("输出删除的数据\n");
//scanf_s("%d", &del, 1);
//DeletNode(nod, nod, del); PreOrder_Traverse(nod, ); return ;
} /* 搜索后继节点的父节点 */
BSTree *SearchParentofSNode(BSTree *Pnod, BSTree *nod)
{
while ()
{
if (nod->left != NULL)
{
Pnod = nod;
nod = nod->left;
}
else
{
break;
}
} return Pnod;
} /* 搜索后继节点 */
BSTree *SearchSuccessorNode(BSTree *nod)
{
while ()
{
if (nod->left != NULL)
{
nod = nod->left;
}
else
{
break;
}
} return nod;
} /* 删除节点 */
/* cur为待删除节点, parent为待删除节点的父节点 */
void DeletNode(BSTree *parent, BSTree *cur, int DelData)
{
BSTree *SNode = NULL; //后继节点
BSTree *PSNode = NULL; //后继节点的父节点 if (DelData > cur->data)
{
DeletNode(cur, cur->right, DelData);
}
else if (DelData < cur->data)
{
DeletNode(cur, cur->left, DelData);
}
else if(DelData == cur->data)
{
if (cur->left == NULL && cur->right == NULL) //待删除节点为叶子节点
{
if (parent->left == cur) //如果该节点是父节点的左子树
{
parent->left = NULL;
}
else if (parent->right == cur) //如果该节点是父节点的右子树
{
parent->right = NULL;
}
}
else if(cur->left != NULL && cur->right == NULL) //待删除节点只有左子树
{
if (parent->left == cur)
{
parent->left = cur->left;
}
else if (parent->right == cur)
{
parent->right = cur->left;
}
}
else if(cur->left == NULL && cur->right != NULL) //待删除节点只有右子树
{
if (parent->left == cur)
{
parent->left = cur->right;
}
else if (parent->right == cur)
{
parent->right = cur->right;
}
}
else if(cur->left != NULL && cur->right != NULL) //待删除节点既有左子树也有右子树
{
SNode = SearchSuccessorNode(cur->right); //搜索后继节点
PSNode = SearchParentofSNode(cur->right, cur->right); //搜索后继节点的父节点 if (cur->right == SNode) //后继节点为待删除节点的右子树(后继节点有右子树和没有右子树的操作相同)
{
if (parent->left == cur)
{
parent->left = SNode;
SNode->left = cur->left;
}
else if (parent->right == cur)
{
parent->right = SNode;
SNode->left = cur->left;
}
}
else if (cur->right != SNode && SNode->right == NULL) //后继节点不为待删除节点的右子树,并且该后继节点没有右子树
{
if (parent->left == cur)
{
parent->left = SNode;
SNode->left = cur->left;
SNode->right = cur->right;
PSNode->left = NULL;
}
else if (parent->right == cur)
{
parent->right = SNode;
SNode->left = cur->left;
SNode->right = cur->right;
PSNode->left = NULL;
}
}
else if (cur->right != SNode && SNode->right != NULL) //后继节点不为待删除节点的右子树,并且该后继节点有右子树
{
if (parent->left == cur)
{
parent->left = SNode;
PSNode->left = SNode->right; //后继节点的右子树作为后继节点父节点的左子树
SNode->left = cur->left;
SNode->right = cur->right;
}
else if (parent->right == cur)
{
parent->right = SNode;
PSNode->left = SNode->right; //后继节点的右子树作为后继节点父节点的左子树
SNode->left = cur->left;
SNode->right = cur->right;
}
}
}
free(cur); //释放待删除节点
}
} /* 添加新节点 */
BSTree *AddNewNode(BSTree *cur, int NewData)
{
if (cur == NULL)
{
if ((cur = (BSTree *)malloc(sizeof(BSTree))) == NULL) //创建新节点
{
printf("内存不足");
exit();
}
cur->data = NewData;
cur->left = NULL;
cur->right = NULL; return cur;
}
if (NewData > cur->data)
{
cur->right = AddNewNode(cur->right, NewData);
}
else if (NewData < cur->data)
{
cur->left = AddNewNode(cur->left, NewData);
}
else if (NewData == cur->data)
{
printf("不允许插入重复值\n");
exit();
} return cur;
} /* 查找特定值 */
void SearchData(int targ, BSTree *nod)
{
if (nod != NULL)
{
if (nod->data == targ)
{
printf("查找值存在,值为%d\n", nod->data);
}
else if (nod->data > targ)
{
SearchData(targ, nod->left); //递归查找左子树
}
else if (nod->data < targ)
{
SearchData(targ, nod->right); //递归查找右子树
}
}
else if (nod == NULL)
{
printf("查找值不存在\n");
}
} /* 创建二叉查找树(数据以前序遍历顺序输入)*/
BSTree *Create_BSTreeNode(BSTree *nod)
{
int num; scanf_s("%d", &num, );
if (num == ) /* 假定输入的数据都为正数,以0作为NULL的标志 */
{
return NULL;
}
else
{
if ((nod = (BSTree *)malloc(sizeof(BSTree))) == NULL)
{
printf("内存空间不足");
exit();
}
nod->data = num;
nod->left = Create_BSTreeNode(nod->left);
nod->right = Create_BSTreeNode(nod->right); return nod;
}
} /* 前序遍历二叉树,并打印 */
void PreOrder_Traverse(BSTree *nod, int level)
{
if (nod == NULL)
{
return ;
} printf("data = %d level = %d\n", nod->data, level);
PreOrder_Traverse(nod->left, level + );
PreOrder_Traverse(nod->right, level + );
}

因为主要是分析二叉查找树的查找、插入、删除操作,没有考虑二叉树为空 或 待删除节点为根节点的情况

补充:(注:删除节点函数修改成了带返回值的递归实现——更新日期2019/8/13)

 #include <stdio.h>
#include <stdlib.h>
#include <conio.h> #define LEFT 1
#define RIGHT 2 typedef struct BSTreeNode
{
int data;
struct BSTreeNode *left;//左子树
struct BSTreeNode *right;//右子树
}BSTree; BSTree *Create_BSTreeNode(BSTree *nod); //创建二叉查找树
void PreOrder_Traverse(BSTree *nod, int level); //前序遍历二叉树,并打印
void SearchData(int targ, BSTree *nod); //查找特定值
BSTree *AddNewNode(BSTree *cur, int NewData); //添加新的节点
BSTree *DeletNode(BSTree *parent, BSTree *cur, int DelData); //删除节点
BSTree *SearchSuccessorNode(BSTree *nod); //搜索后继节点
BSTree *SearchParentofSNode(BSTree *Pnod, BSTree *nod); //搜索后继节点的父节点 int main()
{
BSTree *nod = NULL;
//int num;
//int key;
int del; nod = Create_BSTreeNode(nod);
PreOrder_Traverse(nod, ); /*printf("输出查找数据\n");
scanf_s("%d", &num, 1);
SearchData(num, nod);*/ /*printf("输出新插入数据\n");
scanf_s("%d", &key, 1);
nod = AddNewNode(nod, key);*/ printf("输出删除的数据\n");
scanf_s("%d", &del, );
nod = DeletNode(nod, nod, del); PreOrder_Traverse(nod, ); return ;
} /* 搜索后继节点的父节点 */
BSTree *SearchParentofSNode(BSTree *Pnod, BSTree *nod)
{
while ()
{
if (nod->left != NULL)
{
Pnod = nod;
nod = nod->left;
}
else
{
break;
}
} return Pnod;
} /* 搜索后继节点 */
BSTree *SearchSuccessorNode(BSTree *nod)
{
while ()
{
if (nod->left != NULL)
{
nod = nod->left;
}
else
{
break;
}
} return nod;
} /* 删除节点 */
/* cur为待删除节点, parent为待删除节点的父节点 */
BSTree *DeletNode(BSTree *parent, BSTree *cur, int DelData)
{
BSTree *SNode = NULL; //后继节点
BSTree *PSNode = NULL; //后继节点的父节点
BSTree *temp = NULL; //临时保存待释放节点的子树,避免free后找不到左右子树 if (cur == NULL)
{
printf("删除节点不存在\n");
exit();
}
else if (DelData > cur->data)
{
cur->right = DeletNode(cur, cur->right, DelData);
}
else if (DelData < cur->data)
{
cur->left = DeletNode(cur, cur->left, DelData);
}
else if (DelData == cur->data)
{
if (cur->left == NULL && cur->right == NULL) //待删除节点为叶子节点
{
free(cur);
return NULL;
}
else if(cur->left != NULL && cur->right == NULL) //待删除节点只有左子树
{
temp = cur->left;
free(cur); return temp;;
}
else if(cur->left == NULL && cur->right != NULL) //待删除节点只有右子树
{
temp = cur->right;
free(cur); return cur->right;
}
else if(cur->left != NULL && cur->right != NULL) //待删除节点既有左子树也有右子树
{
SNode = SearchSuccessorNode(cur->right); //搜索后继节点
PSNode = SearchParentofSNode(cur->right, cur->right); //搜索后继节点的父节点 if (cur->right == SNode) //后继节点为待删除节点的右子树(后继节点有右子树和没有右子树的操作相同)
{
SNode->left = cur->left;
free(cur); return SNode;
}
else if (cur->right != SNode && SNode->right == NULL) //后继节点不为待删除节点的右子树,并且该后继节点没有右子树
{
SNode->left = cur->left;
SNode->right = cur->right;
PSNode->left = NULL;
free(cur); return SNode;
}
else if (cur->right != SNode && SNode->right != NULL) //后继节点不为待删除节点的右子树,并且该后继节点有右子树
{ PSNode->left = SNode->right; //后继节点的右子树作为后继节点父节点的左子树
SNode->left = cur->left;
SNode->right = cur->right;
free(cur); return SNode;
}
}
} return cur;
} /* 添加新节点 */
BSTree *AddNewNode(BSTree *cur, int NewData)
{
if (cur == NULL)
{
if ((cur = (BSTree *)malloc(sizeof(BSTree))) == NULL) //创建新节点
{
printf("内存不足");
exit();
}
cur->data = NewData;
cur->left = NULL;
cur->right = NULL; return cur;
}
if (NewData > cur->data)
{
cur->right = AddNewNode(cur->right, NewData);
}
else if (NewData < cur->data)
{
cur->left = AddNewNode(cur->left, NewData);
}
else if (NewData == cur->data)
{
printf("不允许插入重复值\n");
exit();
} return cur;
} /* 查找特定值 */
void SearchData(int targ, BSTree *nod)
{
if (nod != NULL)
{
if (nod->data == targ)
{
printf("查找值存在,值为%d\n", nod->data);
}
else if (nod->data > targ)
{
SearchData(targ, nod->left); //递归查找左子树
}
else if (nod->data < targ)
{
SearchData(targ, nod->right); //递归查找右子树
}
}
else if (nod == NULL)
{
printf("查找值不存在\n");
}
} /* 创建二叉查找树(数据以前序遍历顺序输入)*/
BSTree *Create_BSTreeNode(BSTree *nod)
{
int num; scanf_s("%d", &num, );
if (num == ) /* 假定输入的数据都为正数,以0作为NULL的标志 */
{
return NULL;
}
else
{
if ((nod = (BSTree *)malloc(sizeof(BSTree))) == NULL)
{
printf("内存空间不足");
exit();
}
nod->data = num;
nod->left = Create_BSTreeNode(nod->left);
nod->right = Create_BSTreeNode(nod->right); return nod;
}
} /* 前序遍历二叉树,并打印 */
void PreOrder_Traverse(BSTree *nod, int level)
{
if (nod == NULL)
{
return ;
} printf("data = %d level = %d\n", nod->data, level);
PreOrder_Traverse(nod->left, level + );
PreOrder_Traverse(nod->right, level + );
}

二叉查找树(查找、插入、删除)——C语言的更多相关文章

  1. 数据结构与算法->树->2-3-4树的查找,添加,删除(Java)

    代码: 兵马未动,粮草先行 作者: 传说中的汽水枪 如有错误,请留言指正,欢迎一起探讨. 转载请注明出处. 目录 一. 2-3-4树的定义 二. 2-3-4树数据结构定义 三. 2-3-4树的可以得到 ...

  2. 数据结构系列之2-3-4树的插入、查找、删除和遍历完整版源代码实现与分析(dart语言实现)

    本文属于原创,转载请注明来源. 在上一篇博文中,详细介绍了2-3树的操作(具体地址:https://www.cnblogs.com/outerspace/p/10861488.html),那么对于更多 ...

  3. Java实现二叉排序树的插入、查找、删除

    import java.util.Random; /** * 二叉排序树(又称二叉查找树) * (1)能够是一颗空树 * (2)若左子树不空,则左子树上全部的结点的值均小于她的根节点的值 * (3)若 ...

  4. 【数据结构】——搜索二叉树的插入,查找和删除(递归&非递归)

    一.搜索二叉树的插入,查找,删除 简单说说搜索二叉树概念: 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右 ...

  5. DS-二叉排序树的插入、查找和删除

    2019-12-02(菜鸡开始学习了...) Data Structure 之 二叉排序树 二叉排序树是给定一个节点后,接下来插入的数如果比它大就会放到它的右孩子那边,比它小就会放到它的左孩子那边. ...

  6. Splay的基本操作(插入/删除,查询)

    Splay的基本操作(插入/删除,查询) 概述 这是一棵二叉查找树 让频繁访问的节点尽量靠近根 将查询,插入等操作的点"旋转"至根 树的高度均摊为$log_n$ 变量 int ro ...

  7. leveldb源码分析--插入删除流程

    由于网络上对leveldb的分析文章都比较丰富,一些基础概念和模型都介绍得比较多,所以本人就不再对这些概念以专门的篇幅进行介绍,本文主要以代码流程注释的方式. 首先我们从db的插入和删除开始以对整个体 ...

  8. 洛谷 P2042 [NOI2005]维护数列-Splay(插入 删除 修改 翻转 求和 最大的子序列)

    因为要讲座,随便写一下,等讲完有时间好好写一篇splay的博客. 先直接上题目然后贴代码,具体讲解都写代码里了. 参考的博客等的链接都贴代码里了,有空再好好写. P2042 [NOI2005]维护数列 ...

  9. jQery实现插入删除信息

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  10. [LeetCode] Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复

    Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...

随机推荐

  1. 异常:Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]

    内容中包含 base64string 图片造成字符过多,拒绝显示

  2. 使用Python脚本伪造指定时间区间的数据库备份

    为监管需求,需要保留时间非常长的数据库备份.存储代价太大.所以存在了,临时抱佛脚,伪造备份.. 以下脚本功能,在于根据一个备份,复制出一段时间的备份.并且更改备份的文件时间戳.可以用shell轻松写出 ...

  3. Spring Boot + Elasticsearch 实现索引的日常维护

    全文检索的应用越来越广泛,几乎成了互联网应用的标配,商品搜索.日志分析.历史数据归档等等,各种场景都会涉及到大批量的数据,在全文检索方面,方案无外乎Lucene.Solr.Elasticsearch三 ...

  4. 移动app商城UI模板(仿淘宝)

    该商城UI模板是仿照手机淘宝,实现了搜索商品-查看商品详情-加入购物车-结算的流程,共7个页面,由于没有数据库,所有页面上的数据都来自tempData.cs及tempPro.cs ,具体页面参考如下 ...

  5. 2017-10271weblogic漏洞exp测试及补丁测试

    靶机:weblogic12.1.3.0 战斗机:kali 导弹:burpsuite 1.首先开启kali某端口监听 2.向靶机发送exp 3.查看kali监听 打码保平安~~ 4.打上补丁 5.验证补 ...

  6. InstantiationException:mybatis.spring.transaction.SpringManagedTransactionFactory

    问题表现 Error creating bean with name 'sqlSessionFactory' Invocation of init method failed; nested exce ...

  7. [HDOJ] 1172.猜数字

    Problem Description 猜数字游戏是gameboy最喜欢的游戏之一.游戏的规则是这样的:计算机随机产生一个四位数,然后玩家猜这个四位数是什么.每 猜一个数,计算机都会告诉玩家猜对几个数 ...

  8. tomcat启动成功但是没有监听8080端口

    查看tomcat日志 cd tomcat/logs tailf -1000 catlina.out 错误如下: /home/work/jdk/jdk-10.0.1/jre/bin/java: No s ...

  9. 《VR入门系列教程》之14---面向大众的Unity3D

    大众化的游戏引擎--Unity3D     并不是所有VR应用都是游戏,然而现在做VR开发的几乎都会用专业游戏引擎来做,因为游戏引擎既满足了一个引擎的要求又可以方便地制作出高品质的VR应用.一个游戏引 ...

  10. CentOS 下编译安装PHP

    1.   去php官网下载源码 http://www.php.net/downloads.php ,我下载使用的版本是(php-5.4.8.tar.gz) 2.   安装环境 yum install ...