二叉排序树的多种操作
0x01.二叉排序树概念
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。它可以是一棵空树。
二叉排序树必须满足以下条件:
- 若它的左子树不为空,则左子树上所有结点的值均小于它的根结构的值。
- 若它的右子树不为空,则右子树上所有结点的值均大于它的根结构的值。
- 它的左右子树也分别为二叉排序树。
0x02.二叉排序树的结构
其实就是普通的二叉树结构,只不过对里面的数据有一定的约束。
typedef struct TreeNode
{
int data;
struct TreeNode* Left;
struct TreeNode* Right;
}TreeNode,BinTree;
0x03.二叉排序树的查找操作
//递归实现查找
//指针f指向父结点,初始化为NULL
//查找成功返回true,p指向查找到的结点
//查找失败返回false,p指向最后一个访问的结点
int SearchBST(BinTree BT, int key, BinTree f, BinTree* p)
{
if (!BT)//若找到尽头,一定是查找失败了
{
*p = f;
return false;
}
else if (key == BT->data)//查找成功
{
*p = BT;
return true;
}
else if (key < BT->data)//若key要小于结点数值,则往左子树找
{
return SearchBST(BT->Left, key, BT, p);
}
else//大于结点值,往右子树找
{
return SearchBST(BT->Right, key, BT, p);
}
}
0x04.插入操作
在依靠查找函数的时候:
//当二叉排序树中不存在关键字等于key的元素时,插入k,返回true,否则返回false
int InsertBST(BinTree* BT, int key)
{
BinTree p1, p2;
if (!SearchBST(*BT, key, NULL, &p1))//查找失败
{
p2 = (BinTree)malloc(sizeof(TreeNode));
p2->data = key;
p2->Left = p2->Right = NULL;
if (!p1)//若p1不存在,说明是空树
{
*BT = p2;//将p2插入
}
else if (key < p1->data)//小于插入左树
{
p1->Left = p2;
}
else//大于插入右树
{
p1->Right = p2;
}
return true;
}
else
{
return false;
}
}
在不依赖于查找函数的时候:
//返回头节点
BinTree Insert( BinTree BST, int X )
{
if(!BST)//插入头
{
BinTree p=(BinTree)malloc(sizeof(TreeNode));
p->data=X;
p->Left=p->Right=NULL;
BST=p;
}
else
{
if(X<BST->data)//寻找插入位置,若已存在,则不需要插入操作
{
BST->Left=Insert(BST->Left,X);
}
else
{
BST->Right=Insert(BST->Right,X);
}
}
return BST;
}
0x05.通过数组建立一棵二叉树
void CreateBST()
{
int i, n;
BinTree BT;
printf("请输入数据数:\n");
scanf("%d", &n);
int* a = (int*)malloc(sizeof(int));
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
InsertBST(&BT, a[i]);
}
}
0x06.删除操作
要删除二叉树中的结点,有三种情况:
- 该结点的左子树为空,只需要重接右子树。
- 该结点的右子树为空,只需要重接左子树。
- 该结点左右子树都不为空,需要找到这个要删除的结点的前驱或直接后继,把该前驱,换到该结点处。(因为这个结点替换后,仍满足原来二叉排序树的顺序)
代码:
直接传二级指针改变:
int DeleteBST(BinTree* BT, int key)
{
if (!*BT)//不存在关键字等于key的元素
{
return false;
}
else
{
if (key < (*BT)->data)
{
DeleteBST(&(* BT)->Left,key);
}
else if (key > (*BT)->data)
{
DeleteBST(&(*BT)->Right, key);
}
else//找到,开始删除操作
{
BinTree *p = BT;
BinTree q;
if ((*p)->Left == NULL)//左孩子为空,重接右孩子
{
q = *p;
*p = (*p)->Right;
free(q);
}
else if ((*p)->Right == NULL)//右孩子为空,重接左孩子
{
q = *p;
*p = (*p)->Left;
free(q);
}
else//左右孩子都不为空
{
q = *p;
BinTree s=(*p)->Left;
while (s->Right)//寻找前驱
{
q = s;
s = s->Right;
}
(*p)->data = s->data;
//此时的s是前驱,此时的p是要删除的那个结点,此时的q是s的父结点
//此时若删除s,还需考虑的s的左孩子情况
//若s的父结点等于要删除的结点,说明s就是要删除的那个结点的左孩子,此时就要把s的左孩子接到q的左孩子上
//若不等于,则将s的左孩子接到q的右孩子上
if (q != *p)
{
q->Right = s->Left;
}
else
{
q->Left = s->Right;
}
free(s);
}
}
}
传一级指针,返回删除后的根结点:
BinTree Delete(BinTree BST,int X)
{
BinTree tmp;
if (!BST) puts("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 // 找到需要删除的结点
{
if (BST->Left && BST->Right) // 被删除的结点有左、右子结点
{
BinTree q = BST->Right;
if (!q)
{
tmp = q;
}
else
{
while (q->Left)// 在右子树种找到最小结点填充删除结点
{
q = q->Left;
}
tmp = q;
}
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;
}
}
}
return BST;
}
0x07.最大最小值操作
寻找最小值的结点,并返回该结点:
BinTree FindMin(BinTree BST)
{
if (BST)
{
while (BST->Left)
{
BST = BST->Left;
}
}
return BST;
}
寻找最大值结点,并返回该结点:
BinTree FindMax(BinTree BST)
{
if (BST)
{
while (BST->Right)
{
BST = BST->Right;
}
}
return BST;
}
本章结束。