数据结构-实验4-建立AVL树
- 格式:doc
- 大小:2.26 MB
- 文档页数:32
数据结构树的实验报告数据结构树的实验报告一、引言数据结构是计算机科学中的重要概念,它可以帮助我们组织和管理数据,提高程序的效率和性能。
而树作为一种常见的数据结构,具有广泛的应用。
本实验旨在通过实践操作,深入理解树的基本概念、特性和操作。
二、实验目的1. 掌握树的基本概念和特性;2. 熟悉树的基本操作,如插入、删除、查找等;3. 理解树的遍历算法,包括前序、中序和后序遍历;4. 实现树的基本功能,并验证其正确性和效率。
三、实验过程1. 构建树的数据结构首先,我们需要定义树的数据结构。
树由节点组成,每个节点可以有零个或多个子节点。
我们可以使用面向对象的思想,创建一个节点类和树类。
节点类包含节点值和子节点列表的属性,以及插入、删除子节点等操作的方法。
树类则包含根节点的属性和遍历方法等。
2. 插入和删除节点在树中插入和删除节点是常见的操作。
插入节点时,我们需要找到合适的位置,并将新节点作为子节点添加到相应的位置。
删除节点时,我们需要考虑节点的子节点和兄弟节点的关系,并进行相应的调整。
通过实现这两个操作,我们可以更好地理解树的结构和特性。
3. 查找节点树中的节点可以通过值进行查找。
我们可以使用递归或迭代的方式,在树中进行深度优先或广度优先的搜索。
在查找过程中,我们需要注意节点的存在性和唯一性,以及查找算法的效率。
4. 树的遍历树的遍历是指按照一定的顺序访问树中的所有节点。
常见的遍历方式有前序、中序和后序遍历。
前序遍历先访问根节点,然后递归地访问左子树和右子树;中序遍历先递归地访问左子树,然后访问根节点,最后访问右子树;后序遍历先递归地访问左子树和右子树,最后访问根节点。
通过实现这三种遍历算法,我们可以更好地理解树的结构和遍历过程。
五、实验结果与分析通过实验,我们成功地实现了树的基本功能,并验证了其正确性和效率。
我们可以通过插入和删除节点操作,构建出不同形态的树,并进行查找和遍历操作。
在插入和删除节点时,树的结构会发生相应的变化,但其基本特性仍然保持不变。
数据结构与算法系列研究五——树、⼆叉树、三叉树、平衡排序⼆叉树AVL树、⼆叉树、三叉树、平衡排序⼆叉树AVL⼀、树的定义树是计算机算法最重要的⾮线性结构。
树中每个数据元素⾄多有⼀个直接前驱,但可以有多个直接后继。
树是⼀种以分⽀关系定义的层次结构。
a.树是n(≥0)结点组成的有限集合。
{N.沃恩}(树是n(n≥1)个结点组成的有限集合。
{D.E.Knuth})在任意⼀棵⾮空树中:⑴有且仅有⼀个没有前驱的结点----根(root)。
⑵当n>1时,其余结点有且仅有⼀个直接前驱。
⑶所有结点都可以有0个或多个后继。
b. 树是n(n≥0)个结点组成的有限集合。
在任意⼀棵⾮空树中:⑴有⼀个特定的称为根(root)的结点。
⑵当n>1时,其余结点分为m(m≥0)个互不相交的⼦集T1,T2,…,Tm。
每个集合本⾝⼜是⼀棵树,并且称为根的⼦树(subtree)树的固有特性---递归性。
即⾮空树是由若⼲棵⼦树组成,⽽⼦树⼜可以由若⼲棵更⼩的⼦树组成。
树的基本操作1、InitTree(&T) 初始化2、DestroyTree(&T) 撤消树3、CreatTree(&T,F) 按F的定义⽣成树4、ClearTree(&T) 清除5、TreeEmpty(T) 判树空6、TreeDepth(T) 求树的深度7、Root(T) 返回根结点8、Parent(T,x) 返回结点 x 的双亲9、Child(T,x,i) 返回结点 x 的第i 个孩⼦10、InsertChild(&T,&p,i,x) 把 x 插⼊到 P的第i棵⼦树处11、DeleteChild(&T,&p,i) 删除结点P的第i棵⼦树12、traverse(T) 遍历树的结点:包含⼀个数据元素及若⼲指向⼦树的分⽀。
●结点的度: 结点拥有⼦树的数⽬●叶结点: 度为零的结点●分枝结点: 度⾮零的结点●树的度: 树中各结点度的最⼤值●孩⼦: 树中某个结点的⼦树的根●双亲: 结点的直接前驱●兄弟: 同⼀双亲的孩⼦互称兄弟●祖先: 从根结点到某结点j 路径上的所有结点(不包括指定结点)。
AVL树及其平衡性AVL树是一种自平衡的二叉搜索树,它得名于它的发明者Adelson-Velsky和Landis。
AVL树在插入和删除节点时会通过旋转操作来保持树的平衡,以确保树的高度始终保持在一个较小的范围内,从而提高搜索、插入和删除操作的效率。
本文将介绍AVL树的基本概念、特点以及如何保持其平衡性。
一、AVL树的基本概念AVL树是一种二叉搜索树,具有以下特点:1. 每个节点最多有两个子节点,左子节点的值小于父节点的值,右子节点的值大于父节点的值;2. 每个节点都有一个平衡因子(Balance Factor),定义为左子树的高度减去右子树的高度;3. AVL树的平衡因子必须为-1、0或1,即任意节点的左右子树高度差不超过1;4. AVL树中任意节点的左子树和右子树都是AVL树。
二、AVL树的平衡性AVL树通过旋转操作来保持树的平衡,主要包括左旋转、右旋转、左右旋转和右左旋转四种操作。
在插入或删除节点后,如果AVL树的平衡因子不满足要求,就需要进行相应的旋转操作来调整树的结构,以保持平衡性。
1. 左旋转(LL旋转)当某个节点的平衡因子为2,且其左子树的平衡因子为1或0时,需要进行左旋转操作。
左旋转是将当前节点向左旋转,使其右子节点成为新的根节点,原根节点成为新根节点的左子节点,新根节点的左子节点成为原根节点的右子节点。
2. 右旋转(RR旋转)当某个节点的平衡因子为-2,且其右子树的平衡因子为-1或0时,需要进行右旋转操作。
右旋转是将当前节点向右旋转,使其左子节点成为新的根节点,原根节点成为新根节点的右子节点,新根节点的右子节点成为原根节点的左子节点。
3. 左右旋转(LR旋转)当某个节点的平衡因子为2,且其左子树的平衡因子为-1时,需要进行左右旋转操作。
左右旋转是先对当前节点的左子节点进行右旋转,然后再对当前节点进行左旋转。
4. 右左旋转(RL旋转)当某个节点的平衡因子为-2,且其右子树的平衡因子为1时,需要进行右左旋转操作。
数据结构二叉树的实验报告数据结构二叉树的实验报告一、引言数据结构是计算机科学中非常重要的一个领域,它研究如何组织和存储数据以便高效地访问和操作。
二叉树是数据结构中常见且重要的一种,它具有良好的灵活性和高效性,被广泛应用于各种领域。
本实验旨在通过实际操作和观察,深入了解二叉树的特性和应用。
二、实验目的1. 理解二叉树的基本概念和特性;2. 掌握二叉树的创建、遍历和查找等基本操作;3. 通过实验验证二叉树的性能和效果。
三、实验过程1. 二叉树的创建在实验中,我们首先需要创建一个二叉树。
通过输入一系列数据,我们可以按照特定的规则构建一棵二叉树。
例如,可以按照从小到大或从大到小的顺序将数据插入到二叉树中,以保证树的有序性。
2. 二叉树的遍历二叉树的遍历是指按照一定的次序访问二叉树中的所有节点。
常见的遍历方式有前序遍历、中序遍历和后序遍历。
前序遍历是先访问根节点,然后再依次遍历左子树和右子树;中序遍历是先遍历左子树,然后访问根节点,最后再遍历右子树;后序遍历是先遍历左子树,然后遍历右子树,最后访问根节点。
3. 二叉树的查找二叉树的查找是指在二叉树中寻找指定的节点。
常见的查找方式有深度优先搜索和广度优先搜索。
深度优先搜索是从根节点开始,沿着左子树一直向下搜索,直到找到目标节点或者到达叶子节点;广度优先搜索是从根节点开始,逐层遍历二叉树,直到找到目标节点或者遍历完所有节点。
四、实验结果通过实验,我们可以观察到二叉树的特性和性能。
在创建二叉树时,如果按照有序的方式插入数据,可以得到一棵平衡二叉树,其查找效率较高。
而如果按照无序的方式插入数据,可能得到一棵不平衡的二叉树,其查找效率较低。
在遍历二叉树时,不同的遍历方式会得到不同的结果。
前序遍历可以用于复制一棵二叉树,中序遍历可以用于对二叉树进行排序,后序遍历可以用于释放二叉树的内存。
在查找二叉树时,深度优先搜索和广度优先搜索各有优劣。
深度优先搜索在空间复杂度上较低,但可能会陷入死循环;广度优先搜索在时间复杂度上较低,但需要较大的空间开销。
avl的引入流程AVL树是一种自平衡二叉树,它通过旋转操作来保持树的平衡,确保任何节点的左子树和右子树的高度差最多为1、在引入AVL树的过程中,需要进行如下几个步骤:1.引入背景:首先,我们需要说明引入AVL树的背景和初衷。
AVL树的概念最早由G.M. Adelson-Velsky和E.M. Landis在1962年提出,他们希望通过这种数据结构来提高和插入操作的平均和最糟糕情况下的时间复杂度。
2.定义:接下来,我们需要定义AVL树的性质和操作。
AVL树是一种二叉树,它具有以下几个特点:-每个节点最多有两个子节点。
-左子树和右子树的高度差最多为1-每个节点的值大于其左子树中所有节点的值,小于其右子树中所有节点的值。
3.插入操作:在向AVL树中插入新节点时,需要进行一系列的旋转操作来保持树的平衡。
插入操作的过程如下:-首先,我们需要将新节点插入到合适的位置,使得树仍然保持二叉树的性质。
-然后,我们从插入点开始向上遍历,检查每个祖先节点是否平衡。
如果祖先节点不平衡,需要进行旋转操作来调整平衡。
-旋转操作分为两种类型:左旋和右旋。
左旋可以平衡右子树比左子树高的情况,右旋可以平衡左子树比右子树高的情况。
通过旋转操作,我们可以将不平衡的子树转换为平衡的子树。
-当所有祖先节点都平衡时,整个插入操作完成。
4.删除操作:在从AVL树中删除节点时,也需要进行一系列的旋转操作来保持树的平衡。
删除操作的过程如下:-首先,我们需要找到要删除的节点。
如果节点不存在,则删除操作完成。
-如果要删除的节点有两个子节点,可以选择用其前驱或后继节点替换它,并将要删除的节点变为其前驱或后继节点。
-删除节点后,我们需要从删除点开始向上遍历,检查每个祖先节点是否平衡。
如果祖先节点不平衡,需要进行旋转操作来调整平衡。
-同样,旋转操作分为左旋和右旋,以调整平衡。
-当所有祖先节点都平衡时,整个删除操作完成。
5.性能分析:最后,我们需要对AVL树的性能进行分析。
数据结构实验报告一、实验目的数据结构是计算机科学中非常重要的一门课程,通过本次实验,旨在加深对常见数据结构(如链表、栈、队列、树、图等)的理解和应用,提高编程能力和解决实际问题的能力。
二、实验环境本次实验使用的编程语言为C++,开发工具为Visual Studio 2019。
操作系统为 Windows 10。
三、实验内容1、链表的实现与操作创建一个单向链表,并实现插入、删除和遍历节点的功能。
对链表进行排序,如冒泡排序或插入排序。
2、栈和队列的应用用栈实现表达式求值,能够处理加、减、乘、除和括号。
利用队列实现银行排队系统的模拟,包括顾客的到达、服务和离开。
3、二叉树的遍历与操作构建一棵二叉树,并实现前序、中序和后序遍历。
进行二叉树的插入、删除节点操作。
4、图的表示与遍历用邻接矩阵和邻接表两种方式表示图。
实现图的深度优先遍历和广度优先遍历。
四、实验步骤及结果1、链表的实现与操作首先,定义了链表节点的结构体:```cppstruct ListNode {int data;ListNode next;ListNode(int x) : data(x), next(NULL) {}};```插入节点的函数:```cppvoid insertNode(ListNode& head, int val) {ListNode newNode = new ListNode(val);head = newNode;} else {ListNode curr = head;while (curr>next!= NULL) {curr = curr>next;}curr>next = newNode;}}```删除节点的函数:```cppvoid deleteNode(ListNode& head, int val) {if (head == NULL) {return;}ListNode temp = head;head = head>next;delete temp;return;}ListNode curr = head;while (curr>next!= NULL && curr>next>data!= val) {curr = curr>next;}if (curr>next!= NULL) {ListNode temp = curr>next;curr>next = curr>next>next;delete temp;}}```遍历链表的函数:```cppvoid traverseList(ListNode head) {ListNode curr = head;while (curr!= NULL) {std::cout << curr>data <<"";curr = curr>next;}std::cout << std::endl;}```对链表进行冒泡排序的函数:```cppvoid bubbleSortList(ListNode& head) {if (head == NULL || head>next == NULL) {return;}bool swapped;ListNode ptr1;ListNode lptr = NULL;do {swapped = false;ptr1 = head;while (ptr1->next!= lptr) {if (ptr1->data > ptr1->next>data) {int temp = ptr1->data;ptr1->data = ptr1->next>data;ptr1->next>data = temp;swapped = true;}ptr1 = ptr1->next;}lptr = ptr1;} while (swapped);}```测试结果:创建了一个包含 5、3、8、1、4 的链表,经过排序后,输出为 1 3 4 5 8 。
树和二叉树的实验报告树和二叉树的实验报告一、引言树和二叉树是计算机科学中常用的数据结构,它们在各种算法和应用中都有广泛的应用。
本实验旨在通过实际操作和观察,深入了解树和二叉树的特性和操作。
二、树的构建与遍历1. 树的概念和特性树是一种非线性的数据结构,由节点和边组成。
每个节点可以有零个或多个子节点,其中一个节点没有父节点的称为根节点。
树的特点包括层次结构、唯一根节点和无环等。
2. 树的构建在本实验中,我们使用Python语言构建了一棵树。
通过定义节点类和树类,我们可以方便地创建树的实例,并添加节点和连接节点之间的边。
3. 树的遍历树的遍历是指按照一定顺序访问树中的所有节点。
常见的遍历方式有前序遍历、中序遍历和后序遍历。
我们在实验中实现了这三种遍历方式,并观察了它们的输出结果。
三、二叉树的实现与应用1. 二叉树的概念和特性二叉树是一种特殊的树,每个节点最多有两个子节点,分别称为左子节点和右子节点。
二叉树的特点包括唯一根节点、每个节点最多有两个子节点和子节点的顺序等。
2. 二叉树的实现我们使用Python语言实现了二叉树的数据结构。
通过定义节点类和二叉树类,我们可以创建二叉树的实例,并实现插入节点、删除节点和查找节点等操作。
3. 二叉树的应用二叉树在实际应用中有很多用途。
例如,二叉搜索树可以用于实现快速查找和排序算法。
AVL树和红黑树等平衡二叉树可以用于高效地插入和删除操作。
我们在实验中实现了这些应用,并通过实际操作验证了它们的效果。
四、实验结果与讨论通过实验,我们成功构建了树和二叉树的数据结构,并实现了它们的基本操作。
通过观察和分析实验结果,我们发现树和二叉树在各种算法和应用中的重要性和灵活性。
树和二叉树的特性使得它们适用于解决各种问题,例如搜索、排序、图算法等。
同时,我们也发现了一些问题和挑战,例如树的平衡性和节点的插入和删除操作等。
这些问题需要进一步的研究和优化。
五、总结本实验通过实际操作和观察,深入了解了树和二叉树的特性和操作。
AVL树数据结构的特点与使用场景AVL树是一种自平衡的二叉搜索树,它在插入或删除节点时会通过旋转操作来保持树的平衡,以确保树的高度始终保持在较小的范围内。
AVL树得名于其发明者Adelson-Velsky和Landis,是一种高度平衡的二叉搜索树,具有快速的查找、插入和删除操作的特点。
在本文中,将介绍AVL树数据结构的特点以及其在实际应用中的使用场景。
一、AVL树的特点1. 自平衡性:AVL树是一种自平衡的二叉搜索树,任何时刻,AVL 树的任意节点的左右子树的高度差不超过1。
当插入或删除节点后,AVL树会通过旋转操作来保持树的平衡,以确保树的高度始终保持在较小的范围内,从而保证了查找、插入和删除操作的时间复杂度为O(log n)。
2. 高度平衡:由于AVL树的自平衡性,使得树的高度相对较低,这样在进行查找操作时,平均查找时间较短,提高了搜索效率。
3. 严格平衡:AVL树是一种严格平衡的二叉搜索树,任何时刻,AVL树的任意节点的左右子树的高度差不超过1,这种严格平衡性保证了AVL树的高度始终保持在较小的范围内,使得其在各种操作下都能保持高效性。
4. 插入和删除操作复杂度低:由于AVL树的自平衡性,插入和删除节点时需要进行旋转操作来保持树的平衡,但这些旋转操作的时间复杂度为O(log n),因此插入和删除操作的复杂度仍然为O(log n),保证了操作的高效性。
二、AVL树的使用场景1. 数据库索引:在数据库系统中,AVL树常被用作索引结构,用于加速数据库的查找操作。
由于AVL树具有快速的查找、插入和删除操作,能够保持树的平衡,因此在数据库索引中得到广泛应用。
2. 编辑器中的自动补全功能:在文本编辑器或代码编辑器中,常常需要实现自动补全功能,AVL树可以用来存储单词或代码片段,通过快速查找实现自动补全功能,提高编辑效率。
3. 路由表:在网络路由中,需要快速查找目标地址对应的路由信息,AVL树可以用来存储路由表,通过快速查找实现高效的路由转发,提高网络传输效率。
平衡二叉树构造方法平衡二叉树对于二叉查找树,尽管查找、插入及删除操作的平均运行时间为O(logn),但是它们的最差运行时间都是O(n),原因在于对树的形状没有限制。
平衡二叉树又称为AVL树,它或者是一棵空树,或者是有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左右子树的深度之差的绝对值不超过1。
二叉树的的平衡因子BF为:该结点的左子树的深度减去它的右子树的深度,则平衡二叉树的所有结点的平衡因子为只可能是:-1、0和1一棵好的平衡二叉树的特征:(1)保证有n个结点的树的高度为O(logn)(2)容易维护,也就是说,在做数据项的插入或删除操作时,为平衡树所做的一些辅助操作时间开销为O(1)一、平衡二叉树的构造在一棵二叉查找树中插入结点后,调整其为平衡二叉树。
若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性。
首先要找出插入新结点后失去平衡的最小子树根结点的指针。
然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。
当失去平衡的最小子树被调整为平衡子树后,原有其他所有不平衡子树无需调整,整个二叉排序树就又成为一棵平衡二叉树(1)插入点位置必须满足二叉查找树的性质,即任意一棵子树的左结点都小于根结点,右结点大于根结点(2)找出插入结点后不平衡的最小二叉树进行调整,如果是整个树不平衡,才进行整个树的调整。
(1)LL型LL型:插入位置为左子树的左结点,进行向右旋转由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1变为2,成为不平衡的最小二叉树根结点。
此时A结点顺时针右旋转,旋转过程中遵循“旋转优先”的规则,A结点替换D结点成为B结点的右子树,D结点成为A结点的左孩子。
(2)RR型RR型:插入位置为右子树的右孩子,进行向左旋转由于在A的右子树C的右子树插入了结点F,A的平衡因子由-1变为-2,成为不平衡的最小二叉树根结点。
此时,A结点逆时针左旋转,遵循“旋转优先”的规则,A结点替换D结点成为C的左子树,D结点成为A的右子树。
原题目:比较二叉树和AVL树的区别。
原题目:比较二叉树和AVL树的区别
二叉树和AVL树是常用的数据结构,它们都是树形结构,但
在某些方面有一些区别。
1. 定义:
- 二叉树:每个节点最多有两个子节点的树结构。
- AVL树:也是一种二叉搜索树,但它具有自平衡特性。
2. 平衡特性:
- 二叉树:二叉树没有保持平衡的要求,所以可能出现不平衡
的情况。
- AVL树:AVL树要求在插入或删除节点后,保持树的平衡状态。
每个节点的左右子树高度差(平衡因子)不超过1。
3. 插入和删除操作的效率:
- 二叉树:在二叉树中插入和删除节点的效率取决于树的形状,可能较低。
- AVL树:由于AVL树要保持平衡,插入和删除节点时需要通过旋转操作来调整树的结构,因此插入和删除的效率可能较低。
4. 查找操作的效率:
- 二叉树:二叉树的查找操作时间复杂度为O(log n),其中n为节点数量。
- AVL树:由于AVL树的平衡特性,它的查找操作时间复杂度也为O(log n)。
5. 空间占用:
- 二叉树:二叉树的空间占用取决于树的形状,没有特定的要求。
- AVL树:由于AVL树需要维护平衡,它可能需要更多的额外空间。
总结:二叉树和AVL树都是树形结构,但AVL树具有自平衡特性。
相比之下,二叉树没有要求保持平衡,所以插入和删除的效率可能较低。
同时,AVL树的插入和删除操作需要通过旋转来实现平衡,因此它的效率可能较低。
但二叉树和AVL树的查找操作时间复杂度都为O(log n),并且都可以用于不同的应用场景。
常见基本数据结构——树,⼆叉树,⼆叉查找树,AVL树常见数据结构——树处理⼤量的数据时,链表的线性时间太慢了,不宜使⽤。
在树的数据结构中,其⼤部分的运⾏时间平均为O(logN)。
并且通过对树结构的修改,我们能够保证它的最坏情形下上述的时间界。
树的定义有很多种⽅式。
定义树的⾃然的⽅式是递归的⽅式。
⼀棵树是⼀些节点的集合,这个集合可以是空集,若⾮空集,则⼀棵树是由根节点r以及0个或多个⾮空⼦树T1,T2,T3,......,Tk组成,这些⼦树中每⼀棵的根都有来⾃根r的⼀条有向的边所连接。
从递归的定义中,我们发现⼀棵树是N个节点和N-1条边组成的,每⼀个节点都有⼀条边连接⽗节点,但是根节点除外。
具有相同⽗亲的节点为兄弟,类似的⽅法可以定义祖⽗和孙⼦的关系。
从节点n1到nk的路径定义为节点n1,n2,...,nk的⼀个序列,并且ni是ni+1的⽗亲。
这个路径的长是路径上的边数,即k-1。
每个节点到⾃⼰有⼀条长为0的路径。
⼀棵树从根到叶⼦节点恰好存在⼀条路径。
对于任意的节点ni,ni的深度为从根到ni的唯⼀路径长。
ni的⾼是从ni到⼀⽚叶⼦的最长路径的长。
因此,所有的树叶的⾼度都是0,⼀棵树的⾼等于它的根节点的⾼。
⼀棵树的深度总是等于它最深叶⼦的深度;该深度等于这棵树的⾼度。
树的实现实现树的⼀种⽅法可以是在每⼀个节点除数据外还要有⼀些指针,使得该节点的每⼀个⼉⼦都有⼀个指针指向它。
但是由于每个节点的⼉⼦树可以变化很⼤⽽且事先不知道,故在各个节点建⽴⼦节点的链接是不可⾏的,这样将会浪费⼤量的空间。
实际的做法很简单:将每个节点的所有⼉⼦都放在树节点的链表中。
下⾯是典型的声明:typedef struct TreeNode *PtrToNodestruct TreeNode{ ElementType Element; PtrToNode FirstChild; PtrToNode NextSibling}下⾯是⼉⼦兄弟表⽰法的图⽰:树的遍历及应⽤⼀个常见的使⽤是操作系统中的⽬录结构。
东北大学信息科学与工程学院数据结构课程设计报告题目学生成绩条形图统计问题课题组长王健课题组成员张颖刘琪张晓雨专业名称计算机科学与技术班级计1307指导教师杨雷2015 年1月课程设计任务书目录1 课题概述 (4)1.1 课题任务 (4)1.2 课题原理 (4)1.3 相关知识 (4)2 需求分析 (5)2.1 课题调研 (5)2.2 用户需求分析 (5)3 方案设计 (6)3.1 总体功能设计 (6)3.2 数据结构设计 (6)3.3 函数原型设计 (6)3.4 主算法设计 (7)3.5 用户界面设计 (9)4 方案实现 (10)4.1 开发环境与工具 (10)4.2 程序设计关键技术 (10)4.3 个人设计实现(按组员分工)4.3.1 刘琪设计实现 (10)4.3.2 张晓雨设计实现 (11)4.3.3 王健设计实现 (13)4.3.4 张颖设计实现 (14)5 测试与调试 (17)5.1 个人测试(按组员分工) (17)5.1.1 刘琪测试 (17)5.1.2 张晓雨测试 (17)5.1.3 王健测试 (17)5.1.4 张颖测试 (17)5.2 组装与系统测试 (17)5.3 系统运行 (19)6 课题总结 (21)6.1 课题评价 (21)6.2 团队协作 (21)6.3 下一步工作 (21)6.4 个人设计小结(按组员分工) (21)6.4.1 刘琪设计小结 (21)6.4.2 张晓雨设计小结 (22)6.4.3 王健设计小结 (22)6.4.4 张颖设计小结 (22)7 附录A 课题任务分工 (23)A-1 课题程序设计分工 (23)A-2 课题报告分工 (24)附录B 课题设计文档(光盘) (25)B-1源程序代码(*.H,*.CPP) (25)B-2工程与可执行文件) (25)附录C 用户操作手册(可选) (25)C.1 运行环境说明 (25)C.2 操作说明 (25)1 课题概述1.1 课题任务设计基于二叉排序树的学生成绩条形图统计程序。
计算机专业基础综合数据结构(集合)历年真题试卷汇编4(总分:70.00,做题时间:90分钟)一、单项选择题(总题数:20,分数:40.00)1.下列二叉排序树中,满足平衡二叉树定义的是( )。
【2009年全国试题4(2分)】(分数:2.00)√解析:2.下列叙述中,不符合m阶B树定义要求的是( )。
【2009年全国试题8(2分)】(分数:2.00)A.根结点最多有m棵子树B.所有叶结点都在同一层上C.各结点内关键字均升序或降序排列D.叶结点之间通过指针链接√解析:解析:一棵m阶的B树的定义如下:或为空树,或为满足下列特性的m叉树: (1)树中每个结点至多有m棵子树; (2)若根结点不是叶子结点,则至少有两棵子树; (3)除根结点之外的所有非终端结点至少有[m/2]棵子树;(4)所有的非终端结点中包含下列信息数据(n,P0,P 0,P 1,K 2,P 2,…,K n,P n ),其中:K i (i=1,…,n)为关键字,且K i i+1(i=1,…,n一1),P i(i=0,…,n)为指向子树根结点的指针,且指针P i-1所指子树中所有结点的关键字均小于K i(i=1,…,n),P n所指子树中所有结点的关键字均大于K n,n(|m/2|—1≤n≤m一1)为关键字的个数; (5)所有叶子结点都出现在同一层次上,并且不带信息(可以看作是外部结点或查找失败的结点,实际上这些结点不存在,指向这些结点的指针为空)。
据此,选择答案D不符合B树定义,D描述的是B+树,B+树的叶结点本身按照关键字的大小,自小而大顺序链接。
3.在下图所示的平衡二叉树中,插入关键字48.舌得到一棵新平衡二叉树。
在新平衡二叉树中,关键字37所在结点的左、右子结点中保存的关键字分别是( )。
【2010年全国试题4(2分)(分数:2.00)A.13、48B.24、48C.24、53 √D.24、90解析:解析:失去平衡的最小子树根结点是24,需做RL型调整。
哈尔滨工业大学计算机科学与技术学院实验报告课程名称:数据结构与算法课程类型:必修实验项目名称:查找结构与排序算法实验题目:建立A VL树目录目录 (2)一、实验目的 (3)二、实验要求及实验环境 (3)1.实验要求: (3)2.实验环境: (3)三、设计思想 (3)1.逻辑设计 (3)(1)平衡查找二叉树 (3)(2)平衡因子 (4)(3)失衡情况与修正操作 (4)2.物理设计 (5)(1)存储结构 (5)(2)建立平衡二叉查找树 (6)(3)插入新结点 (6)(4)删除结点 (11)四、测试结果 (15)五、系统不足与经验体会 (15)六、附录:源代码(带注释) (16)一、实验目的通过实现A VL树的建立、插入与删除,掌握A VL树结构。
二、实验要求及实验环境1.实验要求:要求:1.具有插入(建立)、删除和查找功能2.插入操作应包括四种类型的平衡化处理3.删除操作应包括四种类型的平衡化处理并且包括多次平衡化处理4.能体现操作前后二叉树的形态及其变化2.实验环境:Microsoft Windows7, Code::Blocks 10.05三、设计思想1.逻辑设计(1)平衡查找二叉树平衡二叉树的定义是:平衡二叉树或为空树,或满足下列特征:A若其左子树非空,则左子树上所有结点的关键字值都小于根节点关键字值B若其右子树非空,则右子树上所有结点的关键字值都大于根节点关键字值C根节点的左右子树高度之差的绝对值不超过1D根节点的左子树和右子树仍为A VL树平衡查找二叉树不会退化为线性链表,因此时间复杂度比较稳定。
(2)平衡因子为了更好地实现平衡查找二叉树,引进平衡因子Balanced Factor。
平衡因子的值为一个结点的左子树与右子树的高度之差,对于A VL树中的结点而言,BF只能是-1,0,和1。
当插入或删除操作导致平衡二叉查找树的某个结点的平衡因子偏离正确范围时,就可以及时进行修正操作,以保证二叉树保持平衡。
(3)失衡情况与修正操作从平衡二叉查找树出发,插入或删除某个结点后,二叉树失衡,从最底层结点来看只有四种可能:LL型:新结点插入到根节点的左子树的左子树上导致失衡。
对这种情况,应该顺时针旋转原树并进行相应修改:RR型:新结点插入到根节点的右子树的右子树上导致失衡。
对这种情况,应该顺时针旋转原树并进行相应修改:LR型:新结点插入到根节点的左子树的右子树上导致失衡。
对这种情况,应该先逆时针再顺时针旋转原树并进行相应修改:RL型:新结点插入到根节点的右子树的左子树上导致失衡。
对这种情况,应该先顺时针再逆时针旋转原树并进行相应修改:对于删除操作,由于被删除结点可能位于树的内部,需要进一步考虑更多操作。
2.物理设计(1)存储结构基础结构:平衡树结点组合结构:平衡树(2)建立平衡二叉查找树实现操作的主函数为:此函数只是接收参数。
其具体实现依赖于将要提及的插入函数。
(3)插入新结点插入的主函数为:根据插入元素的大小决定插入哪株子树。
如果插入成功,如树增高,根据增长的不同程度决定是否、如何旋转。
插入的过程中会调用平衡树的调整函数。
其中旋转操作的实现函数为:分别实现对特定结点的“旋转”操作。
而要在插入过程中实现调平,还需要更进一步的函数:调平时也结合平衡因子进行判定,并采取相应行为。
针对右子树的调平大体类似。
(4)删除结点删除过程中,对于被删除的结点,如果其左右子树有一为空,则可以以另一子树的根节点替代其地位。
否则,删除后须继续考虑调平。
此处的调平有利用前面的部分函数,也有一些新的函数:删除操作的从函数。
其有二级从函数:四、测试结果输入-1后开始选择函数五、系统不足与经验体会1.没有找到更直观的显示方式,界面不够友好;2.没有输出到文件中,读取不方便。
六、附录:源代码(带注释)见附件。
#include <iostream>using namespace std;const int MAXI = 100;const int LH = 1;const int EH = 0;const int RH = -1;class BSTNode{public:BSTNode(){data = 0;bf = EH;lchild = NULL;rchild = NULL;};~BSTNode(){if(lchild != NULL){lchild->~BSTNode();}if(rchild != NULL){rchild->~BSTNode();}}int data;int bf;//Balance FactorBSTNode *lchild, *rchild;};class BSTpublic:BST(){root = NULL;taller = 0;shorter = 0;}~BST(){};BSTNode *R_Rotate(BSTNode *CurrPTR){BSTNode *TempL = NULL;TempL = CurrPTR->lchild;CurrPTR->lchild = TempL->rchild;TempL->rchild = CurrPTR;CurrPTR = TempL;return CurrPTR;}BSTNode *L_Rotate(BSTNode *CurrPTR){BSTNode *TempR = NULL;TempR = CurrPTR->rchild;CurrPTR->rchild = TempR->lchild;TempR->lchild = CurrPTR;CurrPTR = TempR;return CurrPTR;}void L_Balance(BSTNode *CurrPTR);void R_Balance(BSTNode *CurrPTR);void Establish();bool Insert(int InVal);bool Insert(BSTNode *CurrPTR, int InVal);void Search_M();bool Search_S(BSTNode *CurrPTR, int InVal);void Display_M();void Display_S(BSTNode *CurrPTR, int Height);void Delete_S_L(BSTNode *CurrPTR);void Delete_S_R(BSTNode *CurrPTR);void Delete_S(BSTNode *CurrPTR, BSTNode *NextPTR);bool Delete_M(BSTNode *CurrPTR, int DelVal);private:BSTNode *root;bool taller;bool shorter;};void Selection();int main(){cout << "Hello world!" << endl;cout << "Balanced Selection Tree of Kirov_Tujin." << endl << "main :: Orders:" << endl<< "E. Establish a Balanced Selection Tree." << endl<< "Q. Quit the program." << endl;Selection();return 0;}void Selection(){BST Tree;char Order = 0;bool Selecting = 0;while(Selecting == 0){cout << "Selection 1:Input your Order." << endl;cin >> Order;switch (Order){case 'E':{Selecting = 1;Tree.Establish();break;}case 'Q':{cout << "Selection 1:Quit?('Y' to Quit.)" << endl;cin >> Order;if(Order == 'Y'){return;}else{cout << "Selection 1:Quit:Illegal Input." << endl;}break;}default :{cout << "Selection 1:Illegal Input." << endl;}}}cout << "Selection :: Orders:" << endl<< "S. Search for a key-word." << endl<< "I. Insert a key-word into the tree." << endl<< "D. Delete a key-word from the tree." << endl<< "P. Display the tree." << endl<< "Q. Quit the program." << endl;while(Selecting){cout << "Selection 2:Input your Order." << endl;cin >> Order;switch (Order){case 'S':{cout << "Selection 2:Searching." << endl;Tree.Search_M();cout << "Selection 2:Search Finished." << endl;break;}case 'I':{cout << "Selection 2:Inserting." << endl;int InVal = 0;cout << "Input the value you want." << endl;cin >> InVal;Tree.Insert(InVal);cout << "Selection 2:Insertion Finished." << endl;break;}case 'D':{cout << "Selection 2:Deleteing." << endl;;cout << "Selection 2:Deleting Finished." << endl;break;}case 'P':{cout << "Selection 2:Displaying." << endl;Tree.Display_M();cout << "Selection 2:Display Finished." << endl;break;}case 'Q':{cout << "Selection 2:Quit?('Y' to Quit.)" << endl;cin >> Order;if(Order == 'Y'){return;}else{cout << "Selection 2:Quit:Illegal Input." << endl;}break;}default :{cout << "Selection 2:Illegal Input." << endl;}}}cout << "Selection ended." << endl;return;}void BST :: L_Balance(BSTNode *CurrPTR){BSTNode *TempL = NULL, *TempL_R = NULL;TempL = CurrPTR->lchild;switch (TempL->bf){case LH:{R_Rotate(CurrPTR);CurrPTR->bf = EH;TempL->bf = EH;break;}case RH:{TempL_R = TempL->rchild;L_Rotate(CurrPTR->lchild);R_Rotate(CurrPTR);switch(TempL_R->bf){case LH:{CurrPTR->bf = RH;TempL->bf = EH;break;}case EH:{CurrPTR->bf = EH;TempL->bf = EH;break;}case RH:{CurrPTR->bf = EH;TempL->bf = LH;break;}TempL_R->bf = EH;}}}return;}void BST :: R_Balance(BSTNode *CurrPTR){BSTNode *TempR = NULL, *TempR_L = NULL;TempR = CurrPTR->rchild;switch (TempR->bf){case LH:{R_Rotate(CurrPTR);CurrPTR->bf = EH;TempR->bf = EH;break;}case RH:{TempR_L = TempR->lchild;L_Rotate(CurrPTR->lchild);R_Rotate(CurrPTR);switch(TempR_L->bf){case LH:{CurrPTR->bf = RH;TempR->bf = EH;break;}case EH:{CurrPTR->bf = EH;TempR->bf = EH;break;}case RH:{CurrPTR->bf = EH;TempR->bf = LH;break;}}TempR_L->bf = EH;}}return;}bool BST :: Insert(BSTNode *CurrPTR, int InVal){if(CurrPTR == NULL){BSTNode CURR;CurrPTR = &CURR;CurrPTR->data = InVal;taller = true;}else{if(CurrPTR->data == InVal){taller = false;cout << "BST:Insert_S:Value Existed." << endl;return 0;}else if(CurrPTR->data < InVal){if(Insert(CurrPTR->lchild,InVal) == 0){return 0;}else if(taller){switch(CurrPTR->bf){case LH:{L_Balance(CurrPTR);taller = false;break;}case EH:{CurrPTR->bf = LH;taller = true;break;}case RH:{CurrPTR->bf = EH;taller = false;break;}}}}else if(CurrPTR->data > InVal){if(Insert(CurrPTR->rchild,InVal) == 0){return 0;}else if(taller){switch(CurrPTR->bf){case LH:{CurrPTR->bf = EH;taller = false;break;}case EH:{CurrPTR->bf = RH;taller = true;break;}case RH:{R_Balance(CurrPTR);taller = false;break;}}}}}return 1;}bool BST :: Insert(int InVal){if(root == NULL){BSTNode CURR;root = &CURR;root->data = InVal;taller = true;}else{if(root->data == InVal){taller = false;cout << "BST:Insert_S:Value Existed." << endl;return 0;}else if(root->data < InVal){if(Insert(root->lchild,InVal) == 0){return 0;}else if(taller){switch(root->bf){case LH:{L_Balance(root);taller = false;break;}case EH:{root->bf = LH;taller = true;break;}case RH:{root->bf = EH;taller = false;break;}}}}else if(root->data > InVal){if(Insert(root->rchild,InVal) == 0){return 0;}else if(taller){switch(root->bf){case LH:{root->bf = EH;taller = false;break;}case EH:{root->bf = RH;taller = true;break;}case RH:{R_Balance(root);taller = false;break;}}}}}return 1;}void BST :: Search_M(){cout << "Input the value you want." << endl;int WanaVal = 0;cin >> WanaVal;bool Found = 0;Found = Search_S(root,WanaV al);return;}bool BST :: Search_S(BSTNode *CurrPTR, int WanaVal) {if(WanaVal == CurrPTR->data){return true;}else if((WanaVal < CurrPTR->data)&&(CurrPTR->lchild != NULL)){return Search_S(CurrPTR->lchild,WanaVal);}else if((WanaVal < CurrPTR->data)&&(CurrPTR->rchild != NULL)){return Search_S(CurrPTR->rchild,WanaV al);}return false;}void BST :: Display_M(){Display_S(root,0);return;}void BST :: Display_S(BSTNode *CurrPTR, int Height) {cout << "Height:" << Height << "\tData:";if(CurrPTR == NULL){cout << '#' << endl;return;}else{cout << CurrPTR->data << endl;Display_S(CurrPTR->lchild,Height+1);Display_S(CurrPTR->rchild,Height+1);}return;}void BST :: Establish(){int InVal = 0;do{cout << "Input the value you want." << endl;cin >> InVal;Insert(root,InVal);}while(InVal != -1);return;}void BST :: Delete_S_L(BSTNode *CurrPTR){BSTNode *TempR = NULL, *TempR_L = NULL;if(CurrPTR->bf == LH){CurrPTR->bf = 0;shorter = 0;}else if(CurrPTR->bf == EH){CurrPTR->bf = RH;shorter = 0;}else{TempR = CurrPTR->rchild;if(CurrPTR->bf == EH){L_Rotate(CurrPTR);TempR->bf = 1;CurrPTR->bf = -1;shorter = 0;}else if(TempR->bf == RH){L_Rotate(CurrPTR);TempR->bf = NULL;CurrPTR->bf = 0;shorter = 1;}else{TempR_L = TempR->lchild;TempR->lchild = TempR_L->rchild;TempR_L->rchild = TempR;CurrPTR->rchild = TempR_L->lchild;TempR_L->lchild = CurrPTR;if(TempR_L->bf == EH){CurrPTR->bf = EH;TempR->bf = EH;}else if(TempR_L->bf == RH){CurrPTR->bf = LH;TempR->bf = EH;}else{CurrPTR->bf = 0;TempR->bf = LH;}TempR_L->bf = EH;CurrPTR = TempR_L;shorter = true;}}return;}void BST :: Delete_S_R(BSTNode *CurrPTR){BSTNode *TempL = NULL, *TempL_R = NULL;if(CurrPTR->bf == LH){CurrPTR->bf = 0;shorter = 0;}else if(CurrPTR->bf == EH){CurrPTR->bf = RH;shorter = 0;}else{TempL = CurrPTR->rchild;if(CurrPTR->bf == EH){L_Rotate(CurrPTR);TempL->bf = 1;CurrPTR->bf = -1;shorter = 0;}else if(TempL->bf == RH){L_Rotate(CurrPTR);TempL->bf = NULL;CurrPTR->bf = 0;shorter = 1;}else{TempL_R = TempL->lchild;TempL->lchild = TempL_R->rchild;TempL_R->rchild = TempL;CurrPTR->rchild = TempL_R->lchild;TempL_R->lchild = CurrPTR;if(TempL_R->bf == EH){CurrPTR->bf = EH;TempL->bf = EH;}else if(TempL_R->bf == RH){CurrPTR->bf = LH;TempL->bf = EH;}else{CurrPTR->bf = 0;TempL->bf = LH;}TempL_R->bf = EH;CurrPTR = TempL_R;shorter = true;}}return;}void BST :: Delete_S(BSTNode *CurrPTR, BSTNode *NextPTR) {if(NextPTR->rchild == NULL){CurrPTR->data = NextPTR->data;CurrPTR = NextPTR;NextPTR = NextPTR->lchild;delete(NextPTR);shorter = 1;}else{Delete_S(CurrPTR,NextPTR->rchild);if(shorter == LH)Delete_S_R(CurrPTR);}return;}bool BST :: Delete_M(BSTNode *CurrPTR, int DelVal){bool Deleted = false;BSTNode *DelPTR;if(CurrPTR == NULL){cout << "No such node." << endl;return false;}else if(DelVal<CurrPTR->data){Deleted = Delete_M(CurrPTR->rchild,DelVal);if(shorter == 1)R_Balance(CurrPTR,shorter);return Deleted;}else{DelPTR = CurrPTR;if(CurrPTR->rchild == NULL){CurrPTR = CurrPTR->lchild;delete DelPTR;shorter = 1;}else if(CurrPTR->lchild == NULL){CurrPTR = CurrPTR->rchild;delete DelPTR;shorter = 1;}else{Delete_S(DelPTR,DelPTR->lchild,shorter);if(shorter == 1)L_Balance(CurrPTR,shorter);CurrPTR = DelPTR;}return true;}}。