数据结构C++树与二叉树
- 格式:doc
- 大小:206.50 KB
- 文档页数:14
题目:二叉排序树的实现1 内容和要求1)编程实现二叉排序树,包括生成、插入,删除;2)对二叉排序树进展先根、中根、和后根非递归遍历;3)每次对树的修改操作和遍历操作的显示结果都需要在屏幕上用树的形状表示出来。
4)分别用二叉排序树和数组去存储一个班(50 人以上)的成员信息(至少包括学号、姓名、成绩3 项),比照查找效率,并说明在什么情况下二叉排序树效率高,为什么?2 解决方案和关键代码2.1 解决方案:先实现二叉排序树的生成、插入、删除,编写DisplayBST函数把遍历结果用树的形状表示出来。
前中后根遍历需要用到栈的数据构造,分模块编写栈与遍历代码。
要求比照二叉排序树和数组的查找效率,首先建立一个数组存储一个班的成员信息,分别用二叉树和数组查找,利用clock〔〕函数记录查找时间来比照查找效率。
2.2关键代码树的根本构造定义及根本函数typedef struct{KeyType key;} ElemType;typedef struct BiTNode//定义链表{ElemType data;struct BiTNode *lchild, *rchild;}BiTNode, *BiTree, *SElemType;//销毁树int DestroyBiTree(BiTree &T){if (T != NULL)free(T);return 0;}//清空树int ClearBiTree(BiTree &T){if (T != NULL){T->lchild = NULL;T->rchild = NULL;T = NULL;}return 0;}//查找关键字,指针p返回int SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p) {if (!T){p = f;return FALSE;}else if EQ(key, T->data.key){p = T;return TRUE;}else if LT(key, T->data.key)return SearchBST(T->lchild, key, T, p);elsereturn SearchBST(T->rchild, key, T, p);}二叉树的生成、插入,删除生成void CreateBST(BiTree &BT, BiTree p){int i;ElemType k;printf("请输入元素值以创立排序二叉树:\n");scanf_s("%d", &k.key);for (i = 0; k.key != NULL; i++){//判断是否重复if (!SearchBST(BT, k.key, NULL, p)){InsertBST(BT, k);scanf_s("%d", &k.key);}else{printf("输入数据重复!\n");return;}}}插入int InsertBST(BiTree &T, ElemType e){BiTree s, p;if (!SearchBST(T, e.key, NULL, p)){s = (BiTree)malloc(sizeof(BiTNode));s->data = e;s->lchild = s->rchild = NULL;if (!p)T = s;else if LT(e.key, p->data.key)p->lchild = s;elsep->rchild = s;return TRUE;}else return FALSE;}删除//某个节点元素的删除int DeleteEle(BiTree &p){BiTree q, s;if (!p->rchild) //右子树为空{q = p;p = p->lchild;free(q);}else if (!p->lchild) //左子树为空{q = p;p = p->rchild;free(q);}else{q = p;s = p->lchild;while (s->rchild){q = s;s = s->rchild;}p->data = s->data;if (q != p)q->rchild = s->lchild;elseq->lchild = s->lchild;delete s;}return TRUE;}//整棵树的删除int DeleteBST(BiTree &T, KeyType key) //实现二叉排序树的删除操作{if (!T){return FALSE;}else{if (EQ(key, T->data.key)) //是否相等return DeleteEle(T);else if (LT(key, T->data.key)) //是否小于return DeleteBST(T->lchild, key);elsereturn DeleteBST(T->rchild, key);}return 0;}二叉树的前中后根遍历栈的定义typedef struct{SElemType *base;SElemType *top;int stacksize;}SqStack;int InitStack(SqStack &S) //构造空栈{S.base = (SElemType*)malloc(STACK_INIT_SIZE *sizeof(SElemType));if (!S.base) exit(OVERFLOW);S.top = S.base;S.stacksize = STACK_INIT_SIZE;return OK;}//InitStackint Push(SqStack &S, SElemType e) //插入元素e为新栈顶{if (S.top - S.base >= S.stacksize){S.base = (SElemType*)realloc(S.base, (S.stacksize + STACKINCREMENT)*sizeof(SElemType));if (!S.base) exit(OVERFLOW);S.top = S.base + S.stacksize;S.stacksize += STACKINCREMENT;}*S.top++ = e;return OK;}//Pushint Pop(SqStack &S, SElemType &e) //删除栈顶,应用e返回其值{if (S.top == S.base) return ERROR;e = *--S.top;return OK;}//Popint StackEmpty(SqStack S) //判断是否为空栈{if (S.base == S.top) return TRUE;return FALSE;}先根遍历int PreOrderTraverse(BiTree T, int(*Visit)(ElemType e)) {SqStack S;BiTree p;InitStack(S);p = T;while (p || !StackEmpty(S)){if (p){Push(S, p);if (!Visit(p->data)) return ERROR;p = p->lchild;}else{Pop(S, p);p = p->rchild;}}return OK;}中根遍历int InOrderTraverse(BiTree T, int(*Visit)(ElemType e)) {SqStack S;BiTree p;InitStack(S);p = T;while (p || !StackEmpty(S)){if (p){Push(S, p);p = p->lchild;}else{Pop(S, p);if (!Visit(p->data)) return ERROR;p = p->rchild;}}return OK;}后根遍历int PostOrderTraverse(BiTree T, int(*Visit)(ElemType e)) {SqStack S, SS;BiTree p;InitStack(S);InitStack(SS);p = T;while (p || !StackEmpty(S)){if (p){Push(S, p);Push(SS, p);p = p->rchild;}else{if (!StackEmpty(S)){Pop(S, p);p = p->lchild;}}}while (!StackEmpty(SS)){Pop(SS, p);if (!Visit(p->data)) return ERROR;}return OK;}利用数组存储一个班学生信息ElemType a[] = { 51, "陈继真", 88,82, "黄景元", 89,53, "贾成", 88,44, "呼颜", 90,25, "鲁修德", 88,56, "须成", 88,47, "孙祥", 87, 38, "柏有患", 89, 9, " 革高", 89, 10, "考鬲", 87, 31, "李燧", 86, 12, "夏祥", 89, 53, "余惠", 84, 4, "鲁芝", 90, 75, "黄丙庆", 88, 16, "李应", 89, 87, "杨志", 86, 18, "李逵", 89, 9, "阮小五", 85, 20, "史进", 88, 21, "秦明", 88, 82, "杨雄", 89, 23, "刘唐", 85, 64, "武松", 88, 25, "李俊", 88, 86, "卢俊义", 88, 27, "华荣", 87, 28, "杨胜", 88, 29, "林冲", 89, 70, "李跃", 85, 31, "蓝虎", 90, 32, "宋禄", 84, 73, "鲁智深", 89, 34, "关斌", 90, 55, "龚成", 87, 36, "黄乌", 87, 57, "孔道灵", 87, 38, "张焕", 84, 59, "李信", 88, 30, "徐山", 83, 41, "秦祥", 85, 42, "葛公", 85, 23, "武衍公", 87, 94, "范斌", 83, 45, "黄乌", 60, 67, "叶景昌", 99, 7, "焦龙", 89, 78, "星姚烨", 85, 49, "孙吉", 90, 60, "陈梦庚", 95,};数组查询函数void ArraySearch(ElemType a[], int key, int length){int i;for (i = 0; i <= length; i++){if (key == a[i].key){cout << "学号:" << a[i].key << " 姓名:" << a[i].name << " 成绩:" << a[i].grade << endl;break;}}}二叉树查询函数上文二叉树根本函数中的SearchBST()即为二叉树查询函数。
数据结构(一)目录第1章序论 (1)1.1 什么是数据? (1)1.2 什么是数据元素? (1)1.3 什么是数据结构及种类? (1)1.4 数据的逻辑结构 (1)1.5 数据的物理结构 (1)1.6 算法和算法分析 (1)1.7 算法的五个特性 (1)1.8 算法设计的要求 (2)1.9 算法效率的度量 (2)第2章线性表 (3)2.1 线性表举例 (3)2.2 线性表的存储 (4)2.3 线性表-栈 (4)2.4 队列 (4)2.5 双端队列 (6)第3章树和二叉树 (6)3.1 树 (6)3.1.1 树的基本概念 (6)3.1.2 树的常用存储结构 (6)3.1.3 树的遍历 (7)3.2 二叉树 (7)3.2.1 二叉树的基本概念 (7)3.2.2 二叉树与树的区别 (7)3.2.3 树及森林转到二叉树 (7)3.2.4 二叉树的性质 (8)3.2.5 满二叉树 (8)3.2.6 完全二叉树 (8)3.2.7 完全二叉树的性质 (9)3.2.8 二叉树的四种遍历 (9)3.2.9 二叉排序树 (10)3.2.10 平衡二叉树 (11)3.2.11 m阶B-树 (11)3.2.12 最优二叉树 (11)3.2.13 二叉树的存储结构 (12)3.3 广义表 (13)3.4 矩阵的压缩存储 (14)3.4.1 特殊矩阵 (14)3.4.2 压缩存储 (14)第4章历年真题讲解 (15)4.1 2009年上半年 (15)4.2 2009年下半年 (15)4.3 2010年上半年 (15)4.4 2011年上半年 (16)4.5 2011年下半年 (16)4.6 2012年上半年 (17)4.7 2012年下半年 (17)4.8 2013年上半年 (18)4.9 2013年下半年 (18)4.10 2014年上半年 (18)4.11 2014年下半年 (19)4.12 2015年上半年 (19)4.13 2015年下半年 (19)4.14 2016年上半年 (20)第1章序论什么是数据?所有能输入到计算机中并能够被计算机程序处理的符号的总称,它是计算机程序加工的原料。
计算机专业基础综合数据结构(树和二叉树)历年真题试卷汇编1(总分:86.00,做题时间:90分钟)一、单项选择题(总题数:27,分数:54.00)1.一棵完全二叉树上有1001个结点,其中叶子结点的个数是( )。
【西安交通大学1996三、2(3分)】(分数:2.00)A.250B.500C.254D.505E.以上答案都不对2.一棵124个叶结点的完全二叉树,最多有( )个结点。
【中国科学技术大学1995十四、3(2分)】(分数:2.00)A.247B.248C.249D.250E.2513.已知一棵完全二叉树中共有626个结点,叶子结点的个数应为( )。
【上海交通大学2005四、6(2分)】(分数:2.00)A.3 11B.3 12C.3 13D.3 14E.其他4.具有300个结点的二叉树,其高度至少应为( )。
【北京理工大学2006五、8(1分)】(分数:2.00)A.6B.7C.8D.95.当结点数目一定时,具有最小深度的二叉树是( )。
【北京航空航天大学2005】(分数:2.00)A.满二叉树B.完全二叉树C.线索二叉树D.二叉排序树6.二叉树的第I层上最多含有的结点数为( )。
【中山大学1998二、7(2分)】【北京理工大学2001六、5(2分)】(分数:2.00)A.2 IB.2 I-1一1C.2 I-1D.2 I一17.从树根(第0层)起,自上到下,逐层从左到右给二叉树的所有结点从1开始编号,则完全二叉树的第h 层的从左到右第k个结点的编号为( )。
【电子科技大学2005一、6(1分)】(分数:2.00)A.2 h +h-1B.2 h一k+1C.2 h +k+1D.2 h一k-18.下列判断中,( )是正确的。
【华南理工大学2006一、2(2分)】(分数:2.00)A.深度为k的二叉树最多有2 k -1个结点(k≥1),最少有k个结点B.二叉树中不存在度大于2的结点C.对二叉树遍历是指先序、中序或后序遍历中的一种D.构造线索二叉树是为能方便找到每个结点的双亲9.一个具有1025个结点的二叉树的高h为( )。
1、树最适合用来表示()。
A.元素之间无联系的数据B.元素之间具有层次关系的数据C.无序数据元素D.有序数据元素正确答案:B2、现有一“遗传”关系,设x是y的父亲,则x可以把他的属性遗传给y。
表示该遗传关系最适合的数据结构为()。
A.线性表B.树C.数组D.图正确答案:B3、一棵节点个数为n、高度为h的m(m≥3)次树中,其分支数是()。
A.n+hB.h-1C.n-1D.nh正确答案:C4、若一棵3次树中有2个度为3的节点,1个度为2的节点,2个度为1的节点,该树一共有()个节点。
A.11B.5C.8D.10正确答案:A解析: A、对于该3次树,其中有n3=2,n2=1,n1=2,总分支数=总度数=n-1,总度数=1×n1+2×n2+3×n3=10,则n=总度数+1=11。
5、设树T的度为4,其中度为1、2、3、4的节点个数分别为4、2、1、1,则T中的叶子节点个数是()。
A.6B.8C.7D.5正确答案:B解析: B、这里n1=4,n2=2,n3=1,n4=1,度之和=n-1=n1+2n2+3n3+4n4=15,所以n=16,则n0=n-n1-n2-n3-n4=16-8=8。
6、有一棵三次树,其中n3=2,n2=1,n0=6,则该树的节点个数为()。
A.9B.12C.大于等于9的任意整数D.10正确答案:C解析: C、n=n0+n1+n2+n3=6+n1+1+2=9+n1。
7、假设每个节点值为单个字符,而一棵树的后根遍历序列为ABCDEFGHIJ,则其根节点值是()。
A.JB.BC.以上都不对D.A正确答案:A8、一棵度为5、节点个数为n的树采用孩子链存储结构时,其中空指针域的个数是()。
A.4nB.4n-1C.4n+1D.5n正确答案:C解析: C、总指针数=5n,非空总指针数=分支数=n-1,空指针域的个数=5n-(n-1)=4n+1。
9、有一棵三次树,其中n3=2,n2=2,n1=1,该树采用孩子兄弟链存储结构时,则总的指针域数为()。
计算机专业基础综合数据结构(树和二叉树)历年真题试卷汇编1计算机专业基础综合数据结构(树和二叉树)历年真题试卷汇编1(总分:86.00,做题时间:90分钟)一、单项选择题(总题数:27,分数:54.00)1.一棵完全二叉树上有1001个结点,其中叶子结点的个数是( )。
【西安交通大学1996三、2(3分)】A.250B.500C.254D.505E.以上答案都不对√2.一棵124个叶结点的完全二叉树,最多有( )个结点。
【中国科学技术大学1995十四、3(2分)】A.247B.248 √C.249D.250E.2513.已知一棵完全二叉树中共有626个结点,叶子结点的个数应为( )。
【上海交通大学2005四、6(2分)】A.3 11B.3 12C.3 13 √D.3 14E.其他4.具有300个结点的二叉树,其高度至少应为( )。
【北京理工大学2006五、8(1分)】A.6B.7C.8D.9 √5.当结点数目一定时,具有最小深度的二叉树是( )。
【北京航空航天大学2005】A.满二叉树B.完全二叉树√C.线索二叉树D.二叉排序树设结点数目是n,n个结点未必是满二叉树,A错。
C和D明显错误。
6.二叉树的第I层上最多含有的结点数为( )。
【中山大学1998二、7(2分)】【北京理工大学2001六、5(2分)】A.2 IB.2 I-1一1C.2 I-1√D.2 I一17.从树根(第0层)起,自上到下,逐层从左到右给二叉树的所有结点从1开始编号,则完全二叉树的第h 层的从左到右第k个结点的编号为( )。
【电子科技大学2005一、6(1分)】A.2 h +h-1 √B.2 h一k+1C.2 h +k+1D.2 h一k-18.下列判断中,( )是正确的。
【华南理工大学2006一、2(2分)】A.深度为k的二叉树最多有2 k -1个结点(k≥1),最少有k个结点√B.二叉树中不存在度大于2的结点√C.对二叉树遍历是指先序、中序或后序遍历中的一种D.构造线索二叉树是为能方便找到每个结点的双亲9.一个具有1025个结点的二叉树的高h为( )。
二叉树定义[二叉树] 二叉树(binary tree)t 是有限个元素的集合(可以为空)。
当二叉树非空时,其中有一个称为根的元素,余下的元素(如果有的话)被组成2个二叉树,分别称为t的左子树和右子树。
二叉树和树的根本区别是:• 二叉树可以为空,但树不能为空。
• 二叉树中每个元素都恰好有两棵子树(其中一个或两个可能为空)。
而树中每个元素可有若干子树。
• 在二叉树中每个元素的子树都是有序的,也就是说,可以用左、右子树来区别。
而树的子树间是无序的。
像树一样,二叉树也是根节点在顶部。
二叉树左(右)子树中的元素画在根的左(右)下方。
在每个元素和其子节点间有一条边。
二叉树的特性特性1包含n (n> 0 )个元素的二叉树边数为n-1。
证明:二叉树中每个元素(除了根节点) 有且只有一个父节点。
在子节点与父节点间有且只有一条边,因此边数为n-1。
二叉树的高度(h e i g h t)或深度(d e p t h)是指该二叉树的层数。
特性2若二叉树的高度为h,h≥0,则该二叉树最少有h个元素,最多有2h - 1个元素。
证明:因为每一层最少要有1个元素,因此元素数最少为h。
每元素最多有2个子节点,则第i 层节点元素最多为2i - 1个,i > 0。
h= 0时,元素的总数为0,也就是20 - 1。
当h > 0时,元素的总数不会超过.特性3 包含n 个元素的二叉树的高度最大为n,最小为[l o g2 (n+ 1 )]。
证明:因为每层至少有一个元素,因此高度不会超过n。
由特性2,可以得知高度为h 的二叉树最多有2h-1个元素。
因为n≤2h-1,因此h≥log2 (n+ 1 )。
由于h 是整数,所以h≥[l o g2 (n+ 1 )]。
当高度为h 的二叉树恰好有2h - 1个元素时,称其为满二叉树(full binary tree)假设从满二叉树中删除k个元素,其编号为2h -i, 1≤i≤k,所得到的二叉树被称为完全二叉树(complete binary tree)在完全二叉树中,一个元素与其孩子的编号有非常好的对应关系。
其关系在特性4中给出。
特性4 设完全二叉树中一元素的序号为i, 1≤i≤n。
则有以下关系成立:1) 当i = 1时,该元素为二叉树的根。
若i > 1,则该元素父节点的编号为⎣i / 2⎦。
2) 当2i >n时,该元素无左孩子。
否则,其左孩子的编号为2i。
3) 若2i + 1 >n,该元素无右孩子。
否则,其右孩子编号为2i + 1。
证明 :通过对i 进行归纳即可得证。
二叉树描述链表描述二叉树最常用的描述方法是用链表或指针。
每个元素都用一个有两个指针域的节点表示,这两个域为L e f t C h i l d和R i g h t C h i d。
除此两个指针域外,每个节点还有一个d a t a域。
这种定义为二叉树节点提供了三种构造函数。
第一种无参数,初始化时节点的左右孩子域被置为0(即N U L L);第二种有一个参数,可用此参数来初始化数据域,孩子域被置为0;第三种有3个参数,可用来初始化节点的3个域。
二叉树的边可用一个从父节点到子节点的指针来描述。
指针放在父节点的指针域中。
因为包括n 个元素的二叉树恰有n-1条边,因此将有2n-(n-1 ) =n+ 1个指针域没有值,这些域被置为0。
-------------------------------------------------------------------------------------------------------------------------------- //链表二叉树的节点类template <class T>class BinaryTreeNode{friend void Visit ( BinaryTreeNode<T> *);friend void InOrder(BinaryTreeNode<T> *);friend void PreOrder(BinaryTreeNode<T> *);friend void PostOrder(BinaryTreeNode<T> *);friend void LevelOrder(BinaryTreeNode<T> *);// friend int main(void);public :BinaryTreeNode(){LeftChild = RightChild = 0;}BinaryTreeNode(const T& e){data = e;LeftChild = RightChild = 0;}BinaryTreeNode(const T& e, BinaryTreeNode *l,BinaryTreeNode *r){data = e;LeftChild = l;RightChild = r;}private :T data;BinaryTreeNode<T> *LeftChild, //左子树*RightChild; // 右子树} ;--------------------------------------------------------------------------------------------------------------------------------说明:变量(在图中为t) 来保存二叉树的根,用该变量的名称来指称根节点或整个二叉树,因此可以说根节点t 或二叉树t。
从根节点开始,沿着LeftChild 和RightChild 指针域逐层进行搜索,可以访问二叉树t 中的所有节点。
在二叉树中不设置指向父节点的指针一般不会有什么问题,因为在二叉树的大部分函数中并不需要此指针。
若某些应用需要此指针,可在每个节点增加一个指针域。
二叉树常用操作二叉树的常用操作为:• 确定其高度。
• 确定其元素数目。
• 复制。
• 在屏幕或纸上显示二叉树。
• 确定两棵二叉树是否一样。
• 删除整棵树。
• 若为数学表达式树,计算该数学表达式。
• 若为数学表达式树,给出对应的带括号的表达式。
以上所有操作可以通过对二叉树进行遍历来完成。
在二叉树的遍历中,每个元素仅被访问一次。
在访问时执行对该元素的所有操作。
这些操作包括:把该元素显示在屏幕或纸上;计算以该元素为根的子树所表示的数学表达式的值;对二叉树中元素的个数加1;删除表示该元素的节点等。
二叉树遍历有四种遍历二叉树的方法:• 前序遍历。
• 中序遍历。
• 后序遍历。
• 逐层遍历。
前三种遍历方法在程序1- 2,1- 3,1- 4中给出。
假设要遍历的二叉树采用前前面所介绍的链表的方法来描述,并且B i n a n y Tr e e N o d e被定义为类或模板结构。
-------------------------------------------------------------------------------------------------------------------------------- //1-2前序遍历template <class T>void PreOrder(BinaryTreeNode<T> *t){// 对* t进行前序遍历if (t){Visit ( t ) ; // 访问根节点PreOrder ( t -> LeftChild ) ; // 前序遍历左子树PreOrder( t -> RightChild ) ; // 前序遍历右子树}}---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //1-3中序遍历template <class T>void InOrder(BinaryTreeNode<T> *t){// 对* t进行中序遍历if (t){InOrder(t -> LeftChild ) ; // 中序遍历左子树Visit( t ) ; // 访问根节点InOrder ( t -> RightChild ) ; // 中序遍历右子树}}---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //1-4后序遍历template <class T>void PostOrder(BinaryTreeNode<T> *t){// 对* t进行后序遍历if (t){PostOrder ( t -> LeftChild ) ; // 后序遍历左子树PostOrder ( t -> RightChild) ; // 后序遍历右子树Visit( t ) ; // 访问根节点}}-------------------------------------------------------------------------------------------------------------------------------- 说明:在前三种方法中,每个节点的左子树在其右子树之前遍历。
这三种遍历的区别在于对同一个节点在不同时刻进行访问。
在进行前序遍历时,每个节点是在其左右子树被访问之前进行访问的;在中序遍历时,首先访问左子树,然后访问子树的根节点,最后访问右子树。
在后序遍历时,当左右子树均访问完之后才访问子树的根节点。
在逐层遍历过程中,按从顶层到底层的次序访问树中元素,在同一层中,从左到右进行访问。