数据结构课程设计之线索二叉树的应用.docx
《数据结构课程设计之线索二叉树的应用.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计之线索二叉树的应用.docx(33页珍藏版)》请在冰点文库上搜索。
##大学
数据结构课程设计报告
题目:
线索二叉树的应用
院(系):
计算机工程学院 学生姓名:
班级:
学号:
起迄日期:
2011.6.16-2011.6.29
指导教师:
日
月
年
签名:
成绩:
指导教师评语:
2010—2011年度第2学期
一、需求分析
1.问题描述:
在这个问题中,要解决的任务是:
实现线索二叉树的建立、插入、删除、恢复线索的
实现.n个结点的二叉链表中含有n+1个空指针域。
利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前趋和后继结点的指针。
加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。
线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
在此次课程设计中,采用的是中序线索二叉树。
2.基本功能
1:
定义数据结构; 2:
建立二叉树函数,返回根指针;3:
中序遍历;
4:
中序线索化算法函数实现;5:
输出线索; 6:
查找数据结点函数;
7:
查找父亲结点函数; 8:
插入结点函数; 9:
删除结点函数。
3.输入输出
原始数据要求输入二叉树的七个结点:
abcdefg,输入的是一个二叉树,这就实现了
二叉树的建立过程。
然后对二叉树进行线索化。
对其进行插入:
在d结点插入结点h;删除:
删除结点f;恢复线索等功能。
**********************************
* *
*课程设计题目:
线索二叉树的运算.*
* *
创建二叉树,请依次输入,@表示虚结点,以#结束:
abcdef@@g
1中序输出二叉树
2进行二叉树线索化
3进行插入操作
4进行删除操作
5输出线索二叉树
0退出请选择:
1
→d→g→b→e→a→f→c
1中序输出二叉树
2进行二叉树线索化
3进行插入操作
4进行删除操作
5输出线索二叉树
0退出请选择:
2
已经实现二叉树的线索化,(可选择'5'查看线索)
二、概要设计
1.设计思路:
建立二叉树(即指在内存中建立二叉树的存储结构),建立一个二叉链表,需按某种顺
序一次输入二叉树中的结点,且输入顺序必须隐含结点间的逻辑结构信息。
对于一般的二叉树,需添加虚结点,使其成为完全二叉树。
关键在于如何将新结点作为左孩子和右孩子连接到它的父结点上。
可以设置一个队列,该队列是一个指针类型的数组,保存已输入的结点地址。
操作:
(1)令队头指针front指向其孩子结点当前输入的建立链接的父结点,队尾指针rear指向当前输入的结点,初始:
front=1,rear=0;
(2)若rear为偶数,则该结点为父结点的左孩子;若rear为奇数,则该结点的右孩子;若父结点和孩子结点为虚结点,则无需链接。
(3)若父结点与其两个孩子结点的链接完毕,则令front=front+1,使front指向下一个等待链接的父结点。
二叉树的中序线索化算法与中序遍历算法类似。
只需要将遍历算法中访问结点的操作具体化为建立正在访问的结点与其非空中序前趋结点间线索。
该算法应附设一个指针pre始终指向刚刚访问过的结点(pre的初值应为NULL),而指针p指示当前正在访问的结点。
结点*pre是结点*p的前趋,而*p是*pre的后继。
结点插入算法:
由线索二叉树的定义易知插入的节点定是个叶子节点,需注意线索的修改,可分为两种情况:
(1):
插入的节点t是右儿子,t的中序后继是其父亲的中序后继,中序前驱是其父亲。
(2):
插入的节点t是左儿子,t的中序前驱是其父亲的中序前驱,中序后继是其父亲。
结点删除算法:
删除的情况与搜索二叉树的删除的类似
(1):
删除的节点p是叶子节点,直接删除,修改其父亲的线索。
(2):
删除的节点p有一个儿子,p有一个左儿子,以p为根的左子树中的具有最大值节点的t中序后继是p的中序后继,中序前驱不变;p有一个右儿子,以p为根的右子中的具有最小值节点t中序前驱是p的中序前驱,中序后继不变。
(3):
删除的节点p有二个儿子,转化为叶子节点或只有一个儿子节点的删除。
2.数据结构设计:
抽象数据类型二叉树的定义如下:
ADTBinaryTree{
数据对象D:
D是具有相同特性的数据元素的集合。
数据关系R:
若D=φ,则R=φ,称BinaryTree为空二叉树;若D=φ,则R={H},H是如下二元关系:
(1)在D中存在唯一的成为根的数据元素root,它在关系H下无前驱;
(2)若D—{root}≠φ,则存在D—{root}=(D1,Dr),且D1∩Dr=φ;
(3)若D1≠φ,则D1中存在惟一的元素X1,∈H,且存在D1上的关系H1∈H;若Dr≠φ,则Dr中存在惟一的元素Xr,∈H,且存在Dr上的关系Hr∈H,H={,,H1,Hr};
(4)(D1,{H})是一颗符合本定义的二叉树,称为根的左子树,(Dr,{Hr})是一颗符合本定义的二叉树,称为根的右子树。
基本操作P:
*CreatTree()
操作结果:
建立二叉树树函数,返回根指针
Inorder(*T)
初始条件:
二叉树已存在,已知其根结点。
操作结果:
中序遍历输出各结点二叉树。
PreThread(*root)
初始条件:
二叉树已存在,已知其根结点。
操作结果:
中序线索化二叉树。
PrintIndex(*t)
初始条件:
二叉树已存在,已知其根结点。
操作结果:
输出线索二叉树的线索。
*SearchChild(*point,findnode)
初始条件:
二叉树已存在,已知其根结点;已知结点的数据。
操作结果:
返回数据对应的结点;若不存在此结点,则返回“空”。
*SearchPre(*point,*child)
初始条件:
二叉树已存在,已知其根结点;已知其孩子结点。
操作结果:
返回child父亲结点;若不存在此结点,则返回“空”。
Insert(*root)
初始条件:
二叉树已存在,已知其根结点。
操作结果:
将要插入的结点插到要插的目标结点之前,并实现它线索化的恢复;若目标结点不存在,则输出“没有找到结点”。
*DeleteNode(*t)
初始条件:
二叉树已存在,已知其根结点。
操作结果:
删除目标结点,,并实现它线索化的恢复;若目标结点不存在,则输出
“没有找到结点”。
3.软件结构设计:
模块(函数名,返回类型,形式参数类型)[调用的函数所对应的序号]1)创建二叉树(CreatTree,void,);2)中序遍历二叉树(Inorder,void,Bithptr*T)3)中序线索化二叉树(PreThread,void,Bithptr*root)
4)输出线索二叉树(PrintIndex,void,Bithptr*t)
5)查找数据结点(SearchChild,Bithptr,Bithptr*point\charfindnode)
6)查找父亲结点(SearchPre,Bithptr,Bithptr*point\Bithptr*child)
7)插入结点(Insert,void,Bithptr*root)[5]
8)删除结点(DeleteNode,Bithptr,Bithptr*t)[5,6]
9)主程序模块(main,void,)[1,2,3,4,7,8]
三、详细设计
1.结点类型
typedefstructnode
{
intltag,rtag;
structnode*lchild,*rchild;chardata;
}Bithptr; //结点
2.二叉树的实现
void*CreatTree()
//建立二叉树
voidInorder(Bithptr*T)
//中序遍历二叉树
3.线索二叉树的实现
voidPreThread(Bithptr*root)
//中序线索化二叉树voidPrintIndex(Bithptr*t)
//输出线索二叉树
voidInsert(Bithptr*root)
//插入结点
voidDeleteNode(Bithptr*root)
//删除结点
4.全局变量
Bithptr*Q[maxsize];
Bithptr*pre=NULL;
5.主函数
voidmain()
{
Bithptr*T;inti;
T=CreatTree();printf("\n");i=1;
while(i)
{
printf("\t1中序输出二叉树\n");
printf("\t2进行二叉树线索化\n");
printf("\t3进行插入操作\n");
printf("\t4进行删除操作\n");
printf("\t5输出线索二叉树\n");
printf("\t0退出\n");
printf("\t请选择:
");
scanf("%d",&i);
printf("\n");switch(i)
{
case1:
Inorder(T);printf("\n");break;
case2:
PreThread(T);
printf("\t已经实现二叉树的线索化,(可选择'5'查看线索)\n");printf("\n");
break;
case3:
Insert(T);printf("\n");break;
case4:
T=DeleteNode(T);printf("\n");break;case5:
PrintIndex(T);break;
default:
printf("error\n\t请继续选择:
");
}
}
}
Bithptr*CreatTree() //创建二叉树
{
charch;
intfront,rear;
Bithptr*T,*s;
T=NULL;
front=1;rear=0;printf("**********************************\n");printf("* *\n");
printf("*课程设计题目:
线索二叉树的运算.*\n");printf("* *\n");
printf("**********************************\n");
printf("创建二叉树,请依次输入,@表示虚结点,以#结束\n");ch=getchar();
while(ch!
='#')
{
s=NULL;
if(ch!
='@')
{
s=(Bithptr*)malloc(sizeof(Bithptr));s->data=ch;
s->lchild=NULL;s->rchild=NULL;s->ltag=0;
s->rtag=0;
}
rear++;Q[rear]=s;if(rear==1)
T=s;
else
{
if(s!
=NULL&&Q[front]!
=NULL)if(rear%2==0)
Q[front]->lchild=s;
else
Q[front]->rchild=s;
if(rear%2==1)
front++;
}
ch=getchar();
}
returnT;
}
voidInorder(Bithptr*T) //递归中序遍历
{
if(T)
{
if(T->ltag!
=1)
Inorder(T->lchild);printf("→%c",T->data);if(T->rtag!
=1)
Inorder(T->rchild);
}
}
Bithptr*pre=NULL;
voidPreThread(Bithptr*root)
{
Bithptr*p;p=root;if(p)
{
PreThread(p->lchild);if(pre&&pre->rtag==1)pre->rchild=p;
if(p->lchild==NULL)
{
p->ltag=1;
p->lchild=pre;
}
if(p->rchild==NULL)p->rtag=1;
pre=p;
PreThread(p->rchild);
}
}
voidPrintIndex(Bithptr*t) //输出线索二叉树的线索
{
Bithptr*f;f=t;
if(f)
{
if(f->ltag==1&&f->lchild==NULL&&f->rtag==1)printf("[%c]",f->data);
if(f->ltag==1&&f->lchild!
=NULL)
printf("%c→[%c]",f->lchild->data,f->data);
if(f->ltag==1&&f->rchild!
=NULL&&f->rtag==1)
printf("→%c",f->rchild->data);
else
if(f->rchild!
=NULL&&f->rtag==1)
printf("[%c]→%c",f->data,f->rchild->data);
printf("\n");
if(f->ltag!
=1) PrintIndex(f->lchild);if(f->rtag!
=1) PrintIndex(f->rchild);
}
}
Bithptr*SearchChild(Bithptr*point,charfindnode) //查找数据结点
{
Bithptr*point1,*point2;if(point!
=NULL)
{
if(point->data==findnode)returnpoint;
else
if(point->ltag!
=1)
{
point1=SearchChild(point->lchild,findnode);if(point1!
=NULL)
returnpoint1;
}
if(point->rtag!
=1)
{
point2=SearchChild(point->rchild,findnode);if(point2!
=NULL)
returnpoint2;
}
}
else
}
returnNULL;
returnNULL;
Bithptr*SearchPre(Bithptr*point,Bithptr*child) //查找父亲结点
{
Bithptr*point1,*point2;if(point!
=NULL)
{
if((point->ltag!
=1&&point->lchild==child)||(point->rtag!
=1&&point->rchild==child))returnpoint;
else
if(point->ltag!
=1)
{
point1=SearchPre(point->lchild,child);if(point1!
=NULL)
returnpoint1;
}
if(point->rtag!
=1)
{
point2=SearchPre(point->rchild,child);if(point2!
=NULL)
returnpoint2;
}
}
else
}
returnNULL;
returnNULL;
voidInsert(Bithptr*root) //插入结点
{
charch;charc;
Bithptr*p1,*child,*p2;
printf("请输入要插入的结点的信息:
");scanf("%c",&c);
scanf("%c",&c);
p1=(Bithptr*)malloc(sizeof(Bithptr));p1->data=c;
p1->lchild=NULL;p1->rchild=NULL;p1->ltag=0;
p1->rtag=0;
printf("输入查找的结点信息:
");scanf("%c",&ch);
scanf("%c",&ch);child=SearchChild(root,ch);if(child==NULL)
{
}
else
printf("没有找到结点\n");return;
printf("发现结点%c\n",child->data);
if(child->ltag==0)
{
p2=child;child=child->lchild;
while(child->rchild&&child->rtag==0)child=child->rchild;
p1->rchild=child->rchild;p1->rtag=1;
child->rtag=0;
}
else
{
}
child->rchild=p1;p1->lchild=child;p1->ltag=1;
p1->lchild=child->lchild;child->ltag=0;
p1->ltag=1;child->lchild=p1;
p1->rchild=child;p1->rtag=1;
printf("\n\t插入结点操作已经完成,并同时完成了线索化的恢复\n");
}
Bithptr*DeleteNode(Bithptr*t) //删除结点
{
Bithptr*child,*pre,*s,*q;charch;
printf("输入查找的结点信息:
");ch=getchar();
ch=getchar();child=SearchChild(t,ch);if(NULL==child)
{
printf("没有找到结点:
");returnt;
}
if(child!
=t)
{
}
else
pre=SearchPre(t,child);
printf("发现结点%c\n",pre->data);printf("ltag=%d,rtag=%d\n",child->ltag,child->rtag);
if(child->ltag==1&&child->rtag==1)t=NULL;
else
if(child->ltag==1&&child->rtag!
=1)
{
t=child->rchild;
child->rchild->lchild=NULL;free(child);
returnt;
}
else
if(t->ltag!
=1&&t->rtag==1)
{
}
else
t=child->lchild;
child->lchild->rchild=NULL;free(child);
returnt;
if(t->ltag!
=1&&t->rtag!
=1)
{
t=child->lchild;s=child->lchild;
while(s->rchild&&s->rtag!
=1)s=s->rchild;
q=child->rchild;
while(q->lchild&&q->ltag!
=1)q=q->lchild;
s->rchild=child->rchild;s->rtag=0;
q->lchild=s;free(child);returnt;
}
if(child==pre->lchild||child==pre)
{
if(child->ltag==1&&child->rtag==1)
{
}
else
pre->lchild=child->lchild;pre->ltag=1;
if(child->lchild!
=NULL)if(child->lchild->rtag==1)
child->lchild->rchild=pre;free(child);
if(child->ltag!
=1&&child->rtag!
=1)
{
pre->lchild=child->lchild;s=child->lchild;
while(s->rchild)
s=s->rchild;
s->rchild=child->rchild;
}
else
free(child);
if(child->ltag==1&&child->rtag!
=1)
{
pre->lchild=child->rchild;s=child->rchild;
while(s->lchild)
s=s->lchild;
s->lchild=child->lchild;if(child->lchild!
=NULL)
if(child->lchild->rtag==1)child->lchild->rchild=pre;
free(child);
}
else
}
else
{
if(child->ltag!
=1&&child->rtag!
=1)
{
pre->lchild=child->lchild;s=child->rchild;
while(s->lchild&&s->ltag!
=1)s=s->lchild;
q=child->lchild;
while(q->rchild&&q->rtag!
=1)q=q->rchild;
q->rchild=child->rchild;q->rtag=0;
s->lchild=q;free(child);
}
if(child==pre->rchild)
{
if(child->ltag==1&&child->rtag==1)
{
pre->rchild=child->rchild;pre->rtag=1;
if(child->rchild!
=NULL)if(child->rchild->ltag==1)
child->rchild->lchild=pre;free(child);
}
else
{
if(child->ltag!
=1&&child->rtag==1)
}
else
{
}
else
pre->rchild=child->lchild;s=child->lchild;
while(s->rchild)
s=s->rchild;
s->rchild=child->rchild;if(child->rchild!
=NULL)