数据结构
勇士后卫头盔哥
这个作者很懒,什么都没留下…
展开
-
二叉树的线索化
前言线索化二叉树就是将二叉树转换为双向链表的过程,也就是从非线性到线性的转化,对于结点的先后访问次序每次都去遍历的话效率太低,所以得引入双向链表来反映某种二叉树的遍历次序,利用结点的right指针指向遍历中的后继结点,利用结点的left指针指向遍历中的前驱结点,那么如何在遍历时记录结点间的访问次序,我们可以使用队列来进行操作,遍历结束后队列记录了访问次序,循环访问队列连接队列中的结点,如下图所示...原创 2020-07-28 20:58:05 · 263 阅读 · 0 评论 -
二叉树的操作(二)
二叉树的属性操作1.二叉树结点的数目对于二叉树结点数目的计算需要用递归来解决,在node为根节点的二叉树中统计结点数目的递归公式如下所示 return 0; node == NULLcount(node) count(node->left)+count(node->right)+1; node!=NULL;代码如下:int count(BTreeNode<T>* node)const{原创 2020-07-24 22:07:32 · 124 阅读 · 0 评论 -
二叉树的操作(一)
二叉树的查找二叉树也有两种查找方式,一种是基于数据元素值的查找和基于结点的查找,之前说过通用树结构的查找,一样也是一个递归调用的过程,递归公式如下图所示值查找的递归公式基于值的查找virtual BTreeNode<T>* find(BTreeNode<T>* node,const T& value)const{ BTreeNode<T>* ret = NULL; if(node!=NULL) { if(node-&原创 2020-07-20 23:03:55 · 133 阅读 · 0 评论 -
二叉树的定义
前言定义:二叉树是由n(n>=0)个结点组成的有限集合,该集合或者为空,或者是由一个根结点加上两颗分别称为左子树和右子树的,互不相交的二叉树组成在此之前我们已经实现过了通用树结构,通用树结构中的每个结点都可以有任意多的孩子,都可能具有无线形态,所以很复杂,我们可以简化结点中孩子的数量,之前实现的通用树结构是用双亲孩子表示法来实现的,如下图所示,每个结点都有一个指向双亲的指针,每个结点都有若干个指向其孩子的指针除此之外还有一种树结构模型叫孩子兄弟表示法,如下图所示,每个结点都有一个指向其第一个原创 2020-06-25 09:30:00 · 636 阅读 · 0 评论 -
树的操作(三)
树的属性操作树的属性操作具体指的就是树中结点的数目,树的高度,树的度数等…1.树中结点的数目查找树中结点数目的操作是递归完成的,是递归就有递归出口,当结点为空或者结点的子链表长度为0时就为递归出口,上图就是递归公式的提炼,我们看到下图,要求出该树的结点数可以分为3个部分,count(B)表示求以B为根结点的树的结点数,count©表示求以C为根结点的树的结点数,count(D)表示求以D为根结点的树的结点数,看得count(A)的同时又用到count©这就是一个递归调用的过程代码演示int c原创 2020-06-21 23:52:03 · 141 阅读 · 0 评论 -
树的操作(二)
树的清除操作树这种数据结构可以看做是一种容器,树的清除操作就是将树中的所有结点清除,也就是释放堆中的结点,如上图所示,假设我们要将树中数据元素清除,可以先将根结点里面的每一棵子树给清除掉,最后再将根节点清除即可,在清除子树的时候又用到清除树的操作所以这是一个递归调用的过程,出口就是树只有一个根节点且没有子树,公式定义如下代码实现void free(GTreeNode<T>* node){ if(node!=NULL) { for(node->ch原创 2020-06-20 21:43:48 · 194 阅读 · 0 评论 -
树的操作(一)
树的查找在之前树的定义中我们可以知道,我们提供的查找操作有基于数据元素值的查找和基于结点的查找,树是一种非线性结构,当我们查找根据数据元素值查找时需要用到递归调用,从根节点出发自顶向下对子节点进行查找对于树中数据元素和结点的查找如下基于数据元素值的查找基于结点的查找插入操作对于插入操作有插入新结点和插入新元素两种操作,树是非线性的,无法采用下标的形式定位数据元素,每一个树结点都有唯一的前驱结点(父节点),因此,必须先找到前驱结点才能完成新结点的插入对于插入新结点的流程图如下所示对于插入数原创 2020-06-20 12:41:49 · 137 阅读 · 0 评论 -
树的定义
前言树是一种非线性的数据结构,树是由n(n>=0)个结点组成的有限集合,如果n=0称为空树,如果n>0则包含根结点,根结点只有直接后继,但没有直接前驱,除根以外的其他结点划分为m(m>=0)个互不相交的有限集合T0,T1…Tm-1,每个集合又是一颗树,并且称之为根的子树(sub tree),可以看出树也是递归的一种树中度的概念1.树的结点包含一个数据及若干指向子树的分支2.结点拥有的子树数目称为结点的度 度为0的结点称为叶结点 度不为0的结点称为分支结点3.树的度定义为原创 2020-06-18 09:40:30 · 671 阅读 · 0 评论 -
项目中的排序工程
前言struct Test : public Object{ int id; int data1[1000]; double data2[500];}..................Test t[1000]Sort::Bubble(t,1000,false);如上述代码所示,如果当待排数据元素为体积庞大的对象时,如何提高排序的效率,大家肯定会想到用更高效的排序方法来提高效率,但是发现效率的提高是微不足道的,问题的关键在于排序过程中不可原创 2020-06-12 15:20:08 · 318 阅读 · 0 评论 -
归并排序和快速排序
前言之前文章提到过的希尔排序它有划时代的意义,打破了一个认知——排序算法的复杂度不可能超过O(n*n),之后各种各样更高效的排序算法就开始出现了,比如这次文章中提到的归并排序和快速排序归并排序基本思想:将两个或者两个以上的有序序列合并成一个新的有序序列,有序序列V[0]…V[m]和V[m+1]…V[n-1]合并成V[0]…V[n-1],这种归并方法称为2路归并,以此类推,将多个有序序列归并为一个新的有序序列,称为多路归并,特别注意的是,要归并的序列必须是有序的,如下图所示,归并排序其实是一个递归调用原创 2020-06-12 13:07:52 · 200 阅读 · 0 评论 -
冒泡排序和希尔排序
冒泡排序基本思想每次从后向前进行(假设为第i次),j=n-1,n-2,…,i,两两比较V[j-1]和V[j]的关键字,如果发生逆序则交换V[j-1]和V[j]的值,如下图所示从无序序列区域最后一个元素开始冒泡,若发现逆序则交换元素,一次冒泡过后有序序列区域增加一个元素且仍有序下图是动画演示过程,Exchang用来标记无序序列是否已经有序,若已经有序则Exchang置为0避免再次冒泡比较浪费时间,时间复杂度为O(n*n)且是稳定排序代码演示 template <typename T>原创 2020-06-11 17:37:10 · 667 阅读 · 0 评论 -
选择排序和插入排序
前言所谓排序就是计算机内经常进行的一种操作,其目的就是将一组"无序"的数据元素调整为"有序"的数据元素,排序也存在稳定性的定义:如果在序列中有两个数据元素R[i]和R[j],它们的关键字(排序的依据)K[i]==K[j],且在排序之前,对象R[i]排在R[j]前面,如果在排序之后,对象R[i]仍在对象R[j]的前面,则称这个排序方法是最稳定的,否则称这个排序方法是不稳定的,在排序中也有多关键字排序,所谓多关键字排序就是有多个排序依据,且它们的优先级不同,当优先级相同时则看一下关键字,对于多关键字排序,只要原创 2020-06-11 12:31:48 · 208 阅读 · 1 评论 -
栈和队列的深入分析
用栈实现队列栈和队列采用同样的存储方法,那我们就可以用栈来实现队列,用栈实现队列就是用"后进先出"的特性实现"先进先出"的特性,我们准备两个栈,一个栈专门用于元素的进入,一个栈专门用于元素的出去,如下图所示,a1,a2,a3进入第一个栈后,然后弹出进入第二个栈,然后再把第二个栈弹出就变成了队列的实现设计思路:当有新元素入队时:将其压入stack_in当需要出队时:1.stack_out...原创 2020-04-28 23:05:18 · 249 阅读 · 0 评论 -
队列的概念及实现
1 前言队列也是一种特殊的线性表,队列仅能在线性表的两端进行操作,队头(Front)为取出数据元素的一端,队尾为插入数据元素的一端,队列的特性为先进先出(First In First Out)队列的操作包括创建队列,销毁队列,清空队列,进队列,出队列,获取队头元素,获取队列的长度,队列可以包括静态队列和动态队列,我们可以抽象出一个队列父类,静态队列和动态队列都继承于该类,队列的顺序实现如下图...原创 2020-04-28 17:54:59 · 208 阅读 · 0 评论 -
栈的概念及其实现
1 前言栈是一种特殊的线性表,栈仅能在线性表的一端进行操作,栈顶(Top)为允许操作的一端,栈底(Bottom)为不允许操作的一端,栈的特性就是后进先出(Last In First Out),只允许在线性表的一段进行操作栈可以看成一个容器,所以栈的操作有创建栈,销毁栈,清空栈,进栈(pop),出栈(push),获取栈顶元素,获取栈的大小,对于栈有静态栈和动态栈,所以我们可以抽象出一个**栈父...原创 2020-04-27 20:04:20 · 244 阅读 · 0 评论 -
循环链表
循环链表在概念就是任意数据元素都有一个前驱和一个后继(与单链表不同的重点,单链表首结点没有前驱而尾结点没有后继),所有的数据元素的关系构成一个逻辑上的环,在实现上,循环链表是一种特殊的单链表,其尾结点的指针域保存了首结点的地址,如下图所示循环链表的实现思路通过模板定义CircleList类,继承自LinkList单链表类定义内部函数last_to_first(),用于将单链表首尾相连特殊...原创 2020-04-16 19:41:53 · 401 阅读 · 0 评论 -
静态单链表
之前我们说过如果频繁增删数据元素,我们应该选择单链表就可以,但是如果数据元素的最大个数固定,那么就需要静态单链表,而且动态单链表如果长时间使用单链表对象频繁增加和删除数据元素,堆空间产生大量的内存碎片,导致系统运行缓慢,所谓单链表就是“顺序表 + 单链表 =静态单链表”设计思路在"单链表"的内部增加一片预留的空间,所有的Node对象都在这片空间中动态创建和动态销毁,所以我们得重载create(...原创 2020-04-11 20:16:44 · 196 阅读 · 0 评论 -
链式线性表
对于顺序存储结构线性表的最大问题就是插入和删除需要移动大量的元素,而这使代码效率变得低下,所以这里就要引入我们的链式存储结构,链式存储结构为了表示每个数据元素与其直接后继元素之间的逻辑关系,数据元素除了存储本身的信息外,还需要存储其后继的信息,如下图表示,ai元素的数据结构保存了下一个ai+1元素的地址,就像小朋友过马路,一个牵着一个形成链式结构链式存储逻辑结构:...原创 2020-04-11 11:55:06 · 529 阅读 · 0 评论 -
数组类的创建
前文在线性表的文章中我们看到了线性表的局限,所以我们现在得引入数组类,提供可靠的原生数组代替品,这是原生数组无法提供数组的长度信息,并且也无法检测在使用的时候当前的操作是否合法,是否越界,所以我们自己创建的数组类必须满足以下需求:数组类包含长度信息数组类能够主动发现越界访问设计要点:抽象类模板,存储空间的位置和大小由子类完成重载数组操作符,判断访问下标是否合法提供数组长度的抽象访问函...原创 2020-04-01 15:39:33 · 576 阅读 · 0 评论 -
线性表
线性表是由零个或多个数据元素组成的集合,数据元素在位置上有序排列的,数据元素的个数是有限的,数据元素的类型必须相同,线性表可用于描述排队关系的问题,线性表(List)的抽象定义如下,ai是表项(数据元素),n是表长度线性表的性质:a0为线性表的第一个元素,只有一个后继an-1为线性表的最后一个元素,只有一个前驱除a0和an-1外的其他元素ai既有前驱,又有后继直接支持逐项访问和顺序存取...原创 2020-03-30 20:53:48 · 119 阅读 · 0 评论