目录
一、基础理论
1、特点:
(1) 若它的左子树不空,则 左子树 上所有结点的值 均小于 它的根结点的值;
(2) 若它的右子树不空,则 右子树 上所有结点的值 均大于 它的根结点的值;
(3) 它的 左、右子树又分别为二叉排序树 。
2、结构:
二叉树
二、查找
(1)从根开始,未找到,则获取空结点地址,返回;
(2)相等则找到,提示,退出;
(3)key < 结点,向左遍历(递归lchild)
(4)key > 结点,向右遍历(递归rchild)
(查找的同时还可以进行定位,最后返回需要查找的位置)
(和二分查找比较相似)
查找结点13:
第一步:访问根结点 8 .
第二步:根据二叉排序树的左子树均比根结点小,右子树均比根结点大的性质, 13 > 8 ,因此值为13的结点可能在根结点 8 的右子树当中,我们查看根结点的右子节点 10 :
第三步:与第二步相似, 13 > 10 ,因此查看结点 10 的右孩子 14 :
第四步:根据二叉排序树的左子树均比根结点小,右子树均比根结点大的性质, 13 < 14 ,因此查看 14 的左孩子 13 ,发现刚好和要查找的值相等:
//查找二叉排序树
void Search_BST(pBiTree* T, int key) //关键字
{
//查找失败(没有值,需要添加)
if (!(*T))
{
p = T;
return;
}
//查找成功
if (key == (*T)->data)
{
printf("查找成功!\n");
success = 1;
return;
}
else if (key < (*T)->data)
Search_BST(&((*T)->lchild), key); //小,往左遍历
else
Search_BST(&((*T)->rchild), key); //大,往右遍历
}
三、插入
先查找,定位到待插入的位置,直接进行插入。
首结点放入根,后面的依次与前面的每一个结点判断,小则放在左边,大则放在右边。
插入全部:
代码
//插入二叉排序树
void Insert_BST(int key) //索引
{
Search_BST(&head, key);
//找到
if (success)
return;
//未找到(创建新结点,容纳)
(*p) = (pBiTree)malloc(sizeof(pBiTree));
(*p)->data = key; //存储
//给左右子树赋空值
(*p)->lchild = NULL;
(*p)->rchild = NULL;
}
四、删除
删除操作与查找和插入操作不同,我们要分以下三种情况进行处理:
1、被删除的结点D是叶子结点
从二叉排序树当中直接删除即可,也不会影响树的结构。
2、被删除的结点D仅有一个孩子
(1)如果只有左孩子,没有右孩子,那么只需要把要删除结点的左孩子链接到要删除结点的父亲节点,然后删除D结点就好了;(覆盖)
(2)如果只有右孩子,没有左孩子,那么只要将要删除结点D的右孩子重接到要删除结点D的父亲结点。(覆盖)
2-1、删除结点14(有左无右)
覆盖。
保存要删除结点 14 的 左孩子 结点 13 到临时变量 temp,并删除结点 14;
将删除结点 14 的父结点 10 的 右孩子 设置为 temp,即结点 13。
2-2、删除结点 10 (有右无左)
覆盖。
保存要删除结点 10 的 右孩子 结点 14 到临时变量 temp,并删除结点 10;
将删除结点 10 的父结点 8 的 右孩子 设置为 temp,即结点 14。
3、被删除结点的左右孩子都存在
用左子树中的最大值或者右子树中的最小值替换顶点。
(对于这种情况就复杂一些了,这一次我们将图变得复杂一点儿,给原来结点 10 增加了一个左孩子结点 9 。)
对于上面的二叉排序树的中序遍历结果如下所示:
以删除顶点8为例:
方法一:以左子树最大结点替换根结点
(1)获取左子树中的最大结点7
(2)将删除结点 8 的值替换为 7
(3)删除根结点左子树当中值最大结点(要考虑好该结点有无左孩子)
方法二:以右子树最小结点替换根结点
(1)查找删除结点 8 的右子树当中值最小的结点,即 9
(2)将删除结点 8 的值替换为 9
(3)删除根结点右子树当中值最小的结点(要考虑好该结点有无右孩子)
代码1:定位到待删除的结点
//删除(定位到删除的结点)
void Delete_BST(pBiTree* p, int key)
{
if (*p) //结点存在
{
if (key == (*p)->data)
Delete(p);
else if (key < (*p)->data)
Delete_BST(&(*p)->lchild, key); //递归左
else
Delete_BST(&(*p)->rchild, key); //递归右
}
}
代码2:单结点删除
//删除结点
void Delete(pBiTree* p)
{
pBiTree s;
//1、左右均为空
if (!(*p)->lchild && !(*p)->rchild)
*p = NULL;
//2、左子树为空
else if (!(*p)->lchild)
*p = (*p)->rchild; //覆盖
//3、右子树为空
else if (!(*p)->rchild)
*p = (*p)->lchild; //覆盖
//4、左右子树均不为空(两个方法:找左子树最大值/找右子树最小值)
//这里选择找左子树最大值
else
{
pBiTree q = (*p);
s = (*p)->lchild; //先定位左子树
while (s->rchild)
{
q = s; //保存上一结点
s = s->rchild; //往后找
}
(*p)->data = s->data; //覆盖
//考虑:存在左结点
p = &q; //定位到上一节点
(*p)->rchild = s->lchild; //重接q右子树
}
}
总代码
//二叉排序树(查找,插入,删除)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define MAXSIZE 20
int data[MAXSIZE];
int length = 0; //数组长度
int success = 0; //记录是否查找成功
//二叉树结构体
typedef struct BiTree
{
int data;
struct BiTree* lchild, * rchild;
}BiTree, * pBiTree, ** p2BiTree;
BiTree* head;
pBiTree* p;
//输入数据
void Input()
{
int Data;
int i = 0;
printf("请输入初始数据:\t");
//输入数据
do
{
scanf("%d", &Data);
data[i++] = Data;
} while (getchar() != '\n');
length = i; //记录数组长度
}
//二叉树初始化
void Init_BiTree()
{
head = NULL;
}
//查找二叉排序树
void Search_BST(pBiTree* T, int key) //关键字
{
success = 0; //初始化,不影响查找结果
//查找失败(没有值,需要添加)
if (!(*T))
{
p = T;
return;
}
//查找成功
if (key == (*T)->data)
{
printf("查找成功!\n");
success = 1;
return;
}
else if (key < (*T)->data)
Search_BST(&((*T)->lchild), key); //小,往左遍历
else
Search_BST(&((*T)->rchild), key); //大,往右遍历
}
//插入
void Insert_BST(int key) //索引
{
Search_BST(&head, key);
//找到
if (success)
return;
//未找到(创建新结点,容纳)
(*p) = (pBiTree)malloc(sizeof(pBiTree));
(*p)->data = key; //存储
//给左右子树赋空值
(*p)->lchild = NULL;
(*p)->rchild = NULL;
}
//删除结点
void Delete(pBiTree* p)
{
pBiTree s;
//1、左右均为空
if (!(*p)->lchild && !(*p)->rchild)
*p = NULL;
//2、左子树为空
else if (!(*p)->lchild)
*p = (*p)->rchild; //覆盖
//3、右子树为空
else if (!(*p)->rchild)
*p = (*p)->lchild; //覆盖
//4、左右子树均不为空(两个方法:找左子树最大值/找右子树最小值)
//这里选择找左子树最大值
else
{
pBiTree q = (*p);
s = (*p)->lchild; //先定位左子树
while (s->rchild)
{
q = s; //保存上一结点
s = s->rchild; //往后找
}
(*p)->data = s->data; //覆盖
//考虑:存在左结点
p = &q; //定位到上一节点
(*p)->rchild = s->lchild; //重接q右子树
}
}
//删除(定位到删除的结点)
void Delete_BST(pBiTree* p, int key)
{
if (*p) //结点存在
{
if (key == (*p)->data)
Delete(p);
else if (key < (*p)->data)
Delete_BST(&(*p)->lchild, key); //递归左
else
Delete_BST(&(*p)->rchild, key); //递归右
}
}
//中序遍历输出
void Inorder_Traverse(pBiTree p)
{
if (p)
{
Inorder_Traverse(p->lchild);
printf("%d ", p->data);
Inorder_Traverse(p->rchild);
}
}
int main()
{
int key;
Input(); //输入
Init_BiTree(); //二叉树初始化
for (int i = 0; i < length; i++)
Insert_BST(data[i]); //插入二叉排序树
//删除
printf("\n请输入需要删除的数据:\t");
scanf("%d", &key);
Delete_BST(&head, key);
//查找
printf("请输入需要查询的数据:\t");
scanf("%d", &key);
Search_BST(&head, key);
//插入
printf("\n请输入需要插入的数据:\t");
scanf("%d", &key);
Insert_BST(key);
//查找
Search_BST(&head, key);
Inorder_Traverse(head); //遍历(中序遍历,从小到大输出)
return 0;
}