源码在文章最后面!!!
随着计算机渗入生活,人们开始要求计算机参与处理非数值计算(特点是计算过程相对简单,数据结构相对复杂,数据的组织排列结构从某种意义上决定着非数据计算应用的有效性数据的组织排列结构成为处理和解决数据处理问题的核心),这时候原来的程序设计以程序为中心的设计过程已经无法满足大量的非数值计算。急需一门以复杂数据为中心,研究数据的合理组织形式,并设计出基于合理数据组织结构下的高效程序的科学来指导计算机的发展。数据结构就是在这种环境下诞生的。
而数据结构往往在逻辑层上为程序抽象出算法,并对算法进行优化。最终推出较优的指导性算法,方便后续的具体程序设计。
二叉平衡树算法实现
1.2设计任务:
1)、能够针对给定的输入序列,建立其存储结构。
2)、根据1)的存储结构,实现各种遍历。
3)、对于生成的二叉平衡树,能实现数据的查找、插入、删除。
4)、对生成的树,能输出各种遍历结果。
5)、对生成的树,能求其叶子结点。
6)、对生成的树,能求其树的深度。
7)、对生成的树,能销毁二叉平衡树。
ADT BinaryTree{
数据对象D:
D是具有相同性质的数据元素的集合
数据关系R:
若D = Ø,则 R = Ø ;
若D != Ø,则 R = {H},则H是如下的二元关系:
1.root 唯一;
2,Dj ∩ Dk = Ø;
3.D内数据类型为int;
基本操作P:
1.建立平衡二叉树
前置条件:初始化一个链队列
输入:以中序方式输入要建立的平衡二叉树(输入整型数据)
功能:根据输入数据建立平衡二叉树
后置条件:存在一个平衡二叉树
2.插入节点
前置条件:存在一个平衡二叉树
输入:输入要插入的数据(整型)
功能:插入节点到二叉树中
后置条件:二叉树节点增加
3.删除节点
前置条件:要删除节点存在于平衡二叉树中
输入:输入要插入的数据(整型)
功能:删除平衡二叉树中的节点
后置条件:二叉树中的节点减少
4.查找节点
前置条件:存在一个平衡二叉树
输入:输入要查找的整型数据
功能:在平衡二叉树中查找节点
输出:存在输出,“查找成功”,不存在,输出“不存在此整型数据”
5.遍历平衡二叉树
前置条件:存在一个平衡二叉树
功能:以先序,中序,后序,层次遍历的方法遍历该二叉树
输出:输出各种遍历的结果
6.求叶子结点
前置条件:存在一个平衡二叉树
功能:求出该平衡二叉树的叶子节点
输出:输出该平衡二叉树的叶子节点
7.平衡二叉树的深度
前置条件:存在一个平衡二叉树
功能:求出平衡二叉树的深度
输出:平衡二叉树的深度
8.销毁平衡二叉树
前置条件:存在一个平衡二叉树
功能:销毁一个平衡二叉树
输出:“销毁成功”或者“无法销毁”
后置条件:平衡二叉树被销毁
}ADT BinaryTree
判断树是否为空,若为空则返回false。先访问根节点,若根节点与所查找数据相同则返回true,如果数字大于根节点则采用自身递归访问右子树,否则访问左子树。
插入结点e,若T中存在和e相同关键字的结点,则插入一个数据元素为e的新结点,并返回TRUE,否则返回FALSE。
当被删结点有两个孩子,其前驱结点是左孩子时flag=1,若该结点只有一个孩子,被删结点有两个孩子,则找到其前驱结点并将前驱结点的值赋,删除前驱结点将左子树取代该结点,删除完结点之后,重调结点的平衡因子
判断树是否为空,先打印根节点,采用自身递归调用PreOrderTraverse()访问左子树,然后再采用自身递归访问右子树。
先判断树是否为空,先采用自身递归访问左子树,第二步打印根节点,最后采用自身递归访问右子树。
先判断树是否为空,第一步采用自身递归访问左子树,第二步采用自身递归访问右子树,打印根节点。
先判断树是否为空,第一步将根结点入队,接下来就不断从队伍中去出队一个结点,同时,如果他有左右孩子,就分别将他的左右孩子入队,这就是访问顺序:首先是根结点,然后是他的左右孩子,左右孩子后面是他的左孩子的左右孩子,右孩子的左右孩子。
若树T为空树,则其括号表示为空,若树T只包含一个结点,则其括号表示即为该结点本身,若树T由根结点A和它的m棵子树T1,T2,...,Tm构成,则其括号表示为:A(T1的括号表示,T2的括号表示,... ,Tm的括号表示)
先判断数是否为空,若不为空,则返回0,若不为空,则用递归的方法访问左孩子,找到左孩子的深度,在访问右孩子,找到右孩子的深度,最后返回两者最大值并加一。
先判断树是否为空,若为空,则返回,若不为空,且左右子树也不都为空,则用递归访问左子数跟右子树,最后打印出左子树叶子数跟右子树叶子数。
将二叉树中的每一个结点用free()函数释放, 其具体过程采用递归,将平衡二叉树的根结点的指针T传到销毁函数,如果T结点的左孩子不为空,则将T结点的左子树的根结点进行递归,直到结点的左孩子为空,再判断结点的右孩子是否为空,若不为空则将结点的右子树的根结点进行递归,直到结点的右子树为空,最后将结点的指针赋为空指针。
建立平衡二叉函数: MakeBBSTree();
左(右)旋函数: L_ Rotate(),R_Rotate();
左右平衡函数: LeftBalance(),RightBalance();
插入节点函数: InsertAVL();
删除节点函数: DeleteAVL();
查找节点函数: SearchAVL();
前(中)后序遍历与层次遍历: PreOrderTraverse(), InOrderTraverse(),
PosOrderTraverse(), LevelOrderTraverse_I();
求叶子节点函数:leaves();
求平衡二叉树深度的函数: BBSTreeDepth();
销毁平衡二叉树的函数:DestroyAVL();
总调用关系图
/*链表结构体*/
typedef struct ListNode {
RcdType data;
ListNode *next;
}ListNode, *List;
这是存放输入数据的链表结构体,RcdType data 用于存放链表数据, ListNode *next 定义了一个指针,用于指向下一个节点地址。
/*平衡二叉树结构体*/
typedef struct BBSTNode {
RcdType data;
int bf;
BBSTNode *lchild, *rchild;
}BBSTNode, *BBSTree;
RcdType data 存放二叉树的节点数据,int bf 定义了节点的平衡因子,用来判断二叉树是否平衡,BBSTNode *lchild, *rchild定义平衡二叉树的左子树,右子树。
/*栈结点结构体*/
typedef struct LSNode {
BBSTree data;
struct LSNode *next;
}LSNode, *LStack;
BBSTree data 定义栈节点数据,struct LSNode *next定义了一个next指针,用于指向下一个节点。
/*链队列结构体*/
typedef struct LQNode {
BBSTree elem;
struct LQNode *next;
}LQNode, *QueuePtr;
BBSTree elem 用于定义一个二叉树节点, struct LQNode *next 定义了一个LQNode指针,用于指向下一个节点。
/*队列结点结构体*/
typedef struct {
QueuePtr front;
QueuePtr rear;
}LQueue;
QueuePtr front定义了一个队头指针,用于指向队头元素的前一个元素,QueuePtr rear定义了一个队尾指针,用于指向队尾元素。
(4.2.1)先序遍历流程图
(4.2.2)中序遍历流程图
(4.2.3)后序遍历流程图
(4.2.4)销毁平衡二叉树流程图
(4.2.5)求平衡二叉树叶子节点流程图
(4.2.6)平衡二叉树插入节点流程图
(4.2.7)平衡二叉树删除节点流程图
前中后序时间复杂度:O(n)
层次时间复杂度:O(log(n))
插入时间复杂度:O(log(n))
删除时间复杂度:O(log(n))
查找时间复杂度:O(log(n))
销毁时间复杂度:O(log(n))
深度时间复杂度:O(n)
括号表示法输出时间复杂度:O(n)
右(左)旋时间复杂度:O(1)
第一步选择1.建立一个平衡二叉树,第二步,选择5.遍历平衡二叉树,得出遍历结构,即可确定平衡二叉树是否建立成功。第三步,选择2.插入节点,插入一个平衡树中已存在节点,确定其是否可以重复插入。如若不行,则可继续,选择2.插入节点,插入一个平衡树中不存在的节点。第四步,销毁节点,再遍历一次,查看节点是否销毁成功。第五步,求叶子节点与平衡二叉树深度。第七步,8.销毁平衡二叉树,再遍历,遍历无结果,说明销毁成功。第九步,0.退出程序。
(图5.5.1)退出程序
(图5.5.2) 建立平衡二叉树
(图5.5.3) 插入节点图
(图5.5.4)查找节点图
(图5.5.5) 删除节点
(图5.5.6)遍历平衡二叉树
(图5.5.7) 求平衡二叉树叶子节点与深度
(图5.5.8) 销毁程序
基本的增删改查都已完成,程序运行良好,遍历结果正确,叶子节点求取也正确,而且确实为平衡二叉树,插入后,依旧保持平衡。
课程设计是培养学生综合运用所学知识,发现、提出、分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。学了一个学期的数据结构,现在终于到了实践检验真理的时候了,课程设计让我们深刻地认识到了自己编程方面的许多缺点很不足,同时检验了自己的学习成果。或许是大一的时候贪玩了一些,导致大家在C语言这一块学的不是很好,直接影响了数据结构的课程设计。不过在老师和同学的帮助下,这些问题也都迎刃而解。本次课程设计我们选到的第三个二叉平衡树的实现,我们选择的是用链队列这一方面的知识来解决的,正好利用这次的课程设计又把队列的知识好好地复习了一遍。一开始运行时总是会出现许多错误,有些错在语法,有些错在了粗心,不过错多了之后,再去看错误的代码时,也能够比较快的找出自己错误的地方,这一点是收获挺大的。通过这次课程设计,使我们懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,将结论用于实践,从而提高自己的实际动手能力和独立思考的能力。
[1]陈元春,张亮,王勇编著.实用数据结构基础中国铁道出版社
[2]谭浩强编著.C程序设计.清华大学出版社
C语言代码
#include<stdio.h>
#include<malloc.h>
#define OVERFLOW -1
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define LH 1 //左高
#define EH 0 //等高
#define RH -1 //右高
typedef int RcdType;
typedef int Status;
//存放输入数据的链表结构体
typedef struct ListNode {
RcdType data;
ListNode *next;
}ListNode, *List;
//平衡二叉树结构体
typedef struct BBSTNode {
RcdType data;
int bf;
BBSTNode *lchild, *rchild;
}BBSTNode, *BBSTree;
//栈结点结构体
typedef struct LSNode {
BBSTree data;
struct LSNode *next;
}LSNode, *LStack;
//链队列结构体
typedef struct LQNode {
BBSTree elem;
struct LQNode *next;
}LQNode, *QueuePtr;
//队列结点结构体
typedef struct {
QueuePtr front;
QueuePtr rear;
}LQueue;
//初始化一个链栈
Status InitStack_LS(LStack &S) {
S = NULL;
return OK;
}
//进栈
Status Push_LS(LStack &S, BBSTree e) {
LSNode *t;
t = (LSNode*)malloc(sizeof(LSNode));
if (NULL == t) return OVERFLOW;
t->data = e;
t->next = S;
S = t;
return OK;
}
//出栈
Status Pop_LS(LStack &S, BBSTree &e) {
LSNode *t;
if (S == NULL) return ERROR;
t = S;
e = t->data;
S = S->next;
return OK;
}
//获得栈顶元素
Status GetTop_LS(LStack S, BBSTree &e) {
if (NULL == S) return ERROR;
else {
e = S->data;
return OK;
}
}
//判断栈是否为空
Status StackEmpty_LS(LStack S) {
if (NULL == S) return TRUE;
else return FALSE;
}
//初始化链队列
void InitQueue_LQ(LQueue &Q) {
Q.front = NULL;
Q.rear = NULL;
}
//进队
Status EnQueue_LQ(LQueue &Q, BBSTree e) {
LQNode *p;
p = (LQNode*)malloc(sizeof(LQNode));
if (NULL == p)
return OVERFLOW;
p->elem = e;
p->next = NULL;
if (NULL == Q.front) Q.front = p; //e插入空队列
else Q.rear->next = p; //e插入非空队列
Q.rear = p; //队尾指针指向新的队尾
return OK;
}
//出队
Status DeQueue_LQ(LQueue &Q, BBSTree &e) {
LQNode *p;
if (NULL == Q.front)
return ERROR;
p = Q.front;
e = p->elem;
Q.front = p->next;
if (Q.rear == p) Q.rear = NULL;
free(p);
return OK;
}
//左旋调整
void L_Rotate(BBSTree &p) {
BBSTree rc = p->rchild;
p->rchild = rc->lchild;
rc->lchild = p;
p = rc;
}
//右旋调整
void R_Rotate(BBSTree &p) {
BBSTree lc = p->lchild;
p->lchild = lc->rchild;
lc->rchild = p;
p = lc;
}
//左平衡处理操作
void LeftBalance(BBSTree &T) {
BBSTree lc, rd;
lc = T->lchild;
switch (lc->bf) {
case LH: T->bf = lc->bf = EH; R_Rotate(T);break;//LL
case RH://LR
rd = lc->rchild;
switch (rd->bf) {
case LH:T->bf = RH; lc->bf = EH; break;
case EH:T->bf = lc->bf = EH; break;
case RH:T->bf = EH; lc->bf = LH; break;
}
rd->bf = EH;
L_Rotate(T->lchild);
R_Rotate(T);
break;
case EH:
T->bf = LH;
lc->bf = RH;
R_Rotate(T);
}
}
//右平衡处理操作
void RightBalance(BBSTree &T)
{
BBSTree rd, lc;
rd = T->rchild;
switch (rd->bf) {
case RH: T->bf = rd->bf = EH;//RR
L_Rotate(T);
break;
case LH: lc = rd->lchild;//RL
switch (lc->bf) {
case LH: T->bf = EH; rd->bf = RH; break;
case RH: T->bf = LH; rd->bf = EH; break;
case EH: T->bf = rd->bf = EH; break;
}
lc->bf = EH;
R_Rotate(T->rchild);
L_Rotate(T);
break;
case EH:
T->bf = RH;
rd->bf = LH;
L_Rotate(T);
break;
}
}
//平衡二叉树的深度
int BBSTreeDepth(BBSTree T) {
int ldepth, rdepth;
if (NULL == T)
return 0;
else {
ldepth = BBSTreeDepth(T->lchild);
rdepth = BBSTreeDepth(T->rchild);
return 1 + (ldepth > rdepth ? ldepth : rdepth);
}
}
//平衡二叉树的查找
Status SearchAVL(BBSTree T, RcdType x)
{
if (T == NULL)
return FALSE;
if (x == T->data)
return TRUE;
else if (x > T->data)
return SearchAVL(T->rchild, x);
else
return SearchAVL(T->lchild, x);
}
//平衡二叉树的插入操作
Status InsertAVL(BBSTree &T, RcdType e, Status &taller) {
if (NULL == T) {//T为空,树长高
T = (BBSTree)malloc(sizeof(BBSTNode));
T->data = e;
T->bf = EH;
T->lchild = NULL;
T->rchild = NULL;
taller = TRUE;
}
else if (e == T->data) {//已存在结点,插入失败
taller = FALSE;
return FALSE;
}
else if (e < T->data) {
if (FALSE == InsertAVL(T->lchild, e, taller))
return FALSE;
if (TRUE == taller) {
switch (T->bf) {
case LH: LeftBalance(T); taller = FALSE; break;//原左高,左平衡处理
case EH: T->bf = LH; taller = TRUE; break;//原等高,右变高
case RH: T->bf = EH; taller = FALSE; break;//原右高,变等高
}
}
}
else {
if (FALSE == InsertAVL(T->rchild, e, taller))
return FALSE;
if (TRUE == taller) {
switch (T->bf) {
case LH: T->bf = EH; taller = FALSE; break;//原左高,变等高
case EH: T->bf = RH; taller = TRUE; break;//原等高,变右高
case RH: RightBalance(T); taller = FALSE; break;//原右高,右平衡处理
}
}
}
return TRUE;
}
//平衡二叉树的删除结点
Status DeleteAVL(BBSTree &t, RcdType e, Status &shorter)
{
//当被删结点有两个孩子,其前驱结点是左孩子时flag=1
int flag = 0;
if (t == NULL) {
return FALSE;
}
else if (e == t->data) {
BBSTree q = NULL;
//该结点只有一个孩子,将左子树取代该结点
if (t->lchild == NULL) {
q = t;
t = t->rchild;
free(q);
shorter = TRUE;
}
else if (t->rchild == NULL) {
q = t;
t = t->lchild;
free(q);
shorter = TRUE;
}
//被删结点有两个孩子,则找到其前驱结点并将前驱结点的值赋,删除前驱结点
else {
q = t->lchild;
while (q->rchild)
q = q->rchild;
t->data = q->data;
if (t->lchild->data == q->data)
flag = 1;
DeleteAVL(t->lchild, q->data, shorter);
if (flag == 1) {
BBSTree r = t->rchild;
if (NULL == r)
t->bf = 0;
else {
if (r->bf == EH)
t->bf = -1;
else
RightBalance(t);
}
}
}
}
else if (e < t->data) {
if (!DeleteAVL(t->lchild, e, shorter))
return FALSE;
//删除完结点之后,重调结点的平衡因子
if (shorter && (flag == 0)) {
switch (t->bf) {
case LH:
t->bf = EH;shorter = TRUE;
break;
case EH:
t->bf = RH;shorter = FALSE;
break;
case RH:
//右平衡处理
RightBalance(t);
if (t->rchild->bf == EH)
shorter = FALSE;
else
shorter = TRUE;
break;
}
}
}
else if (e > t->data) {
//右子树中继续查找
if (!DeleteAVL(t->rchild, e, shorter))
return FALSE;
//重调结点的平衡因子
if (shorter && (flag == 0)) {
switch (t->bf) {
case LH:
LeftBalance(t);
if (t->lchild->bf == EH)
shorter = FALSE;
else
shorter = TRUE;
break;
case EH:
t->bf = LH;shorter = FALSE;
break;
case RH:
t->bf = EH;shorter = TRUE;
break;
}
}
if (flag == 1) {
int ldepth = BBSTreeDepth(t->lchild);
int rdepth = BBSTreeDepth(t->rchild);
t->bf = ldepth - rdepth;
}
}
return TRUE;
}
//根据输入的数据建一棵平衡二叉树
void MakeBBSTree(BBSTree &T) {
int a;
Status taller = TRUE;
scanf("%d", &a);
while (a != 0) {
InsertAVL(T, a, taller);
scanf("%d", &a);
}
}
//递归先序遍历
Status PreOrderTraverse(BBSTree T)
{
if (NULL == T) return OK;
printf("%d ", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
//递归中序遍历
Status InOrderTraverse(BBSTree T)
{
if (NULL == T) return OK;
InOrderTraverse(T->lchild);
printf("%d ", T->data);
InOrderTraverse(T->rchild);
}
//递归后序遍历
Status PosOrderTraverse(BBSTree T)
{
if (NULL == T) return OK;
PosOrderTraverse(T->lchild);
PosOrderTraverse(T->rchild);
printf("%d ", T->data);
}
//层次遍历
void LevelOrderTraverse_I(BBSTree &T)
{
if (T == NULL) return;
BBSTree p = T;
LQueue q;
InitQueue_LQ(q);
printf("%d ", p->data);
EnQueue_LQ(q, p);
while (DeQueue_LQ(q, p)) {
if (p->lchild) {
printf("%d ", p->lchild->data);
EnQueue_LQ(q, p->lchild);
}
if (p->rchild) {
printf("%d ", p->rchild->data);
EnQueue_LQ(q, p->rchild);
}
}
}
//括号表示法输出平衡二叉树
void BraNotationPrint(BBSTree T) {
if (T == NULL) {
printf("#");
return;
}
printf("%d", T->data);
if (!T->lchild && !T->rchild)
return;
else {
printf("(");
if (T->lchild)
BraNotationPrint(T->lchild);
else
printf("#");
printf(",");
if (T->rchild)
BraNotationPrint(T->rchild);
else
printf("#");
printf(")");
}
}
//求平衡二叉树的叶子结点
void leaves(BBSTree T)
{
if (T == NULL) return;
if (T->lchild == NULL && T->rchild == NULL)
printf("%d ", T->data);
leaves(T->lchild);
leaves(T->rchild);
}
//销毁平衡二叉树
void DestroyAVL(BBSTree &T)
{
if (T) {
DestroyAVL(T->lchild);
DestroyAVL(T->rchild);
free(T);
T = NULL;
}
}
void menu()
{
printf("****************************\n");
printf("* 1.建立平衡二叉树 *\n");
printf("* 2.插入结点 *\n");
printf("* 3.删除结点 *\n");
printf("* 4.查找结点 *\n");
printf("* 5.遍历平衡二叉树 *\n");
printf("* 6.求叶子结点 *\n");
printf("* 7.平衡二叉树的深度 *\n");
printf("* 8.销毁平衡二叉树 *\n");
printf("* 0.退出程序 *\n");
printf("****************************\n");
}
int main()
{
int select, case2;
BBSTree T = NULL, T1 = NULL, T2 = NULL, T3 = NULL;
Status taller = TRUE;
printf("* 数据结构课程设计二叉平衡树 *\n");
while (1) {
menu();
printf("\n请选择:");
scanf("%d", &select);
switch (select)
{
case 0:
DestroyAVL(T);
DestroyAVL(T1);
DestroyAVL(T2);
return 0;
break;
case 1:
printf("请输入整型数据(0退出)\n");
MakeBBSTree(T);
break;
case 2:
printf("请输入插入的整型数据:");
scanf("%d", &case2);
if (SearchAVL(T, case2))
printf("插入失败\n");
else {
InsertAVL(T, case2, taller);
printf("插入成功\n");
}
break;
case 3:
printf("请输入删除的整型数据:");
scanf("%d", &case2);
if (SearchAVL(T, case2)) {
DeleteAVL(T, case2, taller);
printf("删除成功\n");
}
else
printf("无此数据,删除失败\n");
break;
case 4:
printf("请输入要查找的整型数据:");
scanf("%d", &case2);
if (SearchAVL(T, case2) == 0)
printf("无此整型数据\n");
else
printf("查找成功,存在%d\n", case2);
break;
case 5:
printf("\n前序遍历:");
PreOrderTraverse(T);
printf("\n中序遍历:");
InOrderTraverse(T);
printf("\n后序遍历:");
PosOrderTraverse(T);
printf("\n层次遍历:");
LevelOrderTraverse_I(T);
printf("\n括号表示法打印:");
BraNotationPrint(T);
break;
case 6:printf("\n叶子结点是:"); leaves(T); printf("\n"); break;
case 7:printf("\n树的深度是%d\n", BBSTreeDepth(T)); break;
case 8:
if (T == NULL) {
printf("空树,无法销毁\n");
}
else {
DestroyAVL(T);
if (T == NULL)
printf("销毁成功\n");
}
break;
default:
printf("输入错误,重新输入\n");
break;
}
}
}
文档链接:https://gitee.com/blueyuyu/balanced-binary-tree
大家自行下载哦,求点赞,求关注。
希望能帮到大家!!!