课程设计任务书目录1 需求分析 (3)2 概要设计 (4)2.1存储结构设计说明 (4)2.2程序功能图 (4)2.3算法流程图 (5)3 详细设计 (7)3.1程序分析 (7)3.2程序源代码 (7)4 调试分析 (9)5 课程总结 (11)6参考文献 (12)1 需求分析图1-1 二叉树以图1-1所示的二叉树为例设计,建立一个以二叉链表方式存储的二叉树,输入结点信息时按照完全二叉树的结点顺序输入(1为虚结点,0为输入结束)。
由于一棵二叉排序树中序遍历后的序列是递增有序的,因此可利用中序遍历一棵二叉树后的序列是否递增有序来判断是否为二叉排序树。
如图,二叉树的结点输入顺序为77 80 90 50 1 68 88 1 1 34 56 0 (1为虚结点,0为输入结束),中序遍历之后的顺序为50 80 77 34 68 56 90 88 ,由于中序遍历之后的序列不是递增有序的,因此可判断出此二叉树不是二叉排序树。
2 概要设计2.1 存储结构设计说明typedef struct node{int data; //数据域node *lchild,*rchild; //左孩子指针,右孩子指针}Bitree; //结点的结构体定义2.2程序功能图图2-1 程序功能图2.3算法流程图选取部分核心流程图如下:图2-2 主要流程图图2-3 建立二叉树3 详细设计3.1程序分析建立一个以二叉链表方式存储的二叉树,建立二叉树时,按照完全二叉树的结点顺序输入,1表示虚结点,0表示输入结束。
若不是虚结点时,则建立一个新结点,并且将其作为左孩子或右孩子结点连接到它的父结点上(第一个结点无父结点);若是虚结点,则将空结点(NULL)作为左孩子或右孩子结点连接到它的父节点上。
判定二叉树时,中序遍历整棵二叉树,访问根结点时将根结点信息存入一个数组中,以用来比较中序遍历后序列是否为空。
比较数组元素时,从下标为0的数组元素开始比较,先将下标为i=0的a[i]与下标为1的a[i+1]比较,如果a[i]>a[i+1],则结束比较,即该二叉树不是二叉排序树,否则继续比较,直至比较完整个数组元素。
3.2程序源代码#include "stdafx.h" //编写的任何.cpp文件都必须首先包含stdafx.h#include<stdio.h>#include<stdlib.h>#define max 10typedef struct node{int data; //数据域node *lchild,*rchild; //左孩子指针,右孩子指针}Bitree; //结点的结构体定义Bitree *B[max];int temp=0;int Btree[max];Bitree *Creatree(){ //建立二叉树Bitree *T,*S;int ch;int front,rear,sign;sign=0; //结点的序号从0开始编号(按照完全二叉树的顺序标记)front=0; //双亲结点下标初值rear=-1; //自身结点下标初值T=NULL; //初始化树Tprintf("建立二叉树(1表示虚结点,0表示输入结束):\n");scanf("%d",&ch); //按完全二叉树的顺序输入结点while(ch!=0){if(ch!=1) //输入结点不是虚结点{S=(Bitree *)malloc(sizeof(Bitree)); //创建新结点SS->data=ch; //将输入的数据保存到S中S->lchild=S->rchild=NULL; //将S的左右子树为空rear++; //结点下标加1B[rear]=S; //将S保存到数组B中,即从下标为0开始存储if(rear==front) //双亲结点下标与本身下标相同时,即无双亲结点(只有第一个结点会产生这种情况){T=S;sign++; //结点的序号加1}else //寻找双亲结点{if(sign%2==1)B[front]->lchild=S; //S作为左孩子if(sign%2==0){B[front]->rchild=S;//S作为右孩子front++; //下标加1,即寻找下一个双亲结点}sign++;//结点序号加1}}else{ //输入结点为虚结点if(sign%2==0) //为右子树时{front++;} //双亲结点加1 即下一个双亲结点sign++; //结点序号加1}scanf("%d",&ch);}return T;}void Inorder(Bitree *T) //中序遍历二叉树T,并将每个结点数据存入数组中{if(T!=NULL) //如果树不为空{Inorder(T->lchild);printf("%d\t",T->data);Btree[temp]=T->data;temp++;Inorder(T->rchild);}}int Judgesort_bitree(int Btree[]) //判断中序遍历后的二叉树是否是二叉排序树{int i,sign=1;for(i=0;i<temp-1;i++) //用for循环语句看二叉树是否有序递增{if(Btree[i]>Btree[i+1]) //不是有序递增的{sign=0;break;}}return sign;}void Judgeout(int a)//判断输出将sign赋给a{if(a==1)printf("给定二叉树是二叉排序树!\n");if(a==0)printf("给定二叉树不是二叉排序树!\n");}void main(){Bitree *T;T=Creatree(); //建立二叉树printf("中序遍历:\n");Inorder(T); //中序遍历二叉树printf("\n");Judgeout(Judgesort_bitree(Btree)); //判断是否为排序二叉树}4 调试分析实现了设计的所有要求,选取部分运行示意图。
图4-1 给定二叉树是二叉排序树图4-2 给定二叉树不是二叉排序树结果分析:成功的编译了代码,实验结果令人满意。
先说下判断二叉树数否为排序二叉树的时间复杂度。
二叉树以二叉链表存储,在建立二叉树,中序遍历二叉树和判别时的时间复杂度都为O(n)。
再说下编程遇到的问题,编程的关键是要建立一棵二叉树和判别是否为排序二叉树。
其中判断时,用到了递归的思想。
调试时也遇到了一些问题,由于对一些头文件的不熟悉,缺少,导致程序无法运行等小错误通过查阅一些资料得到了解决。
再有就是由于程序涉及到指针,因此有时指针随机访问到系统隐藏空间时会出现异常终端,通过改进,异常出现的几率大大降低,可认为程序能近似完美运行。
最后说下算法的优缺点,优点是:由于使用二叉链表存储,结构简单,可以方便的构造任何形状的二叉树,并可以方便的实现二叉树的大多数操作。
缺点是:查找当前结点的双亲结点操作实现起来比较麻烦。
而且存储效率不高,进一步优化的话,可以逐条归类存储。
算法改进的话,可以调整下操作界面,使人机交流更简单,方便用户操作。
5 课程总结数据结构的课程设计终于结束,真的很开心。
经过一个学期的学习,我觉得课设是对于我们数据结构掌握程度的测验与评估。
这两周的课设,从开始的确定命题,到搜集资料,到初步编程,到修改代码,到最终完成代码,这是一个学习的过程,一个升华的过程。
我想课设的意义也是在于此吧。
这个程序由于使用二叉链表存储,结构简单,可以方便的构造任何形状的二叉树,并可以方便的实现二叉树的大多数操作。
但是他也存在不足,查找当前结点的双亲结点操作实现起来比较麻烦。
而且存储效率不高,进一步优化的话,可以逐条归类存储。
调试时也遇到了一些问题,由于对一些头文件的不熟悉,缺少,导致程序无法运行等小错误通过查阅一些资料得到了解决。
再有就是由于程序涉及到指针,因此有时指针随机访问到系统隐藏空间时会出现异常终端,通过改进,异常出现的几率大大降低,可认为程序能近似完美运行。
虽然刚开始很困难,但是只要你愿意做,就一定能做到。
当然课设也有很多的不足,由于刚学完数据结构没多久,因此没有建立一个系统的知识框架,在编程时大体上还是延续C的思路,并没有过多的采用数据结构在算法和效率上进行优化,这是此次最大的不足,最大的遗憾,也将会是今后学习的重点,我会吸取教训,好好地再巩固自己的理论知识。
当然,我能够成功编译出来也不是自己一个人的功劳,离不开同学,老师的帮助和点播。
在此,我要感谢给于过我帮助的指导老师和热心的同学们,谢谢大家,我会继续努力的。
6参考文献[1]严蔚敏,吴伟民著. 数据结构:C语言版. 清华大学出版社,2007[2]谭浩强著. C++面向对象程序设计. 北京:清华大学出版社,2006。