1、第1章 数据结构与算法,1.1 算法 1.2 数据结构的基本概念 1.3 线性表及其顺序存储结构 1.4 栈和队列 1.5 线性链表 1.6 树和二叉树 1.7 查找技术 1.8 排序技术,算法的基本概念 算法的复杂度分析,1.1 算法,算法的基本概念,通俗的定义: 算法是指解题方案的准确而完整的描述。,算法的基本特征,1.可行性 2.确定性 3.有穷性 4.拥有足够的情报,算法的严格定义:算法是一组严谨地定义运算顺序的规则,并且每一个规则都是有效的,且是明确的,此顺序将在有限的次数下终止。,算法的基本要素,(1) 算法中对数据的运算和操作算术运算逻辑运算关系运算数据传输 (2) 算法的控制结
2、构传统流程图、N-S结构化流程图、算法描述语言等。,算法设计基本方法,1. 列举法根据提出的问题,列举所有可能的情况,并用问题中给定的条件检验哪些是需要的,哪些是不需要的。因此,列举法常用于解决“是否存在”或“有多少种可能”等类型的问题,例如求解不定方程的问题。例:设每只母鸡值3元,每只公鸡值2元,两只小鸡值1元。现要用100元钱买100只鸡,设计买鸡方案。 假设买母鸡I只,公鸡J只,小鸡K只。,2. 归纳法 通过列举少量的特殊情况,经过分析,最后找出一般的关系。 3. 递推 从已知的初始条件出发,逐次推出所要求的各中间结果和最后结果。 4. 递归 将一个复杂的问题归结为若干个较简单的问题,然
3、后将这些较简单的每一个问题再归结为更简单的问题,这个过程可以一直做下去,直到最简单的问题为止。,5. 减半递推技术 所谓“减半”,是指将问题的规模减半,而问题的性质不变。 所谓“递推”,是指重复“减半”的过程。 例:二分法求方程实根 6. 回溯法 通过对问题的分析,找出一个解决问题的线索,然后沿着这个线索逐步试探,对于每一步的试探,若试探成功,就得到问题的解,若试探失败,就逐步回退,换别的路线再进行试探。 例:迷宫问题,算法的复杂度分析,算法的时间复杂度算法的空间复杂度执行算法所需要的内存空间。,1. 2 数据结构的基本概念,什么是数据结构 数据结构的图形表示 线性数据结构与非线性数据结构,目
4、的:提高数据处理的效率提高数据处理的速度尽量节省计算机存储空间 数据结构三个方面的问题: (1)数据的逻辑结构 (2)数据的存储结构 (3)对各种数据结构进行的运算,什么是数据结构,数据结构是指相互有关联的数据元素集合。 现实世界中客观存在的一切个体都可以是数据元素。 描述一年四季的季节名春,夏,秋,冬可以作为季节的数据元素; 表示数值的各个数18,11,35,23,16,可以作为数值的数据元素;,前后件关系,前后件关系(也称为直接前驱和直接后继)是数据元素之间的自然存在的一个基本关系,但前后件关系所表示的实际意义是随具体对象的不同而不同。一般来说,数据元素之间的任何关系都可以用前后件关系来描
5、述。,数据的逻辑结构,一个数据结构应包含两方面的信息(1)表示数据元素的信息;(2)表示各数据元素之间的前后件关系(即逻辑关系)数据的逻辑结构是指反映数据元素之间逻辑关系的数据结构。 数据的逻辑结构有两个要素:数据元素的集合D;反映D中各数据元素之间的前后件关系R。,数据的逻辑结构,数据结构可以表示成B(D,R) 其中B表示数据结构。为了反映D中各数据元素之间的前后件关系,一般用二元组来表示。 设a与b是D中的两个数据,则二元组(a,b)表示a是b的前件,b是a的后件。,数据的逻辑结构,例如B(D,R)D春,夏,秋,冬R(春,夏),(夏,秋),(秋,冬) 家庭成员数据结构B(D,R)D父亲,儿
6、子,女儿R(父亲,儿子),(父亲,女儿),数据的存储结构(数据的物理结构),数据的逻辑结构在计算机存储空间中的存放形式。各数据元素在计算机存储空间中的位置关系与它们的逻辑关系不一定是相同的,而且一般也不可能相同。常用的存储结构有:顺序、链接、索引等存储结构。采用不同的存储结构,其数据处理的效率是不同的。,数据结构的图形表示,数据集合D中的每一个数据元素用中间标有元素值的方框表示(数据结点,结点) 用一条有向线段从前件结点指向后件结点。如:一年四季数据结构的图形表示,家庭成员间辈份关系数据结的图形表示,用图形表示数据结构B(D,R) Ddi |1i7d1,d2,d3,d4,d5,d6,d7 R(
7、d1,d3),(d1,d7),(d2,d4),(d3 ,d6) ,(d4 ,d5 ) ,对数据结构的运算,基本运算:插入和删除 其他运算:查找、分类、合并、分解、复制和修改等。 数据结构的处理过程中,不仅结点的个数在动态地变化,而且各数据元素之间的关系也有可能在动态地变化。,线性数据结构与非线性数据结构,线性结构:(1)有且只有一个根结点;(2)每一个结点最多有一个前件,也最多有一个后件。 线性结构又称线性表。 如果一个数据结构不是线性结构,则称之为非线性结构,不是线性结构的数据结构特例,提示:在一个线性结构中插入或删除任何一个结点后还应是线性结构,空数据结构,1.3 线性表及其顺序存储结构,
8、什么是线性表 线性表的顺序存储结构 线性表在顺序存储下的插入运算 线性表在顺序存储下的删除运算,什么是线性表,n维向量(x1,x2,xn)是一个长度为n的线性表 英文小写字母表(a,b,c,z)是一个长度为26的线性表 一年中的四个季节(春,夏,秋,冬)是一个长度为4的线性表 矩阵是一个比较复杂的线性表 学生情况登记表是一个复杂的线性表,什么是线性表(定义),线性表是由n(n0)个数据元素a1,a2,an组成的一个有限序列,表中的每一个数据元素,除了第一个外,有且只有一个前件,除了最后一个外,有且只有一个后件。即线性表或是一个空表,或可以表示为(a1,a2,ai,an)其中ai(i1,2,n)
9、是属于数据对象的元素,通常也称其为线性表中的一个结点。,非空线性表结构特征,(1)有且只有一个根结点a1,它无前件;(2)有且只有一个终端结点an,它无后件;(3)除根结点与终端结点外,其它所有结点有且只有一个前件,也有且只有一个后件。线性表中结点的个数n称为线性表的长度。当n0时,称为空表。,线性表的顺序存储结构,线性表的顺序存储结构基本特点: (1)线性表中所有元素所占的存储空间是连续的; (2)线性表中各数据元素在存储空间中是按逻辑顺序依次存放的。 线性表中第i个元素ai在计算机存储空间中 的存储地址为ADR(ai)ADR(a1)(i1)k,长度为n的线性表(a1,a2,ai,an) 顺
10、序存储结构,整型一维数组存放长度为8的线性表 (29,18,56,63,35,24,31,47),顺序存储结构下线性表的运算:,插入 删除 查找 排序 分解 合并 复制 逆转原则:运算后仍保持线性表的特性,线性表在顺序存储下的插入运算,线性表在顺序存储下的删除运算,1.4 栈和队列,栈及其基本运算 队列及其基本运算,栈及其基本运算,什么是栈 栈的顺序存储及其运算,栈(stack)是限定在一端进行插入与删除的线性表。 允许插入与删除的一端称为栈顶,不允许插入与删除的另一端称为栈底。 栈是按照“先进后出” (FILOFirst In Last Out)或“后进先出” (LIFOLast In Fi
11、rst Out)的原则组织数据的,因此,栈也被称为“先进后出”表或“后进先出”表。 栈具有记忆作用。 用指针top来指示栈顶的位置,用指针bottom指向栈底。 往栈中插入一个元素称为入栈运算,从栈中删除一个元素(即删除栈顶元素)称为退栈运算。 如:主程序与子程序之间的调用关系,什么是栈,栈的顺序存储及其运算,top0表示栈空;topm表示栈满(1)入栈运算(上溢) (2) 退栈运算(下溢) (3) 读栈顶元素(不删除栈顶元素),栈的顺序存储及其运算,队列及其基本运算,什么是队列 循环队列,队列(equeue)是指允许在一端进行插入、而在另一端进行删除的线性表。 允许插入的一端称为队尾,用尾指
12、针(rear)指向队尾元素。 允许删除的一端称为排头(也称队头),用排头指针(front)指向排头元素的前一个位置。 队列又称为“先进先出” (FIFOFirst In First Out)或“后进后出” (LILOLast In Last Out)的线性表,体现了“先来先服务”的原则。 往队列的队尾插入一个元素称为入队运算,从队列的排头删除一个元素称为退队运算。,什么是队列,队列基本运算,循环队列及其运算,循环队列及其运算,循环队列的初始状态为空,即rear=front=m 入队运算:队尾指针进1,当队尾指针rear=m+1时,则置rear=1。 退队运算:排头指针进1,当排头指针front
13、=m+1时,则置front=1,队列空的条件为 s0(下溢) 队列满的条件为 (s1)且frontrear(上溢),1.5 线性链表,什么是线性表 线性链表的基本运算 循环链表,顺序存储线性表的缺点:,插入上溢共享,1.线性链表 线性表的链式存储结构称为线性链表。,线性链表的基本概念,头结点:指向线性表中第一个结点的指针HEAD称为头指针,当HEAD=NULL(或0)时称为空表。线性单链表只能顺指针向链尾方向进行扫描。,双向链表,带链的栈,带链的队列,线性链表的插入 在链式存储结构下的线性表中插入一个新元素。,线性链表的基本运算,(1)从可利用栈取得一个结点,设该结点号为p。并置结点p的数据域
14、为插入的元素值b,即V(p)b。 (2)在线性链表中寻找包含元素x的前一个结点q。,(3)将结点p插入到结点q之后:使结点p指向包含元素x的结点,即NEXT(p)NEXT(q)使结点q的指针域内容改为指向结点p,即NEXT(q)p,线性链表的删除 链式存储结构下的线性表中删除包含指定元素的结点。,(1)寻找包含元素x的前一个结点q。则包含元素x的结点序号pNEXT(q)。 (2)将结点q后的结点p删除,即NEXT(q)NEXT(p)。,(3)将包含元素x的结点p送回可利用栈。,(1)在循环链表中,只要指出表中任何一个结点的位置,就可以从它出发访问到表中其他所有的结点。 (2)空表与非空表的运算
15、统一。,循环链表,循环链表的优势:,通过任何一个结点都可以访问到其他任意结点增加了表头结点,使得空表与非空表的运算统一。,树与二叉树,树的基本概念 二叉树及其基本性质 二叉树的存储结构 二叉树的遍历,树是由n (n 0)个结点组成的有限集合。如果n = 0,称为空树;如果n 0,则: 有一个特定的称之为根的结点,它只有后继,但没有前驱; 除根以外的其它结点划分为m (m 0)个互不相交的有限集合T0, T1, , Tm-1,每个集合本身又是一棵树,并且称之为根的子树。每棵子树的根结点有且仅有一个直接前驱,但可以有0个或多个后继。,什么是树?,1)度(次数、级)(1)结点的度:一个结点所拥有的子
16、树的个数(2)树的度:树内各结点的度的最大值 2)描述上下及左右的关系孩子结点:一个结点的子树的根双亲结点:结点的直接前驱(前件)兄弟结点:同一个双亲的孩子之间互称兄弟祖先:结点的祖先是从根到该结点所经分支上的所有结点子孙:结点的后代 3)层次(1)结点的层次(2)树的深度(高度),树的基本术语,结点(node) 结点的度(degree) 分支(branch)结点 叶(leaf)结点 孩子(child)结点 双亲(parent)结点,兄弟(sibling)结点 祖先(ancestor)结点 子孙(descendant)结点 结点所处层次(level) 树的深度(depth) 树的度(degre
17、e),(1)表达式中的每一个运算符在树中对应一个结点,称为运算符结点。 (2)运算符的每一个运算对象在树中为该运算符结点的子树(在树中的顺序为从左到右)。 (3)运算对象中的单变量均为叶子结点。,表达式树,a*(bc/d)e*hg*f(s,t,xy),a*(bc/d)e*hg*f(s,t,xy),注:树在计算机中通常用多重链表表示。,(1)非空二叉树只有一个根结点;(2)每一个结点最多有两棵子树,且分别称为该结点的左子树与右子树。,什么是二叉树,性质1 在二叉树的第k层上,最多有2k1(k1)个结点。 性质2 深度为m的二叉树最多有2m1个结点。 性质3 在任意一棵二叉树中,度为0的结点(即叶
18、子结点)总是比度为2的结点多一个。 性质4 具有n个结点的二叉树,其深度至少为log2n1其中log2n表示取log2n的整数部分。,二叉树的基本性质,满二叉树,完全二叉树,若设二叉树的深度为h,则共有h层。除第h层外,其它各层(0h-1)的结点数都达到最大个数,第h层从右向左连续缺若干结点,这就是完全二叉树。,性质5 具有n个结点的完全二叉树的深度为log2n1。 性质6 设完全二叉树共有n个结点。如果从根结点开始,按层序(每一层从左到右)用自然数1,2,n给结点进行编号,则对于编号为k(k1,2,n)的结点有以下结论:(1)若k1,则该结点为根结点,它没有父结点;若k1,则该结点的父结点编
19、号为INT(k/2)。(2)若2kn,则编号为k的结点的左子结点编号为2k;否则该结点无左子结点(显然也没有右子结点)。(3)若2k1n,则编号为k的结点的右子结点编号为2k1;否则该结点无右子结点。,二叉链表,二叉树的存储结构(链表存储和顺序存储),1.前序遍历(DLR) 若二叉树为空,则结束返回。否则: (1)访问根结点; (2)前序遍历左子树; (3)前序遍历右子树。 2.中序遍历(LDR) 若二叉树为空,则结束返回。否则: (1)中序遍历左子树; (2)访问根结点; (3)中序遍历左子树。 3.后序遍历(LRD) 若二叉树为空,则结束返回。否则: (1)后序遍历左子树; (2)后序遍历
20、左子树; (3)访问根结点。,二叉树的遍历,二叉树的遍历例题,(1)已知二叉树后序遍历序列是dabec,中序遍历序列是debac,它的前序遍历序列是 A)acbed B)decab C)deabc D)cedba(2)已知一棵二叉树前序遍历和中序遍历分别为ABDEGCFH和DBGEACHF,则该二叉树的后序遍历为A)GEDHFBCA B)DGEBHFCA C)ABCDEFGH D)ACBFEDHG,1.7 查找技术,顺序查找 二分法查找,(1)如果线性表为无序表(即表中元素的排列是无序的),则不管是顺序存储结构还是链式存储结构,都只能用顺序查找。 (2)即使是有序线性表,如果采用链式存储结构,
21、也只能用顺序查找。 (3)最坏情况时间复杂度为n。,顺序查找,设有序线性表的长度为n,被查元素为x。 将x与线性表的中间项进行比较: 若中间项的值等于x,则说明查到,查找结束; 若x小于中间项的值,则在线性表的前半部分(即中间项以前的部分)以相同的方法进行查找; 若x大于中间项的值,则在线性表的后半部分(即中间项以后的部分)以相同的方法进行查找。 这个过程一直进行到查找成功或子表长度为0(说明线性表中没有这个元素)为止。 在最坏情况下,对分查找只需比较log2n次,而顺序查找需比较n次。,二分法查找,1.8 排序技术,交换类排序 插入类排序 选择类排序,首先,从表头开始往后扫描线性表,在扫描过
22、程中逐次比较相邻两个元素的大小。若相邻两个元素中,前面的元素大于后面的元素,则将它们互换,称之为消去了一个逆序。显然,在扫描过程中,不断地将两相邻元素中的大者往后移动,最后就将线性表中的最大者换到了表的最后。 然后从后到前扫描剩下的线性表,同样,在扫描过程中逐次比较相邻两个元素的大小。若相邻两个元素中,后面的元素小于前面的元素,则将它们互换,这样就又消去了一个逆序。显然,在扫描过程中,不断地将两相邻元素中的小者往前移动,最后就将剩下线性表中的最小者换到了表的最前。 对剩下的线性表重复上述过程,直到剩下的线性表变空为止,此时的线性表已经变为有序。 最坏情况下的时间复杂度为n(n-1)/2.,冒泡
23、排序,快速排序,首先,在表的第一个、中间一个与最后一个元素中选取中项,设为P(k),并将P(k)赋给T,再将表中的第一个元素移到P(k)的位置上。 然后设置两个指针i和j分别指向表的起始与最后的位置。反复作以下两步: (1)将j逐渐减小,并逐次比较P(j)与T,直到发现一个P(j)T为止,将P(j)移到P(i)的位置上。 (2)将i逐渐增大,并逐次比较P(i)与T,直到发现一个P(i)T为止,将P(i)移到P(j)的位置上。 上述两个操作交替进行,直到指针i与j指向同一个位置 (即ij)为止,此时将T移到P(i)的位置上。,简单插入排序,5 1 7 3 1 6 9 4 2 8 6 j2 1 5
24、 7 3 1 6 9 4 2 8 6 j3 1 5 7 3 1 6 9 4 2 8 6 j4 1 3 5 7 1 6 9 4 2 8 6 j5 1 1 3 5 7 6 9 4 2 8 6 j6,1 1 3 5 6 7 9 4 2 8 6 j7 1 1 3 5 6 7 9 4 2 8 6 j8 1 1 3 4 5 6 7 9 2 8 6 j9 1 1 2 3 4 5 6 7 9 8 6 j10 1 1 2 3 4 5 6 7 8 9 6 j11 1 1 2 3 4 5 6 6 7 8 9,将整个无序序列分割成若干小子序列分别进行插入排序 子序列的分割方法如下: 将相隔某个增量h的元素构成一个子序
25、列。在排序过程中,逐次减小这个增量,最后当h减到1时,进行一次插入排序,排序就完成。 增量序列一般取 htn/2k(k1,2,log2n), 其中n为待排序序列的长度。,希尔排序,简单选择排序,堆的定义: 具有n个元素的序列(h1,h2,hn), 当且仅当满足 或(i1,2,n/2)时称之为堆。 由堆的定义可以看出,堆顶元素(即第一个元素)必为最大(小)项。,堆排序,序列(91,85,53,36,47,30,24,12)是一个堆,调整建堆 在一棵具有n个结点的完全二叉树(用一维数组 H(1:n)表示)中,假设结点H(m)的左右子树均 为堆,现要将以H(m)为根结点的子树也调整为堆。,(1)首先将一个无序序列建成堆。 (2)然后将堆顶元素(序列中的最大项)与堆中最后 一个元素交换(最大项应该在序列的最后)。不考虑已经换到最后的那个元素,只考虑前n1个元素构成的子序列,显然,该子序列已不是堆,但左、右子树仍为堆,可以将该子序列调整为堆。 反复做第(2)步,直到剩下的子序列为空为止。,