1. 二叉排序树
二叉排序树又称二叉查找树,它是一种特殊的二叉树。
其定义为:二叉排序树或者是一棵空树,或者是具有如下性质的二叉树:
① 若它的左子树非空,则左子树上所有结点的值均均小于根结点的值。
② 若它的左子树非空,则左子树上所有结点的值均均大于(或大于等于)根结点的值。
③ 它的左右子树也分别为二叉排序树。
二叉排序树的特性
由二叉排序树定义可得,按中序遍历可以得到一个递增有序序列,按逆中序遍历可以得到一个递减有序序列。
如上图中序遍历结果为1,2,3,4,5,6,7,8,9,是递增有序序列。
逆中序遍历结果为9,8,7,6,5,4,3,2,1,是递减有序序列。
2. 二叉排序树实现算法
2.1 存储结构
二叉排序树的存储结构同二叉树,使用二叉链表作为存储结构。
typedef int DataType;
/*二叉排序树的存储结构*/
typedef struct node {
DataType data;
struct node* lchild, * rchild;
}BSTNode, * BSTree;
2.2 二叉排序树的插入与创建
给定一个元素序列,可以采用逐个插入结点算法来创建一棵二叉排序树。
例如按45、24、53、12、28、90顺序输入序列,生成二叉排序树过程如下图:
注:输入的顺序不同建立的二叉排序树也不同。
/*二叉排序树的插入算法(递归)*/
void InsertBST(BSTree* bst, DataType data) {
BSTree s;
if (*bst == NULL) {
s = (BSTree)malloc(sizeof(BSTNode));
s->data = data;
s->lchild = NULL;
s->rchild = NULL;
*bst = s;
}
else if (data < (*bst)->data)
InsertBST(&((*bst)->lchild), data); //将s插入左子树
else if (data >= (*bst)->data)
InsertBST(&((*bst)->rchild), data); //将s插入左子树
}
/*创建二叉排序树*/
void CreatBST(BSTree* bst) {
DataType data;
*bst = NULL;
scanf("%d", &data);
while (data != 0) {
InsertBST(bst, data);
scanf("%d", &data);
}
}
2.3 二叉排序树的查找
首先将待查数据data和根结点进行比较,如果:
① data = t,则返回根结点;
② data < t,则进一步查左子树;
③ data > t,则进一步查右子树。
/*二叉排序树的查找(递归)*/
BSTree SearchBST_recursion(BSTree bst, DataType data) {
if (bst == NULL)
return NULL;
else if (bst->data == data)
return bst;
else if (bst->data > data)
return SearchBST_recursion(bst->lchild, data); //在左子树继续查找
else
return SearchBST_recursion(bst->rchild, data); //在右子树继续查找
}
/*二叉排序树的查找(非递归)*/
BSTree SearchBST(BSTree bst, DataType data) {
BSTree q;
q = bst;
while (q) {
if (q->data == data)
return q;
if (q->data > data)
q = q->lchild; //查找左子树
else
q = q->rchild; //查找右子树
}
return NULL; //查找失败
}
2.4 二叉排序树的删除
删除操作首先查找要删除的结点,看是否在二叉排序树中,若不在不做任何操作;
否则假设要删除的结点为p,结点p的双亲结点为f,并假设结点p是结点f的左孩子:
① 若p为叶结点,则可直接删除:f->lchild=NULL
② 若p结点只有左子树,或只有右子树,则可将p的左子树或右子树直接改为双亲结点f的左子树:f->lchild=p->lchild(或f->lchild=p->rchild)
③ 若p既有左子树又有右子树,找到p结点在中序序列中的直接前驱s结点,然后用s结点的值替代p结点的值,再将s结点删除,原s结点的左子树改为s的双亲结点q的右子树:p->data = s->data;q->rchild = s->lchild;
BSTNode* DelBST(BSTree bst, DataType data) {
BSTNode* p, * f, * s, * q;
p = bst;
f = NULL;
while (p) {
//查找值为data的待删除结点
if (p->data == data)
break;
f = p; //f指向p结点的双亲结点
if (p->data > data)
p = p->lchild; //查找左子树
else
p = p->rchild; //查找右子树
}
if (p == NULL)
return bst;
if (p->lchild == NULL) {
//若待删除结点p无左子树
if (f == NULL) //若p为原二叉排序树的根
bst = p->rchild;
else if (f->lchild == p) //若p为f的左孩子
f->lchild = p->rchild;
else //若p为f的右孩子
f->rchild = p->rchild;
free(p);
}
else {
//若待删除结点p有左子树
q = p;
s = p->lchild;
while (s->rchild) {
//在p的左子树中查找最右下结点
q = s;
s = s->rchild;
}
if (q == p) //结点s无右子树
q->lchild = s->lchild;
else
q->rchild = s->lchild;
p->data = s->data;
free(s);
}
return bst;
}
3. 完整实现代码及运行结果
/*二叉排序树*/
# include<stdio.h>
# include<malloc.h>
typedef int DataType;
/*二叉排序树的存储结构*/
typedef struct node {
DataType data;
struct node* lchild, * rchild;
}BSTNode, * BSTree;
/*二叉排序树的插入算法(递归)*/
void InsertBST(BSTree* bst, DataType data) {
BSTree s;
if (*bst == NULL) {
s = (BSTree)malloc(sizeof(BSTNode));
s->data = data;
s->lchild = NULL;
s->rchild = NULL;
*bst = s;
}
else if (data < (*bst)->data)
InsertBST(&((*bst)->lchild), data); //将s插入左子树
else if (data >= (*bst)->data)
InsertBST(&((*bst)->rchild), data); //将s插入左子树
}
/*创建二叉排序树*/
void CreatBST(BSTree* bst) {
DataType data;
*bst = NULL;
scanf("%d", &data);
while (data != 0) {
InsertBST(bst, data);
scanf("%d", &data);
}
}
/*中序遍历输出二叉树*/
void InOrder(BSTree bst) {
if (bst != NULL) {
InOrder(bst->lchild);
printf("%d ", bst->data);
InOrder(bst->rchild);
}
}
/*二叉排序树的查找(递归)*/
BSTree SearchBST_recursion(BSTree bst, DataType data) {
if (bst == NULL)
return NULL;
else if (bst->data == data) {
printf("%d", bst->data);
return bst;
}
else if (bst->data > data)
return SearchBST_recursion(bst->lchild, data); //在左子树继续查找
else
return SearchBST_recursion(bst->rchild, data); //在右子树继续查找
}
/*二叉排序树的查找(非递归)*/
BSTree SearchBST(BSTree bst, DataType data) {
BSTree q;
q = bst;
while (q) {
if (q->data == data) {
printf("%d", q->data);
return q;
}
if (q->data > data)
q = q->lchild; //查找左子树
else
q = q->rchild; //查找右子树
}
return NULL; //查找失败
}
/*二叉排序树的删除*/
void DelBST(BSTree bst, DataType data) {
BSTNode* p, * f, * s, * q;
p = bst;
f = NULL;
while (p) {
//查找值为data的待删除结点
if (p->data == data)
break;
f = p; //f指向p结点的双亲结点
if (p->data > data)
p = p->lchild; //查找左子树
else
p = p->rchild; //查找右子树
}
if (p == NULL)
return bst;
if (p->lchild == NULL) {
//若待删除结点p无左子树
if (f == NULL) //若p为原二叉排序树的根
bst = p->rchild;
else if (f->lchild == p) //若p为f的左孩子
f->lchild = p->rchild;
else //若p为f的右孩子
f->rchild = p->rchild;
free(p);
}
else {
//若待删除结点p有左子树
q = p;
s = p->lchild;
while (s->rchild) {
//在p的左子树中查找最右下结点
q = s;
s = s->rchild;
}
if (q == p) //结点s无右子树
q->lchild = s->lchild;
else
q->rchild = s->lchild;
p->data = s->data;
free(s);
}
return bst;
}
int main() {
BSTree bst;
CreatBST(&bst);
printf("中序遍历输出:");
InOrder(bst);
printf("\n递归查找结果:");
SearchBST_recursion(bst, 12);
printf("\n非递归查找结果:");
SearchBST(bst, 12);
DelBST(bst, 24);
printf("\n删除值为24的结点后中序遍历输出:");
InOrder(bst);
return 0;
}
运行结果
参考:耿国华《数据结构——用C语言描述(第二版)》
更多数据结构内容关注我的《数据结构》专栏:https://blog.csdn.net/weixin_51450101/category_11514538.html?spm=1001.2014.3001.5482