第二章数据结构与算法
算法
算法的基本概念
所谓算法,是指解决问题方案的准确而完备的描述
可行性
①算法中的每一个步骤必须能够实现
②算法执行的结果要能够达到预期的目的
确定性
指算法中每一个步骤都必须有明确的定义,不允许有模棱两可的解释,也不允许有多义性
有穷性
指算法必须能在有限的时间内做完,即算法必须能在执行有限个步骤之后终止,算法的有穷性还应包括合理的执行时间的含义
拥有足够的情报
一个算法执行的结果总是与输入的初始数据有关,不同的输入将会有不同的结果,输出一般来说,当算法拥有足够的情报时,此算法才是有效的,而当提供的情报不够使算法可能无效
综上所述,所谓算法是一组严谨的定义运算顺序的规则,并且每一个规则都是有效的,且是明确的,此顺序将在有限的次序下终止
算法设计基本方法
计算机解题的过程实际上是在实施某种算法,这种算法称为计算机算法
列举法
基本思想:根据提出的问题,列举所有可能的情况,并用问题中给定的条件,检验哪些是需要的,哪些是不需要的
注意点:当列举可能情况较多时,列举算法的工作量将会很大,因此,在用列举法设计算法时,使方案优化,尽量减少运算工作量
归纳法
基本思想:通过列举少量的特殊情况,经过分析,最后找出一般的关系
归纳是一种抽象,即从本质现象中找出一般关系
本质上讲归纳就是通过观察一些简单而特殊的情况,最后总结出一般性的结论
注意点:由于在归纳过程中不可能对所有情况进行举例,因此,最后由归纳得到的结论还只是一种猜测,还需要对这种猜测加以必要的证明
递推法
基本思想:从已知的初始条件出发,逐次推出所要求的中间结果和最后结果
初始条件或问题本身已给定,或者通过对问题分析与简化而确定。
递归法
基本思想:在解决一些复杂问题时,为了降低问题的复杂程度,一般总是将问题逐层分解,最后归纳为一些简单的问题
这种将问题逐层分解的过程,实际上并没有对问题进行求解,而只是解决了最后那些最简单的问题后,再沿着原本分解的逆过程,逐步进行综合,这就是递归
直接递归
如果一个算法p直接调用自己,称为直接递归调用
间接递归
如果算法p调用了另一个算法q,而算法q又调用了算法p称为间接递归调用
本质上递推和递归都属于归纳法,通常情况下,递归算法要比递推算法清晰易读,且结构比较简练
减半递推技术
是分治法的一种
基本思想:所谓减半,是将问题的规模减半,而问题性质不变。所谓递推,是重复减半的过程
回溯法
基本思想:通过对问题的分析,找出一个解决问题的线索,然后沿着这个线索逐步试探,对于每一步的试探,若试探成功,则得到问题的解,若试探失败就逐步回退,换别的线路,再进行试探
常用于难以归纳,并且无法举例的问题
算法复杂度
时间复杂度
执行算法所需要的计算工作量,用算法在执行过程中所需基本运算的执行次数来度量算法的工作量,基本运算反映了算法运算的主要特征
空间复杂度
只执行这个算法所需的内存空间
数据结构的基本概念
为解决大量数据元素在计算机中如何组织,以便提高数据处理效率,节省计算机储存空间,这是进行数据处理的关键问题
数据结构研究的三个方面的问题
数据的逻辑结构
数据集合中,各数据元素之间所固有的逻辑关系
数据的存储结构
在对数据进行处理时,各数据元素在计算机中的存储关系
对各种数据结构进行的运算
什么是数据结构?
数据结构概论
简单地说,数据结构是指相互有关联的数据元素的集合
数据处理
对数据集合中的各元素,以各种方式进行运算,包括插入,删除,查找,更改等运算,也包括对数据元素进行分析等
数据元素具有广泛含义
一般来说,现实世界中客观存在的一切个体都可以是数据元素
一般情况下,在具有相同特征的数据元素集合中,各数据元素之间存在着某种关系及联系,这种关系反映了该集合中的数据元素所固有的一种结构。
在数据处理领域,通常把数据元素之间,这种固有的关系,简单地用前后件关系来描述,或者直接前驱与直接后继关系
一般来说,人们不会同时处理特征完全不同,且相互之间没有任何联系的各类数据元素,对于具有不同特征的数据元素,总是分别进行处理
数据的逻辑结构
数据元素之间前后件的关系就是逻辑关系,与他们在计算机中存储位置无关
所谓数据的逻辑结构,是指反映数据元素之间的逻辑关系的数据结构
表示数据元素的信息
表示各元素之间的前后件关系
数据结构的二元关系表示
二元组(a,b)
a是b的前件,b是a的后件
B=(D,R)
D为数据元素的集合,R为D上的关系,反映了地中各数据元素之间的前后件关系。B表示数据结构
举例:一年四季的数据结构可以表示成
B=(D,B)
D={春,夏,秋,冬}
R={(春,夏),(夏,秋),(秋,冬)}
数据的存储结构
数据的逻辑结构在计算机存储空间中的存放形式称为数据的存储结构
由于数据元素在计算机存储空间中的位置关系可能与逻辑关系不同,因此,为了表示存放在计算机存储空间中的各数据元素之间的逻辑关系及前后件关系,在数据的存储结构中,不仅要存放数据元素的信息,还要存放各数据元素之间的前后件关系信息
数据结构的图形表示
对于数据集合D中的每一个元素用中间标有元素值的方框表示称为数据结点,简称结点。用一条有向线段从前件节点指向后件结点
没有前件的节点称为根结点
没有后件的节点称为终端结点,也称叶子结点
数据结构中,除了根结点与终端节点外的其它街点,一般称为内部结点
通常情况下,一个数据结构中的元素节点可能是在动态变化的。
可以进行插入删除两种基本运算,还有查找,分类,合并,分解,复制和修改等运算
线性结构与非线性结构
根据数据结构中各数据元素之间前后件关系的复杂程度,一般将数据结构分为两大类,即线性结构与非线性结构
非线性结构
如果一个数据结构不是线性结构,则称为非线性结构
在非线性结构中,各数据元素间的前后件关系要比线性结构复杂。因此,对非线性结构的存储与处理比线性结构要复杂的多
线性结构(线性表)的条件
非空的数据结构要满足以下两个条件
有且只有一个根结点
每一个节点最多有一个前件也最多有一个后件
线性结构和非线性结构都可以是空的数据结构
一个空的数据结构究竟是属于线性结构还是非线性结构,是根据具体情况来确定
一个数据元素都没有的数据结构称为空的数据结构
线性表及其顺序存储结构
在计算机中存放线性表一种最简单的方法是顺序存储,也称为顺序分配
线性表是最简单,最常用的一种数据结构,是一种线性结构
线性表的基本概念
由此可以看出,在线性表的顺序存储结构中,其前后件两个元素在存储空间中是紧邻的,且前件元素一定存储在后件元素的前面
①线性表中所有元素所占存储空间是连续的
②线性表中各数据元素在存储空间中是按逻辑顺序依次存放的
在程序设计语言中,通常定义一个一维数组来表示线性表的顺序储存空间
在线性表的顺序储存结构下,可以对线性表进行各种处理,主要的运算有以下几种
插入:在线性表的指定位置处插入一个新的元素
删除:在线性表中删除指定元素
查找:在线性表中查找某个或某些特定元素
排序:对线性表元素进行整序
分解:将一个线性表分解成多个线性表
合并:将多个线性表合并成一个线性表
复制:复制一个线性表
逆转:逆转一个线性表
顺序表的插入运算
在为线性表开辟的有限的储存空间内,在某个元素位置前插入一个新元素,在此之后的元素均往后移动一个位置
若线性表开辟的储存空间已满,就不能再插入新的元素了,如果硬插入会导致称为“上溢”的错误
顺序表的删除运算
在为线性表开辟的有限的储存空间内,删除某个元素,其后的所有元素往前移动一个位置
线性表的顺序存储结构的缺点
①一般情况下,在顺序存储的线性表中插入或删除一个元素,为保证插入或删除后的线性表仍然有序,需要移动大量的数据元素,对于大的线性表,特别是插入和删除频繁的情况下,效率很低
②单位一个线性表分配顺序存储空间后,如果出现线性表存储空间已满,还要插入新元素,就会发生上溢错误。即顺序存储结构下线性表存储空间不便与扩充
③多个线性表共享存储空间,为了保证每一个线性表的存储空间连续且顺序分配,会导致在对某个线性表进行动态分配,存储空间时必须要移动其他线性表中的数据。即线性表的顺序存储结构不便于对存储空间进行的动态分配
栈和队列
栈及其基本运算
什么是栈?
栈实际上也是线性表,只不过是一种特殊的线性表
栈是限定在一端进行插入与删除的线性表
这种线性表的结构中,一端是封闭的,不允许进行插入和与删除元素,另一端是开口的,允许插入和伸出元素。在顺序存储结构下,对这种类型线性表的插入与删除运算是不需要移动其它数据元素的,这种线性表称为栈
允许插入与删除的一端称为栈顶,通常用指针top来指示栈顶的位置
不允许插入和删除的一端称为栈底,用指针bottom指向栈底
栈也被称为“先进后出”表或“后进先出”表
往栈中插入一个元素称为入栈运算,从栈中删除一个元素称为退栈运算
栈的顺序存储及其运行
在程序设计语言中,用一维数组s(1 :m)作为栈的顺序存储空间。其中m为栈的最大容量
Top等于零表示栈空,top=m表示栈满
顺序储存结构下栈的三种运算
特别注意,在运行以下三种运算之前,必须先判断栈顶指针是否为零?或者指针是否以指向储存空间最后一个位置?
入栈运算
入栈运算是在栈顶位置插入一个新元素,栈顶指针进一top+1
退栈运算
取出栈顶元素,并赋给一个定义的变量,栈顶指针减一top-1
读栈顶元素
将栈顶元素赋给一个指定的变量
栈的初始化,即建立一个空栈
队列及其基本运算
什么是队列?
队列实际上也是线性表,只不过是个特殊的线性表
队列是指允许在一端进行插入,而在另一端进行删除的线性表
需要加入的元素总是插入到线性表的末尾,并且又总是从线性表的头部取出或删除元素,这种线性表称为队列
允许插入的一端称为队尾,通常用尾指针rear指向队尾元素
允许删除的一端称为排头,也称对头,通常用排头指针front指向排头元素的前一个位置
队列又称为“先进先出”或“后进后出”的线性表
往队列的队尾插入一个元素,称为入队运算,从队列的排头删除一个元素,称为退队运算。
循环队列及其运算
在实际应用中,队列的顺序存储结构一般采用循环队列的形式
所谓队列,就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间
循环队列主要有两种基本运算
注意,要首先判断队列是否已满,或者判断队列是否为空
入队运算
在循环队列的队尾加入一个新元素,同时将队尾指针rear+1
退队运算
在循环队列的排头位置退出一个元素,同时将排头指针进一front+1
队列的初始化,即建立一个空队列
线性链表
线性表的链式存储结构称为线性链表
在线性链表中,用一个专门的指针HEAD指向线性链表中的第一个数据元素的结点
在线性链表中,最后一个节点的指针域为空(用NULL或0表示),表示链表终止
线性单链表
线性链表的基本概念
为了适应线性表的链式存储结构,计算机存储空间被划分为一个一个小块,每一小块占若干个字节,通常称这些小块为存储结点
每个结点由两部分构成,一部分用于存储数据元素值,称为数据域,另一部分用于存放指针,其中存放下一个数据元素的存储序号,即存储结点的地址(即指向后件的结点)称为指针域。
存放数据结构的存储空间可以不连续,各数据结点的存储顺序与数据元素之间的逻辑关系可以不一致,而数据元素之间的逻辑关系是由指针域来确定的
链式存储方式即可用于表示线性结构,也可用于表示非线性结构
以上讨论的为单链表,在这种链表中,每一个节点只有一个指针域,因此只能找到后件的结点,不能找到前件的结点
为了找它的前件,就必须从头指针开始重新寻找
线性双向链表
基本原理与单链表完全相同
为弥补单项链表的缺点,双向链表在每个结点设置了两个指针,一个称左指针(Llink)用以指向前件结点,一个称后指针(Rlink)用以指向后件结点
带链的栈
栈也是线性表,也可采用链式存储结构
在实际应用中,带链的栈可以用来收集计算机存储空间中所有空闲的存储节点,这种带链的栈称为可利用栈
由于可利用栈链接了计算机存储空间中所有空闲结点,因此,当计算机系统或用户程序需要存储结点时,就可从中取出栈定结点。同理,当计算机系统释放一个结点,则要将该节点放回到可利用栈的栈顶
带链栈的基本操作与线性栈基本一致
带链的队列
队列也是线性表,也可采用链式存储结构
带链队列的基本操作与顺序队列基本一致
线性列表的基本运算
在线性链表中,包含指定元素的结点前插入一个新元素
在线性链表中删除包含指定元素的结点
将两个线性链表按要求合并成一个线性链表
将一个线性链表按要求分解
逆转线性链表
复制线性链表
线性链表的查找
线性链表的排序
线性链表的插入(现在要在线性链表中包含x元素的结点,之前插入一个新元素b)
线性存储结构下线性列表插入一个新元素
①从可利用栈取出一个结点,设该结点存储序号为p,并假设结点p的数据为插入的元素值b
②在线性表中寻找目标元素x的前一个结点,假设该结点存储序号放置在变量p中
③最后将结点p插入到结点q之后
a.使结点p指针指向包含元素x的结点
b.使结点q的指针域内容改为指向结点p
线性链表的删除(现在要在线性链表中删除包含元素x的结点)
在链式存储结构下的线性表中删除包含指定元素的结点
①在线性链表中寻找包含元素x的前一个节点,假设该节点序号为q
②将结点q的指针指向包含元素x的结点指针所指向的结点
③将包含元素x的结点送回可利用栈
循环列表
为了克服线性链表在运算过程中,对于空表和对第一结点的处理必须单独考虑的缺点
①在线性链表中增加了一个表头节点,其数据域为任意或者根据需要来设置,指针域指向线性表的第一个元素的结点,循环链表的头指针HEAD指向表头节点
②循环链表中最后一个节点的指针域不是空,而是指向表头节点
树与二叉树
树的基本概念
树是一种简单的非线性结构
数是一种层次结构
在树的这种数据结构中,所有数据元素之间的关系具有明显的层次特征
在数的图形表达式中,总是认为用直线连接起来的两个端点中,上端节点是前件,下端节点是后件
在树结构中,每一个结点只有一个前件,称为父结点
没有钱建的节点,只有一个称为树的根结点,简称树的根
在树结构中,每一个结点可以有多个后件,他们都称为该结点的子结点,没有后件的结点称为叶子节点
在树结构中,一个结点所拥有的后件个数称为该结点的度
在树中,所有结点中最大的度称为树的度
树中的结点数,即为树中所有结点的度之和,再加一
树是一种层次结构,一般按照如下原则分层
根结点在第一层
同一层上所有结点的子节点都在下一层
树的最大层次称为树的深度
在数中以某结点的一个子结点为根构成的树称为该结点的一颗子树
在树中,叶子结点没有子树
二叉树及其基本性质
什么是二叉树?
二叉树是一种很有用的非线性结构,二叉树不同于树结构,但又和树结构很相似,并且树结构所有术语都可以用在二叉树结构上
①非空二叉树只有一个根结点
②每一个结点最多有两棵子树,且分别称为该结点的左子树和右子树
二叉树的基本性质
①在二叉树的k层上,最多有2^(k-1)结点
②深度为m的二叉树,最多有2^m-1个结点
③度为0的节点即子叶结点,总比度为2的结点多一个
满二叉树
除最后一层外,每一层上所有结点都有两个子结点
完全二叉树
除最后一层外,每一层上的结点数均到达最大值,在最后一层上,只缺少右边若干结点数
二叉树的存储结构
在计算机中,二叉树通常采用链式存储结构(二叉链表)
由于二叉树的存储结构中,每一个存储节点有两个指针域,因此,二叉树链式存储结构也被称为二叉链表
用于存储二叉树中的各元素存储结点也由两部分构成,即数据域和指针域
但不同的是,用于存储二叉树的存储节点的指针有两个:一个用于指向该结点的左子结点的存储地址,称为左指针域,另一个用于指向该结点的右子结点的存储地址,称为右指针域
二叉树的遍历
即不重复的访问二叉树中所有的结点
前序遍历DLB
先访问根结点,然后遍历左子树,最后遍历右子树
并且在遍历左右子数时,仍先访问根节点,然后遍历左子树,最后遍历右子树
中序遍历LDR
先遍历左子树,然后访问根节点,最后遍历右子树
并且在电力左右指数时,仍然先遍历左子树,然后访问根节点,最后遍历右子树
后序遍历LRD
首先遍历左子树,然后遍历右子树,最后访问根结点
并且在遍历左右子数时,仍然先遍历左子树,然后遍历右子树,最后访问根结点
查找技术
顺序查找
在线性表中查找指定的元素
基本方法:从线性表第一个元素开始,依次将线性表中的元素与被查元素进行比较,若相等,则找到,即查找成功。若线性表中所有元素与被查元素均不相等,则表示线性没有要找的元素,查找失败
二分法查找(对分查找)
只适用于顺序存储的有序表
将被查元素x与线性表中间项进行比较
若中间项等于x差到结束
若x小于中间项的值,则在线性表中的前半部分,以相同方法进行查找
若x大于中间项的值,则在线性表中的后半部分,以相同的方式进行查找
排序技术
将一个无序序列整理成按值非递减顺序排列的有序序列
交换类排序法
借助数据元素之间相互交换进行的排序方法
冒泡排序法
也称为下沉法。通过相邻数据元素的交换,逐步将线性表变成有序
冒泡排序需要经过n/2遍,从前往后扫描和n/2,便从后往前扫描,需要比较的次数为n×(n- 1)/2。一般情况下要小于这个工作量
①首先从表头开始,往后扫描线性表,在每次扫描过程中,逐次比较相邻两个元素的大小,若相邻两个元素中,前面元素大于后面元素,则将它们互换,称之为消去一个逆序。最后就将线性表中最大者换到了表的最后
②然后,从后往前扫描,剩下的线性表同样在扫描过程中逐次比较,相邻两个元素大小,若相邻两个元素中,后面的元素小于前面的元素,则将它们互换,这样又消去了一个逆序。最后就将剩下线性表中最小者换到了最前面
③对剩下的线性表重复上述过程,直到剩下的线性表变空为止,此时线性表已经变得有序
快速排序法
可以实现通过两个元素交换,能够消除线性表中多个逆序,大大加快排序速度
①从线性表中选取一个元素,假设为t将线性表,将线性表后面小于t的元素移到前面,将线性表前面大于t的数移到t的后面。结果就将线性表分成了两部分,以t为分界线,前面子表中所有元素均不大于t,后面子表中所有元素均不小于t
②这种分割过程可以一直做下去,直到所有子表为空为止,则此时线性表就变成有序表
插入类排序法
简单插入排序法
①一般来说,假设线性表中前j-1个元素已经有序,现在要将线性表中j这个元素插入到前面的有序子表中
②首先将j这个元素放到一个变量t中,然后从有序子表最后一个元素开始,往前逐个与t比较,将大于t的元素一律依次向后移动一个位置,直到发现一个元素不大于t为止,此时将t(即原线性表中J这个元素)插入到刚移出的空位置
希尔排序法
①假设一个增量序列h,一般选取为h=N/2,其中n为待排序序列的长度
②用增量依次衡量待排数列,将增量两段的数,按大的在前,小的在后进行排列
③减小增量的长度依次进行插入排列
选择类排序法
简单选择排序法
扫描整个线性表,选出最小元素,将它交换到表的最前面,然后对剩下的子表采用相同的方法,直到此表为空为止
一般对于长度为n的序列,需要选择排序扫描n- 1遍,每一遍扫描均从剩下的子表中选出最小元素,将该元素与子表中第一个元素进行交换
堆排序法
本文详细介绍了数据结构与算法的基本概念,包括算法的可行性、确定性、有穷性和情报要求,以及算法设计的基本方法如列举法、归纳法、递推法和递归法。此外,还探讨了算法复杂度的度量——时间复杂度和空间复杂度。接着,文章阐述了数据结构的逻辑结构和存储结构,以及线性结构与非线性结构的区别。线性表、栈和队列的概念和操作被详细介绍,包括顺序存储和链式存储结构的特点。最后,文章提到了树和二叉树的基本概念,以及二叉树的遍历方法和查找排序技术。
3万+

被折叠的 条评论
为什么被折叠?



