#include <malloc.h>
#include "stdio.h"
#include <string.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
typedef int KeyType;
typedef struct RcdType {
KeyType key;
}RcdType;
typedef struct BBSTNode {
RcdType data;
int height = 0;
struct BBSTNode* lchild, * rchild;
}BBSTNode, * BBSTree;
BBSTree NULLTree = (BBSTree)malloc(sizeof(BBSTNode));
int max(int i, int j) {
return (i > j) ? i : j;
}
Status InitAVL(BBSTree& T) {
T = NULLTree;
return OK;
}
void DestroyBBST(BBSTree& T) {
//采用递归的方法后序遍历平衡二叉树,访问结点时销毁该结点。
if (NULLTree != T) {
DestroyBBST(T->lchild);
DestroyBBST(T->rchild);
free(T);
}
}
void LL_rotate(BBSTree& T) {
BBSTree lc;
lc = T->lchild;
int lclcH = lc->lchild->height;
int lcrcH = lc->rchild->height;
int rcH = T->rchild->height;//先把高度储存起来
T->lchild = lc->rchild;
lc->rchild = T;
T = lc;//完成变换
T->rchild->height = max(lcrcH, rcH) + 1;
T->height = max(lclcH, T->rchild->height) + 1;
NULLTree->height = 0; //完成高度修改
}
void RR_rotate(BBSTree& T) {
BBSTree rc;
rc = T->rchild;
int lcH = T->lchild->height;
int rclcH = rc->lchild->height;
int rcrcH = rc->rchild->height;//先把高度储存起来
T->rchild = rc->lchild;
rc->lchild = T;
T = rc;//完成变换
T->lchild->height = max(lcH, rclcH) + 1;
T->height = max(rcrcH, T->lchild->height) + 1;
NULLTree->height = 0; //完成高度修改
}
void LR_rotate(BBSTree& T) {
RR_rotate(T->lchild);
LL_rotate(T);
}
void RL_rotate(BBSTree& T) {
LL_rotate(T->rchild);
RR_rotate(T);
}
void InsertAVL(BBSTree& T, RcdType e, Status& ok_error) {
//结束:到达叶子,或已有该值结点存在则不插入
//分解:插入的值小于当前结点左递归插入,大于则右递归插入
//组合:在逐层回溯的时候,调整平衡
if (NULLTree == T) {
T = (BBSTree)malloc(sizeof(BBSTNode));
T->data = e;
T->height = 1;
T->lchild = T->rchild = NULLTree;
ok_error = OK;
NULLTree->height = 0;
}
else if (T->data.key == e.key) ok_error = ERROR;
else if (e.key < T->data.key) {
InsertAVL(T->lchild, e, ok_error);
if (T->lchild->height - T->rchild->height == 2) {
if (e.key < T->lchild->data.key) LL_rotate(T);//说明之前是往左插入
else LR_rotate(T);
}
else T->height = max(T->lchild->height, T->rchild->height) + 1;
}
else if (e.key > T->data.key) {
InsertAVL(T->rchild, e, ok_error);
if (T->rchild->height - T->lchild->height == 2) {
if (e.key > T->rchild->data.key) RR_rotate(T);//说明之前是往右插入
else RL_rotate(T);
}
else T->height = max(T->lchild->height, T->rchild->height) + 1;
}
}
void L_rotate(BBSTree& T) {
if (T->lchild->rchild->height > T->lchild->lchild->height) {
LR_rotate(T);
}
else LL_rotate(T);
}
void R_rotate(BBSTree& T) {
if (T->rchild->lchild->height > T->rchild->rchild->height) {
RL_rotate(T);
}
else RR_rotate(T);
}
RcdType find_maxleft(BBSTree lc) {
//用于在当前要删除结点左右子树都不为空且左子树高或一样高,的情况下找到当前要删除结点直接前驱
while (NULLTree != lc->rchild) {
lc = lc->rchild;
}
return lc->data;
}
RcdType find_minright(BBSTree rc) {
//用于在当前要删除结点左右子树都不为空且右子树高,的情况下找到当前要删除结点直接后驱
while (NULLTree != rc->lchild) {
rc = rc->lchild;
}
return rc->data;
}
void DeleteAVL(BBSTree& T, RcdType e, Status& ok_error, Status& can_end) {
//结束:找到要删的结点,或到NULLTree结点
//分解:要删的结点小于当前结点,左递归删除,大于则右递归删除
//组合:从被删结点的“父节点”开始,逐层回溯,检查是否不平衡;若不平衡则调整,到根结点,或“调整后树的高度没有变化”就结束。
if (NULLTree == T) {
ok_error = ERROR;
can_end = TRUE;
}
else if (T->data.key == e.key) {
if (NULLTree == T->rchild) {//叶子结点,和仅右子树为空的情况
BBSTree temp = T;
T = T->lchild;
free(temp);
ok_error = OK;
}
else if (NULLTree == T->lchild) {//仅左子树为空的情况
BBSTree temp = T;
T = T->rchild;
free(temp);
ok_error = OK;
}
else {//左右结点都不为空的情况
if (T->lchild->height >= T->rchild->height) {
RcdType temp_e;
temp_e = find_maxleft(T->lchild);
T->data = temp_e;//仅赋值,属于“假删除”
Status can_end_temp = FALSE;
DeleteAVL(T->lchild, temp_e, ok_error, can_end_temp);
T->height = max(T->lchild->height, T->rchild->height) + 1; //及时调整高度,否则回溯到父节点
}
else {
RcdType temp_e;
temp_e = find_minright(T->rchild);
T->data = temp_e;//仅赋值,属于“假删除”
Status can_end_temp = FALSE;
DeleteAVL(T->rchild, temp_e, ok_error, can_end_temp);
T->height = max(T->lchild->height, T->rchild->height) + 1;//及时调整高度,否则回溯到父节点
}
}
}
else if (e.key < T->data.key) {
DeleteAVL(T->lchild, e, ok_error, can_end);
if (!can_end) {
if (T->rchild->height - T->lchild->height == 2) {
R_rotate(T);
}
else { //如果调整之后当前结点高度没有变化,则不必要向上回溯调整
int old_height = T->height;
T->height = max(T->lchild->height, T->rchild->height) + 1;
can_end = (old_height == T->height) ? TRUE : FALSE;
}
}
}
else {
DeleteAVL(T->rchild, e, ok_error, can_end);
if (!can_end) {
if (T->lchild->height - T->rchild->height == 2) {
L_rotate(T);
}
else { //如果调整之后当前结点高度没有变化,则不必要向上回溯调整
int old_height = T->height;
T->height = max(T->lchild->height, T->rchild->height) + 1;
can_end = (old_height == T->height) ? TRUE : FALSE;
}
}
}
}
BBSTree SearchBBST(BBSTree T, KeyType key) {
//在平衡二叉树中查找某个值
if (NULLTree == T) return NULLTree;
else if (T->data.key == key) return T;
else if (key < T->data.key) return SearchBBST(T->lchild, key);
else return SearchBBST(T->rchild, key);
}
void print(BBSTree T, int space_number)//凹入表打印树结构
{
if (T != NULLTree)
{
print(T-> rchild, space_number + 1);
for (int i = 0; i < space_number; i++) printf(" ");
printf("%d\n", T->data.key);
print(T-> lchild, space_number + 1);
}
}
void CopyTree(BBSTree t1, BBSTree &t) {
//把t1的结点全都插入到t中
if (NULLTree != t1) {
Status temp;
InsertAVL(t, t1->data, temp);
CopyTree(t1->lchild, t);
CopyTree(t1->rchild, t);
}
}
BBSTree MixTree(BBSTree t1, BBSTree t2) {
BBSTree t;
InitAVL(t);
CopyTree(t1, t); CopyTree(t2, t);
return t;
}
void SplitTree(BBSTree t, BBSTree& t1, BBSTree& t2, int key) {
if (NULLTree != t) {
Status temp = ERROR;
if (t->data.key <= key) InsertAVL(t1, t->data, temp);
else InsertAVL(t2, t->data, temp);
SplitTree(t->lchild, t1, t2, key);
SplitTree(t->rchild, t1, t2, key);
}
}
int main()
{
printf(" 平衡二叉树操作的演示\n");
printf("一开始你拥有10棵空树,编号分别为0 1 2 3 4 5 6 7 8 9 名字是t0 t1 t2 t3 t4 t5 t6 t7 t8 t9\n");
printf("本程序有5种操作:1:查找 需要 查找的树的编号/key\n");
printf(" 2:插入 需要 插入的树的编号/一系列要插入的key\n");
printf(" 3:删除 需要 删除的树的编号/一系列要删除的key\n");
printf(" 4:合并 需要 合并的两棵树的编号/存放合并后的树的编号\n");
printf(" 5:分裂 需要 要分裂的树的编号/存放分裂后的两棵树的编号/分裂参照值key\n");
printf("当要插入或删除一系列key时,输入格式为:key(空格)key(空格)key(ctrl+z) 例如:4 5 6 7 8 9(ctrl+z)\n");
printf("当树已存在key,插入失败;当树不存在key, 删除失败\n\n");
printf("ps:运行程序时,请按照要求和提示操作;输入树的编号请在合理范围内\n\n\n\n");
BBSTree t0 = NULL, t1 = NULL, t2 = NULL, t3 = NULL, t4 = NULL, t5 = NULL, t6 = NULL, t7 = NULL, t8 = NULL, t9 = NULL;
BBSTree forest[10] = { t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 };
const char* forest_name[10] = { "t0","t1","t2","t3","t4","t5","t6","t7","t8","t9" };
int do_index;//操作编号
int tree1_number;//要操作的1树序号
int tree2_number;//要操作的2树序号
int tree3_number;//要操作的3树序号
int search_key;//要查找的数据的key值
int split_key;//分裂操作中的关键字
int go_flag = 1;//是否继续程序
char print_y_n;//是否打印
RcdType e; e.key = 0;//负责存储临时的插入值或删除值
Status ok_error = OK;//存储是否插入或删除成功的状态值
Status can_end = FALSE;//存储是否可以中途结束删除的状态值
for (int i = 0; i < 10; i++) InitAVL(forest[i]);
while (go_flag) {
printf("请输入要进行的操作的序号:");
scanf_s("%d", &do_index);
switch (do_index) {
case 1: {
printf("\n请输入要查找的树的编号:");
scanf_s("%d", &tree1_number);
printf("请输入要查找的key值:");
scanf_s("%d", &search_key);
if (NULLTree == SearchBBST(forest[tree1_number], search_key)) {
printf("\n在%s中找不到%d", forest_name[tree1_number], search_key);
}
else printf("\n在%s中找到了%d", forest_name[tree1_number], search_key);
printf("\n要显示树%s吗(y or n):", forest_name[tree1_number]);
getchar();
scanf_s("%c", &print_y_n);
if (print_y_n == 'y') print(forest[tree1_number], 0);
break;
}
case 2: {
printf("\n请输入要插入结点的树的编号:");
scanf_s("%d", &tree1_number);
printf("请输入要插入的key值(多个值之间以空格隔开,以ctrl+z结尾):");
while (scanf_s("%d", &e.key)) {
InsertAVL(forest[tree1_number], e, ok_error);
if (ok_error == OK) printf("在%s中成功插入%d\n", forest_name[tree1_number], e.key);
else printf("在%s中插入%d失败\n", forest_name[tree1_number], e.key);
}
printf("要显示树%s吗(y or n):", forest_name[tree1_number]);
getchar();
scanf_s("%c", &print_y_n);
if (print_y_n == 'y') print(forest[tree1_number], 0);
break;
}
case 3: {
printf("\n请输入要删除结点的树的编号:");
scanf_s("%d", &tree1_number);
printf("请输入要删除的key值(多个值之间以空格隔开,以ctrl+z结尾):");
while (scanf_s("%d", &e.key)) {
DeleteAVL(forest[tree1_number], e, ok_error, can_end);
if (ok_error == OK) printf("在%s中成功删除%d\n", forest_name[tree1_number], e.key);
else printf("在%s中删除%d失败\n", forest_name[tree1_number], e.key);
can_end = FALSE;
}
printf("要显示树%s吗(y or n):", forest_name[tree1_number]);
getchar();
scanf_s("%c", &print_y_n);
if (print_y_n == 'y') print(forest[tree1_number], 0);
break;
}
case 4: {
printf("\n请输入想合并的第一棵树的编号:");
scanf_s("%d", &tree1_number);
print(forest[tree1_number], 0);
printf("\n请输入想合并的第二棵树的编号:");
scanf_s("%d", &tree2_number);
print(forest[tree2_number], 0);
printf("\n你想把合并后的树存放到哪棵树中:");
scanf_s("%d", &tree3_number);
BBSTree t_temp;
t_temp = MixTree(forest[tree1_number], forest[tree2_number]);
DestroyBBST(forest[tree3_number]);
forest[tree3_number] = t_temp;
printf("要显示树%s吗(y or n):", forest_name[tree3_number]);
getchar();
scanf_s("%c", &print_y_n);
if (print_y_n == 'y') print(forest[tree3_number], 0);
break;
}
case 5: {
printf("\n请输入想分裂的树的编号:");
scanf_s("%d", &tree1_number);
print(forest[tree1_number], 0);
printf("\n请输入分裂操作中的关键字:");
scanf_s("%d", &split_key);
printf("请输入存放小于或等于%d的树的编号:", split_key);
scanf_s("%d", &tree2_number);
printf("请输入存放大于%d的树的编号:", split_key);
scanf_s("%d", &tree3_number);
BBSTree t_temp1, t_temp2;
InitAVL(t_temp1); InitAVL(t_temp2);
SplitTree(forest[tree1_number], t_temp1, t_temp2, split_key);
DestroyBBST(forest[tree2_number]); DestroyBBST(forest[tree3_number]);
forest[tree2_number] = t_temp1;
forest[tree3_number] = t_temp2;
printf("要显示树%s吗(y or n):", forest_name[tree2_number]);
getchar();
scanf_s("%c", &print_y_n);
if (print_y_n == 'y') print(forest[tree2_number], 0);
printf("要显示树%s吗(y or n):", forest_name[tree3_number]);
getchar();
scanf_s("%c", &print_y_n);
if (print_y_n == 'y') print(forest[tree3_number], 0);
break;
}
}
printf("想继续这个程序吗(1 or 0):");
scanf_s("%d", &go_flag);
}
for (int i = 0; i < 10; i++) DestroyBBST(forest[i]);
}