二叉排序树
【问题描述】
从键盘读入一组数据,建立二叉排序树并对其进行查找、遍历、格式化打
印等有关操作。
【基本要求】
建立二叉排序树并对其进行查找,包括成功和不成功两种情况,并给出查找长度
【选作内容】
实现二叉排序树的插入、删除操作。
【算法思想】
通过建立二叉排序数,利用指针,以及执行相关操作的功能的函数完成代码,并
且满足题目所给出的要求,如:插入,删除,打印,遍历(前序遍历,中序遍历,
后序遍历),以及查找次数。但是解决问题的途径不止一种,一些还是可以利用
递归的方法来进行。然后就是一级指针和二级指针的使用,以及形参和实参,函
数的调用的使用。
【模块划分】
1. 函数的存储结构
定义一个链表式的二叉排序树,用链表的方式构造结点,存储二叉排序树中
的结点、结点类型和指针类型如下:
#include
#include
#include
typedef struct node
{
int data, d;
struct node *lt, *rt;
}ST;
int times=0;
2. 判断高度
int deep(ST *root)
if(!root)
return -1;
else return root->d;
{
}
3. 四种调节
ST *RR(ST *root)
{
ST *p;
p = root->rt;
root->rt = p->lt;
p->lt = root;
root->d = max(deep(root->lt), deep(root->rt)) + 1;
return p;
}
ST *LR(ST *root)
{
root->lt = RR(root->lt);
root = LL(root);
return root;
}
ST *RL(ST *root)
{
root->rt = LL(root->rt);
root = RR(root);
return root;
}
4. 插入与建立
插入算法
在二叉排序树中插入一个新节点,首先要查找该节点在二叉
排序树中是否已经存在。若二叉排序树中不存在关键字等于 x 的
节点,则插入。
将一个关键字值为 x 的节点 s 插入到二叉排序树中,可以用
下面的方法:
(1)若二叉排序树为空,则关键字为 x 的节点 s 成为二叉排
序树的根
(2)若二叉排序树非空,则将 x 与二叉排序树根进行比较,
如果 x 的值等于根节点关键值,则停止插入;如果 x 的根节点值
小于根节点关键值,则将 x 插入左子树;如果 x 的值大于根节点
关键字的值,则将×插入右子树。在左右两个子树的插入方法相同
//进行插入与建立
ST *insert(int x, ST *root)
{
if(!root)//这里是建立根节点
{
root = (ST *)malloc(sizeof(ST));
root->data = x;
root->d = 0;
root->lt = NULL; root->rt = NULL;
}
else//如果不是根节点的话,需要判断他的位置,这里是根据深度与大小进
行判断的
{
if(x < root->data)
{
root->lt = insert(x, root->lt);
if(deep(root->lt) - deep(root->rt) > 1)
{
if(root->lt->data > x)
root = LL(root);
else
root = LR(root);
}
}
else if(x > root->data)
{
root->rt = insert(x, root->rt);
if(deep(root->rt) - deep(root->lt) > 1)
{
if(root->rt->data < x)
root = RR(root);
else
root = RL(root);
}
}
}
root->d = max(deep(root->rt),deep(root->lt)) + 1;
return root;
}
5. 删除
在二叉排序树中删除节点,首先要确定被删除的节点是否在
二叉排序树中。
若不在,则不做任何操作;否则,假设要删除的节点为 p,
节点 p 的父节点为 r,并假设 p 是 r 的左孩子。根据被删除节点 p
有无孩子,删除部分可做以下 3 中情况讨论:
(1) 若 p 为叶子节点,则可令其父节点 r 的左孩子指针域
为空,直接将其删除。
(2)若 p 节点只有右子树或左子树,则可以将 p 的左子树
或右子树直接改为其双亲节点 r 的左子树。
(3)若 p 既有左子树又有右子树;将节点 s 为 p 的中序前
驱。首先找到 p 的中序前驱节点 s,然后用节点 s 的值代替节点
p 的值,再将节点 s 删除,节点 s 的原左子树改为 s 的双亲节点 q
的右子树。
//删除
ST *DelST(ST *t,int k)
{
ST *p,*f,*s,*q;
p=t;
f=NULL;
while(p)
{
if(p->data==k)
break;
f=p;
if(p->data>k)
p=p->lt;
else
p=p->rt;
}
if(p==NULL)
return t;
if(p->lt==NULL)
{
if(f==NULL)
t=p->rt;
else
if(f->lt==p)
f->rt=p->rt;
else
f->rt=p->lt;
free(p);
}
else
{
q=p;
s=s->lt;
while(s->rt)
{
q=s;
s=s->rt;
}
if(q==p)
q->lt=s->lt;
else
q->rt=s->lt;
p->data=s->data;
free(s);
}
return t;
}
6. 打印
//打印出序列:前序中序后序
void print(ST *root,int x)
{
if(root){
{
if(x==1)
printf("%d
print(root->lt,x);
print(root->rt,x);
",root->data);
}//前序
else if (x==2)
{
print(root->lt,x);
printf("%d
",root->data);
print(root->rt,x);
} //中序
else if(x==3)
{
print(root->lt,x);
print(root->rt,x);
printf("%d
",root->data);
}//后序
else printf("该序列为空。\n");
}
}
7. 查找
(1)若二叉排序树不为空,将根结点的关键字与待查关键字
进行比较,若相等,则查找成功;若根节点关键字大于待查值,
则进入左子树重复次步骤,否则,进入右子树进行此步骤;若在
查找过程中遇到二叉排序树的叶子节点时,还没有找到待查节
点,则查找不成功。
(2)否则,查找失败,返回 null。
//查找操作
ST *Search(int K,ST *bst)
{
ST
*q;
q=bst;
while(q)
{
times++;
if(q->data==K)
return q;
else if (Kdata) q=q->lt;
else q=q->rt;
}
return NULL;
}
8. 主函数
int main()
{
ST *root;
int n, x;
printf("输入元素的个数为:\n");
scanf("%d",&n);
root = NULL;
printf("请输入一列数字:\n");
while(n--)
{
scanf("%d", &x);
root = insert(x, root);
}
printf("前序输出请输入 1;中序请输入 2,后序请输入 3\n");
int p;
scanf("%d",&p);
print(root,p);
printf("\n");
printf("请输入选择插入的数字:\n");
int data;
scanf("%d",&data);
root=insert (data,root);
printf("该树的中序遍历是:\n");
print(root,2);
printf("请输入要查找的数字:\n");
int data1;
scanf("%d",&data1);
ST *lr;
lr=Search(data1,root);
if (lr)
{printf("已找到该数字,查找次数为%d\n",times); printf("该
树的中序遍历是:\n");print(root,2);
}
else printf("未找到");
int data2;
printf("请输入要删除的数字:\n");
scanf("%d",&data2);
root=DelST(root,data2);
printf("该树的中序遍历是:\n");
print(root,2);
return 0;
}
【源程序】
#include
#include
#include
typedef struct node
{
int data, d;
struct node *lt, *rt;
}ST;
int times=0;
//这里是设置一个函数用来比较大小,方便建立二叉排序树
int max(int a, int b)
{
if(a < b) return b;
else return a;
}
//用来判断高度
int deep(ST *root)
{
if(!root)
return -1;
else return root->d;
}
//四种调节方式:rl,lr,rr,ll
ST *LL(ST *root)
{
ST *p;
p = root->lt;
root->lt = p->rt;
p->rt = root;
root->d = max(deep(root->lt), deep(root->rt)) + 1;
return p;
}
ST *RR(ST *root)
{
ST *p;
p = root->rt;
root->rt = p->lt;
p->lt = root;
root->d = max(deep(root->lt), deep(root->rt)) + 1;
return p;
}
ST *LR(ST *root)
{
root->lt = RR(root->lt);
root = LL(root);
return root;
}
ST *RL(ST *root)
{
root->rt = LL(root->rt);
root = RR(root);
return root;
}
//进行插入与建立
ST *insert(int x, ST *root)
{
if(!root)//这里是建立根节点
{
root = (ST *)malloc(sizeof(ST));
root->data = x;
root->d = 0;
root->lt = NULL; root->rt = NULL;
}
else//如果不是根节点的话,需要判断他的位置,这里是根据深度与大小进
行判断的
{
if(x < root->data)
{
root->lt = insert(x, root->lt);