二叉排序树(Binary Sort Tree),又称为二叉查找树,它具备以下性质,若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;它的左右子树也分别为二叉排序树。
1、二叉排序树的查找操作
递归查找二叉排序树T中是否存在key,指针f指向T的双亲,其初始调用值为NULL,若查找成功,则指针p指向该数据元素结点,并返回TRUE,否则指针p指向查找路径上访问的最后一个结点并返回FALSE。
2、二叉排序树的删除操作
找到key元素的结点并进入Delete函数删除该结点,删除结点三种情况进行分析:叶子结点;仅有左或右子树结点,左右子树都有结点。在实际操作中,通过递归找到删除的结点p:
- 若右子树为空,只需将该结点的左子树重接上去,该结点删除free;
- 若左子树为空,只需将该结点的右子树重接上去,该结点删除free;
- 若左右子树都不为空,找到删除结点*p的左孩子的最右结点s,将删除结点*p的左孩子的最右结点s的值替代删除结点*p的值,第一种情况是删除结点*p的左孩子有右子树,因为删除结点*p的左孩子的最右结点s的值替代删除结点*p的值,那么s->L替代s结点,所以q->R=s->L;第二种情况是删除结点*p的左孩子没有右子树,q就是*p要删除的结点,所以q->L = s->L,最后free结点s
3、二叉排序树总结
二叉排序树是以链接的方式存储,保持了链接存储结构在执行插入或删除操作时不用移动元素的优点,只要找到合适的插入和删除位置后,仅需修改链接指针即可。插入删除的时间性能比较好。而对于二叉排序树的查找,走的就是从根结点到最后查找的结点的路径,其比较次数等于给定值的结点在二叉排序树的层数,所以树的结构对查找效率影响比较大,因此需要平衡二叉树。
#include<iostream>
using namespace std;
#define TRUE 1
#define FALSE 0
typedef char Elemtype;
//二叉链表结点结构定义
typedef struct Node //结点结构
{
Elemtype data; //结点数据
struct Node* L; //左孩子指针
struct Node* R; //右孩子指针
}Node, * BTree;
//按前序输入二叉树中结点的值,#表示空树,构造二叉链表表示二叉树T
void CreateBTree(BTree* T)
{
Elemtype e;
cin >> e;
if (e == '#')
*T = NULL;
else
{
(*T) = (Node*)malloc(sizeof(Node));
(*T)->data = e;
CreateBTree(&(*T)->L);
CreateBTree(&(*T)->R);
}
}
//二叉排序树查找操作
int SearchBST(BTree T, int key, BTree f, BTree* p) //T为根节点,key为查找数,f指向T的父结点(为了插入时找到父节点方便插入为子节点),p为查找成功后的结点,用*p的原因是传引用改变p的值返回
{
if (T == NULL) //查找不成功,返回的结点p指向最后的叶子结点f
{
*p = f;
return FALSE;
}
else if (key == T->data)
{
*p = T;
return TRUE;
}
else if (key < T->data)
return SearchBST(T->L, key, T, p); //在左子树查找
else
return SearchBST(T->R, key, T, p); //在右子树查找
}
//二叉排序树插入操作
int InsertBST(BTree* T, int key)
{
BTree p, s;
if (SearchBST(*T, key, NULL, &p) == NULL) //查找不成功,插入key结点,用*T的原因是插入结点改变T的整个结果返回
{
s = (Node*)malloc(sizeof(Node));
s->data = key;
s->L = s->R = NULL;
if (p == NULL) //T树为空,创建新根节点
*T = s;
else if (key < p->data) //插入s为左孩子
p->L = s;
else
p->R = s;
return TRUE;
}
else
return FALSE;
}
//找到key元素的结点并进入Delete函数删除该结点
/*
删除结点三种情况进行分析:
叶子结点:
仅有左或右子树结点:
左右子树都有结点:
*/
int Delete(BTree* p)
{
BTree q, s;
//右子树为空,只需将该结点的左子树重接上去,该结点删除free
if ((*p)->R == NULL)
{
q = *p;
*p = (*p)->L;
free(q);
}
//左子树为空,只需将该结点的右子树重接上去,该结点删除free
else if ((*p)->L == NULL)
{
q = *p;
*p = (*p)->R;
free(q);
}
else //左右子树都不为空
{
q = *p;
s = (*p)->L;
while ((s->R) != NULL) //找到删除结点*p的左孩子的最右结点s
{
q = s;
s = s->R;
}
(*p)->data = s->data; //将删除结点*p的左孩子的最右结点s的值替代删除结点*p的值
if (q != *p) //这种情况是删除结点*p的左孩子有右子树,因为删除结点*p的左孩子的最右结点s的值替代删除结点*p的值,那么s->L替代s结点,所以q->R=s->L
{
q->R = s->L;
}
else //这种情况是删除结点*p的左孩子没有右子树,q就是*p要删除的结点,所以q->L = s->L
{
q->L = s->L;
}
free(s); //释放s结点
}
return TRUE;
}
//二叉排序树删除操作
int DeleteBST(BTree* T, int key)
{
if ((*T) == NULL) //不存在key的元素
return FALSE;
else
{
//找到key元素的结点并进入Delete函数删除该结点
if (key == (*T)->data)
return Delete(T);
else if (key < (*T)->data) //如果key小于(*T)->data,从左子树找
return DeleteBST(&(*T)->L, key);
else //如果key大于(*T)->data,从右子树找
return DeleteBST(&(*T)->R, key);
}
}
int main()
{
BTree T;
//输入d##
CreateBTree(&T);
InsertBST(&T, 'b');
cout << T->L->data << endl;
InsertBST(&T, 'e');
InsertBST(&T, 'f');
InsertBST(&T, 'c');
InsertBST(&T, 'a');
DeleteBST(&T, 'b');
cout << T->L->data << endl;
return 0;
}
来源:CSDN
作者:Revendell
链接:https://blog.csdn.net/Revendell/article/details/104360588