定义及描述
二叉排序树(Binary Sort Tree)也称二叉查找树,是一种特殊的二叉树。
二叉排序树或者是一棵空树;
或者具有下列性质:
(1)若左子树不空,则左子树中所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树中所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
结点结构体定义:
typedef struct NODE
{
int key;
struct NODE *Lchild;
struct NODE *Rchild;
}BstNode, *BsTree;
二叉排序树的插入
若二叉树为空。则首先单独生成根结点。
若二叉树非空,则将插入值与二叉排序树根结点的关键字进行比较:
a.如果key的值等于根结点的值,则停止插入;
b.如果key的值小于根结点的值,则将结点插入左子树;
c.如果key的值大于根结点的值,则将结点插入右孩子。- 注意:新插入的结点总是叶子结点。
题目:已知序列5,4,8,1,9,7,6,2,12,11,10,3,按照此顺序构造二叉排序树
程序清单:
//创建有序二叉树时的插入算法
void Ins_BsTree(BsTree *root, int key)
{
BstNode *Bsnode;
if (*root == NULL)
{
Bsnode = (BstNode*)malloc(sizeof(BstNode));
Bsnode->key = key;
Bsnode->Lchild = NULL;
Bsnode->Rchild = NULL;
*root = Bsnode;
}
else if (key < (*root)->key)
{
Ins_BsTree(&((*root)->Lchild), key);
}
else if (key>(*root)->key)
{
Ins_BsTree(&((*root)->Rchild), key);
}
}
//创建二叉排序树
void CreateBsTree(BsTree *Bst)
{
int input = 0;
printf("请输入数据建立二叉树,输入“-1”结束。\n");
scanf("%d", &input);
while (input != -1)
{
Ins_BsTree(Bst, input);//调用插入算法将新输入的数据有序的插入到二叉树中
scanf("%d", &input);
}
}
二叉排序树的查找
因为二叉排序树可看做是一个有序表,所以在二叉排序树上进行查找,和折半查找类似,也是一个逐步缩小查找范围的过程。
算法思想:首先将待查关键字key与根结点关键字t进行比较,如果:
- key = t:则返回根结点地址
- key < t:进一步查左子树
- key > t:进一步查右子树
程序清单:
//二叉树的查找
BstNode* SearchBstree(BsTree Bsroot, int key)
{
//二叉树为NULL,查找不到,返回NULL
if (Bsroot == NULL)
{
return NULL;
}
//查找到,返回该结点
if (Bsroot->key == key)
{
return Bsroot;
}
//比根结点的值大,在右子树上查找
else if (key > Bsroot->key)
{
SearchBstree(Bsroot->Rchild, key);
}
//比根结点的值小,在左子树上查找
else
{
SearchBstree(Bsroot->Lchild, key);
}
}
二叉排序树的删除
设在二叉排序树被删除结点是p,其双亲结点为f。(假设结点p是结点f的左孩子)
情况讨论:
(1) 若p为叶结点,则可直接将其删除:f->lchild = NULL;free(p);
(2) 若p结点只有左子树或只有右子树,则可将p的左子树或右子树直接改为其双亲结点f的左子树:f->lchild = p->lchild;free(p);
(3) 若p既有左子树又有右子树,此时有两种处理方法:
方法1:首先找到p结点在中序序列中的直接前驱结点s,然后将p的左子树改为f的左子树,而将p的右子树改为s的右子树:f->lchild = p->lchild;s->rchild = p->rchild;free(p);
方法2:首先找到p结点在中序序列中的直接前驱结点s,然后用s结点的值替代p结点的值,再将s结点删除,原s结点的左子树改为s的双亲结点q的右子树:p->data = s->data;q->rchild = s->lchild;free(s);
程序清单:
//删除(p为待删除结点,p可能是叶子结点,可能只有左子树或右子树,或者左右子树都有)
BstNode* DeleteBstree(BsTree Bsroot, int key)
{
BstNode *p = Bsroot;
BstNode *f = NULL; //f是p的父结点
BstNode *q, *s; //q是s的父结点,s是q的直接前驱
//不断查找直到找到目标结点,直接删除
while (p != NULL)
{
if (key == p->key)
{
break;
}
f = p; //f记录p的父结点位置
if (key < p->key) //待删除的结点<根结点值,继续在左子树上查找
{
p = p->Lchild;
}
else if (key>p->key) //待删除的结点>根结点值,继续在右子树上查找
{
p = p->Rchild;
}
}
//没有查找到,返回原二叉树
if (p == NULL)
{
return Bsroot;
}
//p没有左孩子(将p的右孩子置为f的左孩子或者右孩子,然后直接删除p)
if (p->Lchild == NULL)
{
if (f == NULL) //p没有父结点,即p为二叉树根结点
{
p = p->Rchild;
}
else if (f->Lchild == p)//p是f的左孩子
{
f->Lchild = p->Rchild; //将p的右孩子置为f的左孩子
}
else if (f->Rchild == p)//p是f的右孩子
{
f->Rchild = p->Rchild; //将p的右孩子置为f的右孩子
}
free(p); //删除p
p = NULL;
}
else //p有左孩子
{
q = p;
s = p->Lchild;
while (s->Rchild)//在p的左子树上查找最右边的结点,即为中序序列中p的直接前驱
{
q = s; //q记录s的父结点位置
s = s->Rchild;
}
if (q == p)//待删除的结点是它直接前驱的父结点
{
q->Lchild = s->Lchild;
}
else
{
q->Rchild = s->Lchild;
}
p->key = s->key; //用s的值覆盖掉待删除结点的值
free(s);
}
return Bsroot;
}

763

被折叠的 条评论
为什么被折叠?



