数据结构(严蔚敏)第10章
第十章_排序方法(数据结构ppt-严蔚敏)
第二个问题解决方法——筛选
方法:输出堆顶元素之后,以堆中最后一个元素替代之;然 后将根结点值与左、右子树的根结点值进行比较,并与其中 小者进行交换;重复上述操作,直至叶子结点,将得到新的 堆,称这个从堆顶至叶子的调整过程为“筛选”
例 38 50 97 76
13 27 65 49 13 38
97 27 38 50 76
2 (n 4)(n 1) 记录移动次数: (i 1) 2 i 2
i 2 n
若待排序记录是随机的,取平均值 n2 关键字比较次数: T(n)=O(n² ) 4 记录移动次数:
空间复杂度:S(n)=O(1)
n2 4
折半插入排序
排序过程:用折半查找方法确定插入位置的排序叫~
初始时令i=s,j=t 首先从j所指位置向前搜索第一个关键字小于x的记录,并和rp 交换 再从i所指位置起向后搜索,找到第一个关键字大于x的记录, 和rp交换 重复上述两步,直至i==j为止 再分别对两个子序列进行快速排序,直到每个子序列只含有 一个记录为止
x 例 初始关键字: 27 49 i 完成一趟排序: ( 27 38 13 49 65 i 13) 49 97 76 j 97 49 13 j 97 65 49 27 50 j 50)
13 38
76 65 27 49
堆排序:将无序序列建成一个堆,得到关键字最小 (或最大)的记录;输出堆顶的最小(大)值后,使 剩余的n-1个元素重又建成一个堆,则可得到n个元素 的次小值;重复执行,得到一个有序序列,这个过程 叫~ 堆排序需解决的两个问题:
如何由一个无序序列建成一个堆? 如何在输出堆顶元素之后,调整剩余元素,使之成为一个新 的堆?
按排序所需工作量
数据结构教材 出版社: 清华大学出版社 作者: 严蔚敏吴伟民 ISBN ...
数据结构教材出版社:清华大学出版社作者:严蔚敏吴伟民ISBN :978-7-302-02368-5目录第1章绪论1.1 什么是数据结构1.2 基本概念和术语1.3 抽象数据类型的表现与实现1.4 算法和算法分析第2章线性表2.1 线性表的类型定义2.2 线性表的顺序表示和实现2.3 线性表的链式表示和实现2.4 一元多项式的表示及相加第3章栈和队列3.1 栈3.2 栈的应有和举例3.3 栈与递归的实现3.4 队列3.5 离散事件模拟第4章串4.1 串类型的定义4.2 串的表示和实现4.3 串的模式匹配算法4.4 串操作应用举例第5章数组和广义表5.1 数组的定义5.2 数组的顺序表现和实现5.3 矩阵的压缩存储5.4 广义表的定义5.5 广义表的储存结构5.6 m元多项式的表示5.7 广义表的递归算法第6章树和二叉树6.1 树的定义和基本术语6.2 二叉树6.2.1 二叉树的定义6.2.2 二叉树的性质6.2.3 二叉树的存储结构6.3 遍历二叉树和线索二叉树6.3.1 遍历二叉树6.3.2 线索二叉树6.4 树和森林6.4.1 树的存储结构6.4.2 森林与二叉树的转换6.4.3 树和森林的遍历6.5 树与等价问题6.6 赫夫曼树及其应用6.6.1 最优二叉树(赫夫曼树)6.6.2 赫夫曼编码6.7 回溯法与树的遍历6.8 树的计数第7章图7.1 图的定义和术语7.2 图的存储结构7.2.1 数组表示法7.2.2 邻接表7.2.3 十字链表7.2.4 邻接多重表7.3 图的遍历7.3.1 深度优先搜索7.3.2 广度优先搜索7.4 图的连通性问题7.4.1 无向图的连通分量和生成树7.4.2 有向图的强连通分量7.4.3 最小生成树7.4.4 关节点和重连通分量7.5 有向无环图及其应用7.5.1 拓扑排序7.5.2 关键路径7.6 最短路径7.6.1 从某个源点到其余各顶点的最短路径7.6.2 每一对顶点之间的最短路径第8章动态存储管理8.1 概述8.2 可利用空间表及分配方法8.3 边界标识法8.3.1 可利用空间表的结构8.3.2 分配算法8.3.3 回收算法8.4 伙伴系统8.4.1 可利用空间表的结构8.4.2 分配算法8.4.3 回收算法8.5 无用单元收集8.6 存储紧缩第9章查找9.1 静态查找表9.1.1 顺序表的查找9.1.2 有序表的查找9.1.3 静态树表的查找9.1.4 索引顺序表的查找9.2 动态查找表9.2.1 二叉排序树和平衡二叉树9.2.2 B树和B+树9.2.3 键树9.3 哈希表9.3.1 什么是哈希表9.3.2 哈希函数的构造方法9.3.3 处理冲突的方法9.3.4 哈希表的查找及其分析第10章内部排序10.1 概述10.2 插入排序10.2.1 直接插入排序10.2.2 其他插入排序10.2.3 希尔排序10.3 快速排序10.4 选择排序10.4.1 简单选择排序10.4.2 树形选择排序10.4.3 堆排序10.5 归并排序10.6 基数排序10.6.1 多关键字的排序10.6.2 链式基数排序10.7 各种内部排序方法的比较讨论第11章外部排序11.1 外存信息的存取11.2 外部排序的方法11.3 多路平衡归并的实现11.4 置换一选择排序11.5 最佳归并树第12章文件12.1 有关文件的基本概念12.2 顺序文件12.3 索引文件12.4 ISAM文件和VSAM文件12.4.1 ISAM文件12.4.2 VSAM文件12.5 直接存取文件(散列文件)12.6 多关键字文件12.6.1 多重表文件12.6.2 倒排文件附录A 名词索引附录B 函数索引参考书目。
严蔚敏版数据结构课后习题答案-完整版
第1章绪论1.1 简述下列术语:数据,数据元素、数据对象、数据结构、存储结构、数据类型和抽象数据类型。
解:数据是对客观事物的符号表示。
在计算机科学中是指所有能输入到计算机中并被计算机程序处理的符号的总称。
数据元素是数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。
数据对象是性质相同的数据元素的集合,是数据的一个子集。
数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
存储结构是数据结构在计算机中的表示。
数据类型是一个值的集合和定义在这个值集上的一组操作的总称。
抽象数据类型是指一个数学模型以及定义在该模型上的一组操作。
是对一般数据类型的扩展。
1.2 试描述数据结构和抽象数据类型的概念与程序设计语言中数据类型概念的区别。
解:抽象数据类型包含一般数据类型的概念,但含义比一般数据类型更广、更抽象。
一般数据类型由具体语言系统内部定义,直接提供给编程者定义用户数据,因此称它们为预定义数据类型。
抽象数据类型通常由编程者定义,包括定义它所使用的数据和在这些数据上所进行的操作。
在定义抽象数据类型中的数据部分和操作部分时,要求只定义到数据的逻辑结构和操作说明,不考虑数据的存储结构和操作的具体实现,这样抽象层次更高,更能为其他用户提供良好的使用接口。
1.3 设有数据结构(D,R),其中{}4,3,2,1d d d d D =,{}r R =,()()(){}4,3,3,2,2,1d d d d d d r =试按图论中图的画法惯例画出其逻辑结构图。
解:1.4 试仿照三元组的抽象数据类型分别写出抽象数据类型复数和有理数的定义(有理数是其分子、分母均为自然数且分母不为零的分数)。
解:ADT Complex{数据对象:D={r,i|r,i 为实数}数据关系:R={<r,i>}基本操作: InitComplex(&C,re,im)操作结果:构造一个复数C ,其实部和虚部分别为re和imDestroyCmoplex(&C)操作结果:销毁复数CGet(C,k,&e)操作结果:用e返回复数C的第k元的值Put(&C,k,e)操作结果:改变复数C的第k元的值为eIsAscending(C)操作结果:如果复数C的两个元素按升序排列,则返回1,否则返回0IsDescending(C)操作结果:如果复数C的两个元素按降序排列,则返回1,否则返回0Max(C,&e)操作结果:用e返回复数C的两个元素中值较大的一个Min(C,&e)操作结果:用e返回复数C的两个元素中值较小的一个}ADT ComplexADT RationalNumber{数据对象:D={s,m|s,m为自然数,且m不为0}数据关系:R={<s,m>}基本操作:InitRationalNumber(&R,s,m)操作结果:构造一个有理数R,其分子和分母分别为s和mDestroyRationalNumber(&R)操作结果:销毁有理数RGet(R,k,&e)操作结果:用e返回有理数R的第k元的值Put(&R,k,e)操作结果:改变有理数R的第k元的值为eIsAscending(R)操作结果:若有理数R的两个元素按升序排列,则返回1,否则返回0IsDescending(R)操作结果:若有理数R的两个元素按降序排列,则返回1,否则返回0Max(R,&e)操作结果:用e返回有理数R的两个元素中值较大的一个Min(R,&e)操作结果:用e返回有理数R的两个元素中值较小的一个}ADT RationalNumber1.5 试画出与下列程序段等价的框图。
数据结构严蔚敏版第十章答案
数据结构严蔚敏版第十章答案第十章:图一、概述图是一种非常重要的数据结构,它由节点(顶点)和边组成,用于描述事物之间的关系。
在本章中,我们将学习图的基本概念、表示方法和常用算法。
二、基本概念1. 顶点(节点):图中的一个元素,用于表示一个实体,如人、地点等。
2. 边:连接两个顶点的关系,可以是有向的(箭头指向一个方向)或无向的(没有箭头)。
3. 路径:由一系列顶点和边组成的序列,表示从一个顶点到另一个顶点的通路。
4. 无环图:不存在回路(从一个顶点出发,经过若干边又回到该顶点)的图。
5. 有环图:存在回路的图。
三、表示方法1. 邻接矩阵:使用二维数组来表示图的连接关系,数组的行和列分别对应图中的顶点,数组元素表示边的权重或连接状态。
2. 邻接表:使用链表来表示图的连接关系,每个顶点对应一个链表,链表中存储与该顶点相连的其他顶点。
四、图的遍历1. 深度优先搜索(DFS):从一个顶点开始,沿着一条路径尽可能深入地访问顶点,直到无法继续为止,然后回溯到上一个顶点,继续访问其他路径。
使用栈来实现。
2. 广度优先搜索(BFS):从一个顶点开始,先访问其所有相邻顶点,然后再访问相邻顶点的相邻顶点,以此类推,直到所有顶点都被访问到。
使用队列来实现。
五、最小生成树最小生成树是指在一个连通图中,选择其中的一些边,使得这些边构成一棵树,并且树上所有边的权重之和最小。
常用的算法有Prim算法和Kruskal算法。
六、最短路径最短路径是指从一个顶点到另一个顶点的路径中,路径上所有边的权重之和最小。
常用的算法有Dijkstra算法和Floyd算法。
七、拓扑排序拓扑排序是对有向无环图进行排序的一种算法。
它将图中的顶点按照一定的顺序排列,使得所有的有向边都从前面的顶点指向后面的顶点。
八、关键路径关键路径是指在一个有向无环图中,从开始顶点到结束顶点的最长路径。
关键路径上的活动不能延误,否则将影响整个工程的进度。
九、其他图算法除了上述提到的算法,还有许多其他的图算法,如最大流问题、二分图匹配等。
严蔚敏数据结构各章习题及答案
严蔚敏数据结构各章习题及答案数据结构习题及解答第1章概述【例1-1】分析以下程序段的时间复杂度。
for(i=0;i解:该程序段的时间复杂度为O (m*n )。
【例1-2】分析以下程序段的时间复杂度。
i=s=0; ① while(s<="" ②="" ③="">解:语句①为赋值语句,其执行次数为1次,所以其时间复杂度为O (1)。
语句②和语句③构成while 循环语句的循环体,它们的执行次数由循环控制条件中s 与n 的值确定。
假定循环重复执行x 次后结束,则语句②和语句③各重复执行了x 次。
其时间复杂度按线性累加规则为O (x )。
此时s 与n 满足关系式:s ≥n ,而s=1+2+3+…+x 。
所以有:1+2+3+…+x ≥n ,可以推出:x=nn 241212811+±-=+±-x 与n 之间满足x=f(n ),所以循环体的时间复杂度为O (n ),语句①与循环体由线性累加规则得到该程序段的时间复杂度为O (n )。
【例1-3】分析以下程序段的时间复杂度。
i=1; ① while(i<=n) i=2*i; ②解:其中语句①的执行次数是1,设语句②的执行次数为f (n ),则有:n n f ≤)(2。
log)得:T(n)=O(n2【例1-4】有如下递归函数fact(n),分析其时间复杂度。
fact(int n){ if(n<=1)return(1);①elsereturn(n*fact(n-1));②}解:设fact(n)的运行时间函数是T(n)。
该函数中语句①的运行时间是O(1),语句②的运行时间是T(n-1)+ O(1),其中O(1)为常量运行时间。
由此可得fact(n)的时间复杂度为O(n)。
习题1一、单项选择题1.数据结构是指(1. A )。
A.数据元素的组织形式B.数据类型C.数据存储结构D.数据定义2.数据在计算机存储器内表示时,物理地址与逻辑地址不相同的,称之为(2. C )。
数据结构课后习题答案详解(C语言版-严蔚敏)
数据结构习题集答案(C语言版严蔚敏)第2章线性表2.1 描述以下三个概念的区别:头指针,头结点,首元结点(第一个元素结点)。
解:头指针是指向链表中第一个结点的指针。
首元结点是指链表中存储第一个数据元素的结点。
头结点是在首元结点之前附设的一个结点,该结点不存储数据元素,其指针域指向首元结点,其作用主要是为了方便对链表的操作。
它可以对空表、非空表以及首元结点的操作进行统一处理。
2.2 填空题。
解:(1) 在顺序表中插入或删除一个元素,需要平均移动表中一半元素,具体移动的元素个数与元素在表中的位置有关。
(2) 顺序表中逻辑上相邻的元素的物理位置必定紧邻。
单链表中逻辑上相邻的元素的物理位置不一定紧邻。
(3) 在单链表中,除了首元结点外,任一结点的存储位置由其前驱结点的链域的值指示。
(4) 在单链表中设置头结点的作用是插入和删除首元结点时不用进行特殊处理。
2.3 在什么情况下用顺序表比链表好?解:当线性表的数据元素在物理位置上是连续存储的时候,用顺序表比用链表好,其特点是可以进行随机存取。
2.4 对以下单链表分别执行下列各程序段,并画出结果示意图。
解:2.5 画出执行下列各行语句后各指针及链表的示意图。
L=(LinkList)malloc(sizeof(LNode)); P=L;for(i=1;i<=4;i++){P->next=(LinkList)malloc(sizeof(LNode));P=P->next; P->data=i*2-1;}P->next=NULL;for(i=4;i>=1;i--) Ins_LinkList(L,i+1,i*2);for(i=1;i<=3;i++) Del_LinkList(L,i);解:2.6 已知L是无表头结点的单链表,且P结点既不是首元结点,也不是尾元结点,试从下列提供的答案中选择合适的语句序列。
a. 在P结点后插入S结点的语句序列是__________________。
数据结构严蔚敏(全部章节814张PPT)-(课件)
② 线性结构:结构中的数据元素之间存在一对一的 关系。
③ 树型结构:结构中的数据元素之间存在一对多的 关系。
④ 图状结构或网状结构:结构中的数据元素之间存 在多对多的关系。
图1-3 四类基本结构图
1.1.3 数据结构的形式定义
数据结构的形式定义是一个二元组: Data-Structure=(D,S)
计算机求解问题的一般步骤
编写解决实际问题的程序的一般过程:
– 如何用数据形式描述问题?—即由问题抽象出一个 适当的数学模型; – 问题所涉及的数据量大小及数据之间的关系; – 如何在计算机中存储数据及体现数据之间的关系? – 处理问题时需要对数据作何种运算? – 所编写的程序的性能是否良好? 上面所列举的问题基本上由数据结构这门课程来回答。
其中:D是数据元素的有限集,S是D上关系的有限集。 例2:设数据逻辑结构B=(K,R)
K={k1, k2, …, k9} R={ <k1, k3>,<k1, k8>,<k2, k3>,<k2, k4>,<k2, k5>,<k3, k9>, <k5, k6>,<k8, k9>,<k9, k7>,<k4, k7>,<k4, k6> } 画出这逻辑结构的图示,并确定那些是起点,那些是终点
<基本操作名>(<参数表>) 初始条件: <初始条件描述> 操作结果: <操作结果描述>
– 初始条件:描述操作执行之前数据结构和参数应 满足的条件;若不满足,则操作失败,返回相应的出 错信息。
数据结构,清华大学出版社,严蔚敏吴伟民编著
第一章绪论之五兆芳芳创作1、数据结构是计较机中存储、组织数据的方法.精心选择的数据结构可以带来最优效率的算法.2、程序设计=算法+数据结构3、解决问题办法的效率:●跟数据的组织方法有关●跟空间的利用效率有关●跟算法的巧妙程度有关4、数据:所有能输入到计较机中,且被计较机处理的符号的荟萃,是计较机操纵对象的总称;是计较机处理的信息的某种特定的符号暗示形式.5、数据元素:数据中的一个“个别”,数据结构中讨论的根本单位.相当于“记实”,在计较机程序中通常作为一个整体考虑和处理.6、数据项: 相当于记实的“域”, 是数据的不成联系的最小单位,如学号.数据元素是数据项的荟萃.7、数据对象:性质相同的数据元素的荟萃.例如: 所有运动员的记实荟萃8、数据结构:是相互间存在某种关系的数据元素荟萃.9、数据结构是带结构的数据元素的荟萃.10、不合的关系组成不合的结构.11、次序关系:{<ai,ai+1>|i=1,2,3,4,5,6}12、对每种数据结构,主要讨论如下两方面的问题:1)数据的逻辑结构,数据结构的根本操纵;2)数据的存储结构,数据结构根本操纵的实现;13、数据的逻辑结构:数据之间的结构关系,是具体关系的抽象.数据结构的根本操纵:指对数据结构的加工处理.14、数据的存储结构(物理结构):数据结构在计较机内存中的暗示.数据结构根本操纵的实现:根本操纵在计较机上的实现(办法).15、数据结构的有关概念16、数据元素的4类的根本结构:○1荟萃;○2线性结构:结构中数据元素之间存在一对一的关系;○3树形结构:结构中数据元素之间存在一对多的关系;○4图状结构或网状结构:结构中数据元素之间存在多对多的关系.17、C语言的优点:C语言可以直接操纵内存.18、每个节点都由两部分组成:数据域和指针域.19、链接存储结构特点:●比顺序存储结构的存储密度小(每个节点都由数据域和指针域组成).●逻辑上相邻的节点物理上不必相邻.●拔出、删除灵活(不必移动节点,只要改叛变点中的指针).20、数据类型是一个值的荟萃和定义在此荟萃上的一组操纵的总称.21、ADT 有两个重要特征:数据抽象和数据封装.22、抽象数据类型(Abstract Data Type 简称ADT):是指一个数学模型以及定义在此数学模型上的一组操纵.23、抽象数据类型有:数据对象〈数据对象的定义〉、数据关系〈数据关系的定义〉、根本操纵〈根本操纵的定义〉.24、数据类型的定义和寄义.定义:数据类型是一个值的荟萃和定义在这个值集上的一组操纵的总称.寄义:将数据按一定次序与形式存放的结构.24、算法空间庞杂度S(n)算法的存储量包含:①输入数据所占的空间;②程序自己所占的空间;③帮助变量所占的空间.25、算法具有有穷性、确定性、可行性、输入和输出五大特性.26、抽象数据类型具有数据抽象、数据封装的特点.27、数据的储存结构分为:顺序存储结构和链式存储结构.第二章线性表1、线性结构的特点:在数据元素中的非空有限集中.(1)存在唯一的一个被称作“第一”的数据元素;(2)存在唯一的一个被称作“最后一个”的数据元素;(3)除第一个外,荟萃中的每一个数据元素均只有一个前驱;(4)除最后一个外,荟萃中的每一个数据元素均只有一个后继.2、线性表(Linear List) :一个线性表是n个数据元素的有限序列.3、线性表的顺序存储实现:typedef struct {ElementType Data[MAXSIZE];int Last;} List;List L, *PtrL;4、初始化(成立空的顺序表)List *MakeEmpty( ){ List *PtrL;PtrL = (List *)malloc( sizeof(List) );PtrL->Last = -1;return PtrL;}5、查找int Find( ElementType X, List *PtrL ){ int i = 0;while( i <= PtrL->Last && PtrL->Data[i]!= X )i++;if (i > PtrL->Last) return -1; /* 如果没找到,前往-1 */else return i; /* 找到后前往的是存储位置*/}6、拔出算法void Insert( ElementType X, int i, List *PtrL ){ int j;if ( PtrL->Last == MAXSIZE-1 ){ /* 表空间已满,不克不及拔出*/printf("表满");return;}if ( i < 1 || i > PtrL->Last+2) { /*查抄拔出位置的正当性*/printf("位置不正当");return;}for ( j = PtrL->Last; j >= i-1; j-- )PtrL->Data[j+1] = PtrL->Data[j]; /*将ai~an 倒序向后移动*/PtrL->Data[i-1] = X; /*新元素拔出*/PtrL->Last++; /*Last仍指向最后元素*/return;}7、删除算法void Delete( int i, List *PtrL ){ int j;if( i < 1 || i > PtrL->Last+1 ) { /*查抄空表及删除位置的正当性*/printf (“不存在第%d个元素”, i );return ;}for ( j = i; j <= PtrL->Last; j++ )PtrL->Data[j-1] = PtrL->Data[j]; /*将ai+1~an顺序向前移动*/PtrL->Last--; /*Last仍指向最后元素*/return;}8、求表长int Length ( List *PtrL ){ List *p = PtrL; /* p指向表的第一个结点*/ int j = 0;while ( p ) {p = p->Next;j++; /* 当前p指向的是第j 个结点*/}return j;}9、查找(1)顺次号查找: FindKth;List *FindKth( int K, List *PtrL ){ List *p = PtrL;int i = 1;while (p !=NULL && i < K ) {p = p->Next;i++;}if ( i == K ) return p;/* 找到第K个,前往指针*/else return NULL;/* 不然前往空*/}(2)按值查找: FindList *Find( ElementType X, List *PtrL ){List *p = PtrL;while ( p!=NULL && p->Data != X )p = p->Next;return p;}10、拔出(在链表的第i-1(1≤i≤n+1)个结点后拔出一个值为X 的新结点)List *Insert( ElementType X, int i, List *PtrL ){ List *p, *s;if ( i == 1 ) { /* 新结点拔出在表头*/s = (List *)malloc(sizeof(List)); /*申请、填装结点*/s->Data = X;s->Next = PtrL;return s; /*前往新表头指针*/}p = FindKth( i-1, PtrL ); /* 查找第i-1个结点*/if ( p == NULL ) { /* 第i-1个不存在,不克不及拔出*/printf("参数i错");return NULL;}else {s = (List *)malloc(sizeof(List)); /*申请、填装结点*/s->Data = X;s->Next = p->Next; /*新结点拔出在第i-1个结点的前面*/p->Next = s;return PtrL;}}11、删除(删除链表的第i (1≤i≤n)个位置上的结点)List *Delete( int i, List *PtrL ){ List *p, *s;if ( i == 1 ) { /* 若要删除的是表的第一个结点*/s = PtrL; /*s指向第1个结点*/PtrL = PtrL->Next; /*从链表中删除*/free(s); /*释放被删除结点*/return PtrL;}p = FindKth( i-1, PtrL ); /*查找第i-1个结点*/if ( p == NULL ) {printf(“第%d个结点不存在”, i-1); return NULL;} else if ( p->Next == NULL ){printf(“第%d个结点不存在”, i); return NULL;} else {s = p->Next; /*s指向第i个结点*/p->Next = s->Next; /*从链表中删除*/free(s); /*释放被删除结点*/return PtrL;}}12、链表不具备的特点是 1 .①可随机拜访任一节点②拔出删除不须要移动元素③不必事先估量存储空间④所需空间与其长度成正比13、带头结点的单链表head为空的判定条件是 2 .①head==NULL ②head->next==NULL③head->next==head ④head!=NULL14、如果最经常使用的操纵是取第i个结点及其前驱,则采取 4 存储方法最节省时间.①单链表②双链表③单循环链表④顺序表第三章Chapter 3 栈(stacks)和队列(queues)1、栈是限定仅能在表尾一端进行拔出、删除操纵的线性表.2、栈的特点是“落后栈的元素先出栈”(last in, first out),故栈又称为落后先出表(LIFO).3、一个栈是一些元素的线形列表,其中元素的拔出和删除均在表的同一端进行.拔出和删除产生的一端称为栈顶(the top of the stack).4、第一个进栈的元素在栈底,最后一个进栈的元素在栈顶,第一个出栈的元素为栈顶元素,最后一个出栈的元素为栈底元素.5、连续栈(Contiguous Stack)的类型定义#define MaxStack 50Typedef struct{datatype stack[MaxStack];int top;}Seqstack;Seqstack *s;6、判断栈是否已满?viod Push(Seqstack *s, datatype x ){if (s->top>=MaxStack-1) printf(“ overflow” );else {s-> top++;s->stack[s->top]=x;}}7、判断栈是否为空?datatype pop(Seqstack *s ){ if (s->top<0){printf(“underflow”); return(NULL);}return(s->stack[s->top]);s->top--;}8、前往栈顶元素的值,栈不产生变更.datatype top(Seqstack *s ){ if (s->top<0){printf(“underflow”); return(NULL);}return(s->stack[s->top]);}9、链栈(Linked Stack)的类型定义栈的链式存储结构称为链栈,它是运算受限的单链表,拔出和删除操纵仅限制在表头位置上进行.由于只能在链表头部进行操纵,故链表没有需要像单链表那样附加头结点.栈顶指针就是链表的头指针.链栈的类型说明如下:typedef struct stacknode {datatype datastruct stacknode *next}stacknode10、链式栈的特点:链式栈无栈满问题;空间可扩充;拔出与删除仅在栈顶处执行;链式栈的栈顶在链头;适合于多栈操纵.11、栈是限定仅能在表的一端进行拔出、删除操纵的线性表.12、栈的元素具有落后先出的特点.13、栈顶元素的位置由栈顶指针的指示, 进栈、出栈操纵要修改栈顶指针.14、抽象数据类型队列的定义:队列(Queue)也是一种运算受限的线性表.它只允许在表的一端进行拔出,而在另一端进行删除.允许删除的一端称为队头(front),允许拔出的一端称为队尾(rear).15、队列亦称作先进先出(First In First Out)的线性表,简称FIFO表.16、双端队列:就是限定拔出和删除操纵在表的两端进行的线性表.17、链队列结点定义:typedef struct Qnode{ QElemType data;struct QNode *next;} QNode,*QueuPtr;18、队列的顺序存储结构称为顺序队列,在队列的顺序存储结构中,除了用一组地址连续的储存单元依次存放从队头到队尾的元素之外,尚需要附设两个指针front和rear 辨别指示队列头元素和队列尾元素的位置.19、在非空队列中,头指针始终指向队头元素,而尾指针始终指向队尾元素的下一位置.20、栈的特点是先进后出,队列的特点是先进后出.21、栈和队列的配合特点是只允许在端点处拔出和删除元素.22、一个栈的进栈序列是a,b,c,d,e,则栈的不成能的输出序列是C .(A)edcba (B)decba (C)dceab (D)abcde23、若已知一个栈的进栈序列是p1,p2,p3,…,pn .其输出序列为1,2,3,…,n ,若p3=1,则p1为 C .(A)可能是2(B)一定是2(C)不成能是2 (D)不成能是324、设有一个空栈,栈顶指针为1000H(十六进制,下同),现有输入序列为1、2、3、4、5,经过PUSH,PUSH,POP,PUSH,POP,PUSH,PUSH后,输出序列是3,栈顶指针是8.①5、4、3、2、1 ②2、1 ③2、3④3、4 ⑤1002H ⑥1004H⑦1005H ⑧1003H24、一个队列的入队序列是若1,2,3,4,则队列的输出序列是 B .(A)4,3,2,1 (B)1,2,3,4(C)1,4,3,2 (D)3,2,4,125、若用一个大小为6的一维数组来实现循环队列,且当前rear和front的值辨别为0和3.当从队列中删除一个元素,再参加两个元素后,rear和front的值辨别是 B .(A)1和5 (B)2和4 (C)4和2 (D)5和126、有5个元素,其入栈次序为A、B、C、D、E,在各类可能的出栈次序中,以元素C、D最先出栈(即C第一个且D第二个出栈)的次序有哪几个?C、D、B、A、E C、D、E、B、AC、D、B、E、A第六章树和二叉树1、树型结构是一类重要的非线性结构.2、树的定义:树是n(n>=0)个结点的有限集T,T为空时称为空树,不然它满足如下两个条件:(1)有且仅有一个特定的称为根的结点;(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,T3…Tm,其中每个子集又是一棵树,并称其为根的子树.3、根本术语结点——暗示树中的元素,包含数据项及若干指向其子树的分支结点的度(degree)——结点拥有的子树数叶子(leaf)——度为0的结点孩子(child)——结点子树的根称为该结点的孩子双亲(parents)——孩子结点的上层结点叫该结点的~兄弟(sibling)——同一双亲的孩子树的度——一棵树中最大的结点度数结点的条理(level)——从根结点算起,根为第一层,它的孩子为第二层……深度(depth)——树中结点的最大条理数森林(forest)——m(m0)棵互不相交的树的荟萃例题:4、二叉树是由n(n>=0)个结点的有限荟萃组成,此荟萃或为空集,或由一个根结点及两棵互不相交的左右子树组成,并且左右子树都是二叉树.二叉树可以是空荟萃,根可以有空的左子树或空的右子树.性质1: 在二叉树的第i层上至多有2i-1个结点(i>=1).性质2:深度为k的二叉树至多有2k-1个结点(k>=1).性质3:对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1.性质4:具有n个结点的完全二叉树的深度为log2n+1.性质5:如果对一棵有n个结点的完全二叉树的结点按层序编号(从第1层到第log2n +1层,每层从左到右),则对任一结点i(1<=i<=n),有:(1)如果i=1,则结点i无双亲,是二叉树的根;如果i>1,则其双亲是结点i/2.(2)如果2i>n,则结点i为叶子结点,无左孩子;不然,其左孩子是结点2i.(3)如果2i+1>n,则结点i无右孩子;不然,其右孩子是结点2i+1.一棵深度为k且有2k-1个结点的二叉树称为满二叉树.如:5、二叉树的存储结构●顺序存储结构define MAX-TREE-SIZE 100Typedef TelemType SqBiTree[ MAX-TREE-SIZE];SqBitree bt;缺点是有可能对存储空间造成极大的浪费.●链式存储结构二叉链式存储结构typedef struct BiTNode{ TElemType data;struct BiTNode *lchild, *rchild;}BiTNode,*BiTree;三叉链表typedef struct node{ datatype data;struct node *lchild, *rchild, *parent;}JD;6、遍历二叉树二叉树是由三个根本单元组成:根结点、左子树和右子树.若限定先左后右,则只有前三种情况,辨别称之为先(根)序遍历,中(根)序遍历和后(根)序遍历.(1)先序遍历算法若二叉树为空树,则空操纵;不然,●拜访根结点;●先序遍历左子树;●先序遍历右子树.void PreOrder(BiTree bt){/*先序遍历二叉树bt*/if (bt==NULL) return; /*递归调用的结束条件*/Visite(bt->data); /*(1)拜访结点的数据域*/PreOrder(bt->lchild); /*(2)先序递归遍历bt的左子树*/ PreOrder(bt->rchild);/*(3)先序递归遍历bt的右子树*/}例题:先序遍历序列:A B D Cvoid preorder(JD *bt){ if(bt!=NULL){ printf("%d\t",bt->data);preorder(bt->lchild);preorder(bt->rchild);}}(2)中序遍历算法若二叉树为空树,则空操纵;不然,●先序遍历左子树;●拜访根结点;●先序遍历右子树.void InOrder(BiTree bt){/*先序遍历二叉树bt*/if (bt==NULL) return; /*递归调用的结束条件*/InOrder(bt->lchild); /*(2)先序递归遍历bt的左子树*/ Visite(bt->data); /*(1)拜访结点的数据域*/InOrder(bt->rchild);/*(3)先序递归遍历bt的右子树*/}例题:中序遍历序列:B D A C(3)后序遍历算法若二叉树为空树,则空操纵;不然,●先序遍历左子树;●先序遍历右子树;●拜访根结点.void PostOrder(BiTree bt){/*后序遍历二叉树bt*/if (bt==NULL) return; /*递归调用的结束条件*/PostOrder(bt->lchild);/*(1)后序递归遍历bt的左子树*/PostOrder(bt->rchild); /*(2)后序递归遍历bt的右子树Visite(bt->data); /*(3)拜访结点的数据域*/}例题:后序遍历序列:D B C A(4)条理遍历所谓二叉树的条理遍历,是指从二叉树的第一层(根结点)开始,从上至下逐层遍历,在同一层中,则按从左到右的顺序对结点逐个拜访.条理遍历序列:1 2 3 4 5 67、例题:1、先序序列:A B C D E F G H K中序序列:B D C A E H G K F后序序列:D C B H K G F E K条理序列:A B E C F D G H K2、若先序遍历此二叉树,按拜访结点的先后次序将结点排列起来,其先序序列为:-+a*b-cd/ef按中序遍历,其中序序列为:a+b*c-d-e/f按后序遍历,其后序序列为:abcd-*+ef/ -8、(1)查询二叉树中某个结点Status Preorder (BiTree T, ElemType x, BiTree &p) {// 若二叉树中存在和x 相同的元素,则p 指向该结点并//前往OK,// 不然前往FALSEif (T) {if (T->data= =x) { p = T; return OK,}else {if (Preorder(T->lchild, x, p))return OK;else (Preorder(T->rchild, x, p)) return OK;}//else}//ifelse return FALSE;}(2)计较二叉树中叶子结点的个数int CountLeaf (BiTree T){//前往指针T所指二叉树中所有叶子结点个数if (!T ) return 0;if (!T->lchild && !T->rchild) return 1;else{m = CountLeaf( T->lchild);n = CountLeaf( T->rchild);return (m+n);} //else } // CountLeaf(3)求二叉树的深度(后序遍历)int Depth (BiTree T ){ // 前往二叉树的深度if ( !T ) depthval = 0; else {depthLeft = Depth( T->lchild );depthRight= Depth( T->rchild );depthval = 1 + (depthLeft > depthRight ?depthLeft : depthRight);}return depthval;}(4)按先序遍历序列成立二叉树Status CreateBiTree (BiTree &T ){ //按先序次序输入二叉树中结点的值(一个字符),空格字符暗示空树,机关二叉链表暗示的二叉树Tscanf (&ch);if ( ch==‘‘ ) T=NULL; else {if(!T=(BiTNode *)malloc(sizeof(BiTNode)))) exit (OVERFLOW);T->data=ch; //生成根结点CreateBiTree(T->lchild);//机关左子树CreateBiTree(T->rchild);//机关右子树}Return OK; }//CreateBiTree9、遍历二叉树的非递归算法(1)先序遍历二叉树的非递归算法void inorder(JD *r)//先序遍历二叉树非递归算法// { int i=0; JD *p,*s[M]; p=r;do {while(p!=NULL) {printf("%d\t",p->data);if (p->rc!=NULL)s[i++]=p->rc;p=p->lc;}if ( i > 0) p=s[--i];}while( i>0 || p!=NULL); }(2)中序遍历二叉树的非递归算法void inorder(JD *r)//先序遍历二叉树非递归算法// { int i=0; JD *p,*s[M]; p=r;do {while(p!=NULL) {{s[i++]=p; p=p->lc;}if (i>0){p=s[--i];printf("%d\t",p->data);p=p->lc;}if ( i > 0) p=s[--i];}while( i>0 || p!=NULL); }(3)后序遍历二叉树的非递归算法void inorder(JD *r)//先序遍历二叉树非递归算法//{ int s2[M],b,i=0; JD *p,*s1[M]; p=r;do {while(p!=NULL) {{s1[i-1]=p;s2[i++]=0;p=p->lc;}while (i>0 && (s2[i-1]=1)){p=s1[--i]; printf(“%d\t”,p->data ); }if (i>0){p=s[--i];printf("%d\t",p->data);p=p->lc;}if ( i > 0){ s2[i-1]=1; p=s1[i-1]; p=p->rc; }}while( i>0); }11、线索二叉树:以二叉链表作为存储结构时,只能找到结点的左右孩子的信息,而不克不及在结点的任一序列的前驱与后继信息,这种信息只有在遍历的动态进程中才干得到,为了能保管所需的信息,可增加标记域;Ltag=0 ,lchild 域指示结点的左孩子;Ltag=1,lchild 域指示结点的前驱.Rtag=0,rchild 域指示结点的右孩子;Rtag=1,rchild 域指示结点的后驱.以这种结构组成的二叉链表作为二叉树的存储结构,叫做线索链表,其中指向结点前驱与后继的指针叫做线索,加上线索的二叉树称之为线索二叉树.(1)先序线索二叉树(2)中序线索二叉树(3)后序线索二叉树12、树的存储结构○1双亲暗示法#define MAX_TREE_SIZE 100typedef struct PTNode {//结点结构ElemType data;int parent; // 双亲位置域} PTNode;typedef struct {//树结构PTNode nodes[MAX_TREE_SIZE];int r, n; // 根结点的位置和结点个数} PTree;○2孩子暗示法○3带双亲的孩子链表○4孩子兄弟暗示法链表中每个结点的两个指针域辨别指向其第一个孩子结点和下一个兄弟结点.typedef struct node{ datatype data;struct node *fch, *nsib;}JD;13、树和森林与二叉树的转换加线:在兄弟之间加一连线.抹线:对每个结点,除了其左孩子外,去除其与其余孩子之间的关系,旋转:以树的根结点为轴心,将整树顺时针转45°.13、将二叉树转换成树●加线:若p结点是双亲结点的左孩子,则将p的右孩子,右孩子的右孩子,……沿分支找到的所有右孩子,都与p的双亲用线连起来.●抹线:抹掉原二叉树中双亲与右孩子之间的连线●调整:将结点按条理排列,形成树结构14、森林转换二叉树(1)将各棵树辨别转换成二叉树.(2)将每棵树的根结点用线相连.(3)以第一棵树根结点为二叉树的根,再以根结点为轴心,顺时针旋转,组成二叉树型结构14、二叉树转换成森林抹线:将二叉树中根结点与其右孩子连线,及沿右分支搜索到的所有右孩子间连线全部抹掉,使之酿成孤立的二叉树.复原:将孤立的二叉树复原成15、树和森林的遍历树的遍历两种次序遍历树的办法:一种是先根(次序)遍历树,即先拜访树的根结点,然后依次先根遍历根的每棵子树;一种是后根(次序)遍历,即先依次后根遍历每棵子树,然后拜访根结点.森林的遍历先序遍历:A B C D E F G H I J中序遍历:B C D A F E H J I G16、赫夫曼树及其应用例题:w={5, 29, 7, 8, 14, 23, 3, 11}习题:1、由于二叉树中每个结点的度最大为2,所以二叉树是一种特殊的树,这种说法B .(A)正确(B)错误2、某二叉树的先序遍历序列和后序遍历序列正好相反,则该二叉树一定是D .(A)空或只有一个结点(B)完全二叉树(C)二叉排序树(D)高度等于其节点数3、深度为5的二叉树至多有C 个结点.(A)16 (B)32 (C)31 (D)104、按照使用频率为5个字符设计的赫夫曼编码不成能是C .(A)111,110,10,01,00(B)000,001,010,011,1(C)100,11,10,1,0(D)001,000,01,11,105、树和二叉树的主要不同是(1)树的结点个数至少为1,而二叉树的结点个数可以为0(2)树中结点的最大度数没有限制,而二叉树结点的最大度数为2(3)树的结点无左、右之分,而二叉树的结点右左、右之分.6、深度为k的完全二叉树至少有个结点,至多有个结点,若按自上而下,从左到右次序给结点编号(从1开始),则编号最小的叶子结点的编号.7、一棵二叉树的第i(i1)层最多有个结点;一棵有n(n>0)个结点的满二叉树共有个叶子结点和个非叶子结点.8、已知二叉树的先序、中序和后序序列辨别如下,其中有一些看不清的字母用*暗示,请机关出一棵适合条件的二叉树并画出该二叉树.●先序序列是:*BC**FG●中序序列是:CB*EAG*●后序序列是:*EDB*FA9、将右图所示的树转化为二叉树,并写出先序遍历,中序遍历和后序遍历的结果.解:先序:ABEFGCDHI中序:EFGBCHIDA后序:GFEIHDCBA10、设给定权集w={2,3,4,7,8,9},试机关关于w的一棵赫夫曼树,并求其加权路径长度WPL.WPL=(9+7+8)*2+4*3+(2+3)*4=80第十章内部排序1、内排序大致可分为五类:拔出排序、互换排序、选择排序、归并排序和分派排序.2、直接拔出排序直接拔出的算法实现void sort(NODE array[],int n)//待排序元素用一个数组array[ ] 暗示,数组有n 个元素 { int i, j;NODE x; // x 为中间结点变量for ( i=1; i<n; i++) //i 暗示拔出次数,共进行n-1次拔出{ x=array[i]; //把待排序元素赋给 xj=i-1;while ((j>=0)&& ( x.key<array[j].key)){array[j+1]=array[j]; j--; } // 顺序比较和移动 array[j+1]=x; }}例如,n=6,数组R 的六个排序码辨别为:17,3,25,14,20,9.它的直接拔出排序的执行进程如图7-1所示. 直接拔出排序的时间庞杂度为O (n2). 直接拔出算法的元素移动是顺序的,该办法是稳定的. 3、希尔排序 希尔排序的时间庞杂性在O (nlog2n )和O (n2 )之间,大致为O (n1.3).由于希尔排序对每个子序列单独比较,在比较时进行元素移动,有可能改动相同排序码元素的原始顺序,因此希尔0 1 2 3 4 5初始状态 (17 ) 3 25 14 20 9 第一次插入 (3 17 ) 25 14 20 9 第二次插入 (3 17 25 ) 14 20 9 第三次插入 (3 14 17 25 ) 20 9 第四次插入 (3 14 17 20 25 ) 9第五次插入 (3 9 14 17 20 25)图10-1直接插入排序示例排序是不稳定的.例如,n=8,数组array[ ]的八个元素辨别为:91,67,35,62,29,72,46,57.下面用图10-2给出希尔排序算法的执行进程.4、互换排序1)冒泡排序冒泡排序的算法实现void Bubblesort( NODE array[],int n){ int i, j, flag; //当flag为0则停止排序NODE temp;for ( i=1; i<n; i++) // i 暗示趟数,最多n-1趟{ flag=0; //开始时元素未互换for ( j=n-1; j>=i; j--)if (array[j].key<array[j-1].key) //产生逆序temp=array[j];array[j]=array[j-1];array[j-1]=temp;flag=1; } //互换,并标识表记标帜产生了互换if(flag==0) break; }}例如,n=6,数组R的六个排序码辨别为:17,3,25,14,20,9.下面用图10-3给出冒泡排序算法的执行进程.冒泡排序算法的时间庞杂度为O(n2).由于其中的元素移动较多,所以属于内排序中速度较慢的一种.因为冒泡排序算法只进行元素间的顺序移动,所以是一个稳定的算法.2)快速排序快速排序(Quick Sorting)是迄今为止所有内排序算法中速度最快的一种.快速排序的算法实现void quicksort(NODE array[],int start , int end){ int i , j; NODE mid;if (start>=end) return;i=start;j=end;mid=array[i];while (i<j){ while (i<j && array[j].key>mid.key) j--;if (i<j) {array[i]=array[j]; i++; }while (i<j && array[i].key<=mid.key) i++;if (i<j) {array[j]=array[i]; j--; } } //一次划分得到基准值的正确位置array[i]=mid;quicksort(array,start,i-1); //递归调用左子区间quicksort(array,i+1,end); }//递归调用右子区间例如,给定排序码为:(46,55,13,42,94,05,17,70),具体划分如图10-4所示.快速排序所占用的帮助空间为栈的深度,故最好的空间庞杂度为O(log2n),最坏的空间庞杂度为O(n).快速排序是一种不稳定的排序办法.5、选择排序1)直接选择排序例如,给定n=8,数组R中的8个元素的排序码为:(8,3,2,1,7,4,6,5),则直接选择排序进程如图7-5所示.直接选择排序的时间庞杂度为O(n2)数量级2)树形选择排序例如,给定排序码头50,37,66,98,75,12,26,49,树形选择排序进程见图7-7.3)堆排序例如,给定排序码49,38,65,97,76,13,27,70,成立初始堆的进程如图7-8所示.按条理遍历完全二叉树,得到一个由大到小排列的有序序列:97,76,70,65,49,38,27,13每次筛选运算的时间庞杂度为O(log2n),故整个堆排序进程的时间庞杂度为O(nlog2n).5、归并排序例如,给定排序码46,55,13,42,94,05,17,70,二路归并排序进程如图7-10所示.二路归并排序的时间庞杂度为O(nlog2n).6、各类内排序办法的比较和选择1)从时间庞杂度比较从平均时间庞杂度来考虑,直接拔出排序、冒泡排序、直接选择排序是三种复杂的排序办法,时间庞杂度都为O(n2),而快速排序、堆排序、二路归并排序的时间庞杂度都为O(nlog2n),希尔排序的庞杂度介于这两者之间.若从最好的时间庞杂度考虑,则直接拔出排序和冒泡排序的时间庞杂度最好,为O(n),其它的最好情形同平均情形相同.若从最坏的时间庞杂度考虑,则快速排序的为O(n2),直接拔出排序、冒泡排序、希尔排序同平均情形相同,但系数大约增加一倍,所以运行速度将下降一半,最坏情形对直接选择排序、堆排序和归并排序影响不大.2)从空间庞杂度比较归并排序的空间庞杂度最大,为O(n),快速排序的空间庞杂度为O(log2n),其它排序的空间庞杂度为O(1).3)从稳定性比较直接拔出排序、冒泡排序、归并排序是稳定的排序办法,而直接选择排序、希尔排序、快速排序、堆排序是不稳定的排序办法.4)从算法复杂性比较直接拔出排序、冒泡排序、直接选择排序都是复杂的排序办法,算法复杂,易于理解,而希尔排序、快速排序、堆排序、归并排序都是改良型的排序办法,算法比复杂排序要庞杂得多,也难于理解.8、各类内排序办法的选择1)从时间庞杂度选择对元素个数较多的排序,可以选快速排序、堆排序、归并排序,元素个数较少时,可以选复杂的排序办法.2)从空间庞杂度选择尽量选空间庞杂度为O(1)的排序办法,其次选空间庞杂度为O(log2n)的快速排序办法,最后才选空间庞杂度为O(n)二路归并排序的排序办法.3)一般选择法则●当待排序元素的个数n较大,排序码散布是随机,而对稳定性不做要求时,则采取快速排序为宜.●当待排序元素的个数n大,内存空间允许,且要求排序稳定时,则采取二路归并排序为宜.●当待排序元素的个数n大,排序码散布可能会出现正序或逆序的情形,且对稳定性不做要求时,则采取堆排序或二路归并排序为宜.●当待排序元素的个数n小,元素根本有序或散布较随机,。
严蔚敏《数据结构》(C语言版)笔记和习题(含考研真题)详解
第 1 章 绪 论............................................................................................................................................... 4 1.1 复习笔记 .......................................................................................................................................... 4 1.2 强化习题详解 ................................................................................................................................... 7 1.3 考研真题与典型题详解 ................................................................................................................... 22
第 4 章 串................................................................................................................................................... 114 4.1 复习笔记 ....................................................................................................................................... 114 4.2 强化习题详解 ................................................................................................................................ 118 4.3 考研真题与典型题详解 ..................................................................................................................138
数据结构严蔚敏PPT(完整版)
时间复杂度是衡量算法效率的重要指标,常见的 排序算法的时间复杂度有O(n^2)、O(nlogn)、 O(n)等。
查找的基本概念和算法
查找的基本概念
查找是指在一个已经有序或部分 有序的数据集合中,找到一个特 定的元素或一组元素的过程。
常见查找算法
常见的查找算法包括顺序查找 、二分查找、哈希查找等。
先进先出(FIFO)的数据 处理。
并行计算中的任务调度。
打印机的打印任务管理。
二叉树的层序遍历(宽度 优先搜索,BFS)。
04
树和图
树的基本概念和性质
树的基本概念
树是一种非线性数据结构,由节 点和边组成,其中节点表示实体 ,边表示实体之间的关系。
树的性质
树具有层次结构,节点按照层次 进行排列,每个节点最多只能有 一个父节点,除了根节点外。
isEmpty:判断队列是否为空。
enqueue:向队尾添加一个元素。
front 或 peek:查看队首元素。
dequeue:删除队首的元素。
栈和队列的应用
栈的应用 后进先出(LIFO)的数据处理。
括号匹配问题。
栈和队列的应用
队列的应用
深度优先搜索(DFS)。 表达式求值。
01
03 02
栈和队列的应用
数据结构严蔚敏ppt( 完整版)
contents
目录
• 绪论 • 线性表 • 栈和队列 • 树和图 • 排序和查找 • 数据结构的应用案例分析
01
绪论
数据结构的基本概念
总结词
数据结构是计算机存储和组织数据的方式,是算法和数据操 作的基础。
详细描述
数据结构是计算机科学中研究数据的组织和存储方式的学科 ,它决定了数据在计算机中的表示和关系。数据结构不仅包 括数据的逻辑结构,还涉及到数据的物理存储方式以及数据 的操作方式。
数据结构C语言版(第2版)严蔚敏人民邮电出版社课后习题答案
数据结构( C语言版)(第 2版)课后习题答案李冬梅2015.3目录第 1 章绪论 (1)第 2 章线性表 (5)第 3 章栈和队列 (13)第 4 章串、数组和广义表 (26)第 5 章树和二叉树 (33)第 6 章图 (43)第 7 章查找 (54)第 8 章排序 (65)第1章绪论1.简述下列概念:数据、数据元素、数据项、数据对象、数据结构、逻辑结构、存储结构、抽象数据类型。
答案:数据:是客观事物的符号表示,指所有能输入到计算机中并被计算机程序处理的符号的总称。
如数学计算中用到的整数和实数,文本编辑所用到的字符串,多媒体程序处理的图形、图像、声音、动画等通过特殊编码定义后的数据。
数据元素:是数据的基本单位,在计算机中通常作为一个整体进行考虑和处理。
在有些情况下,数据元素也称为元素、结点、记录等。
数据元素用于完整地描述一个对象,如一个学生记录,树中棋盘的一个格局(状态)、图中的一个顶点等。
数据项:是组成数据元素的、有独立含义的、不可分割的最小单位。
例如,学生基本信息表中的学号、姓名、性别等都是数据项。
数据对象:是性质相同的数据元素的集合,是数据的一个子集。
例如:整数数据对象是集合N={0 ,± 1,± 2,, } ,字母字符数据对象是集合C={‘A’,‘B’, , ,‘Z’,‘ a’,‘ b’, , ,‘z ’} ,学生基本信息表也可是一个数据对象。
数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。
换句话说,数据结构是带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系。
逻辑结构:从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的。
因此,数据的逻辑结构可以看作是从具体问题抽象出来的数学模型。
存储结构:数据对象在计算机中的存储表示,也称为物理结构。
抽象数据类型:由用户定义的,表示应用问题的数学模型,以及定义在这个模型上的一组操作的总称。
具体包括三部分:数据对象、数据对象上关系的集合和对数据对象的基本操作的集合。
(2024年)数据结构严蔚敏PPT完整版
选择排序的基本思想
在未排序序列中找到最小(或最大)元素,存放到排序 序列的起始位置,然后,再从剩余未排序元素中继续寻 找最小(或最大)元素,然后放到已排序序列的末尾。 以此类推,直到所有元素均排序完毕。
2024/3/26
33
交换排序和归并排序
交换排序的基本思想
通过不断地交换相邻的两个元素(如果它们的顺序错 误)来把最小的元素“浮”到数列的一端。具体实现 时,从第一个元素开始,比较相邻的两个元素,如果 前一个比后一个大,则交换它们的位置;每一对相邻 元素做同样的工作,从开始第一对到结尾的最后一对 ;这步做完后,最后的元素会是最大的数;针对所有 的元素重复以上的步骤,除了最后一个;持续每次对 越来越少的元素重复上面的步骤,直到没有任何一对 数字需要比较。
图的基本操作
创建图、添加顶点、添加边、删除顶点、删除边 等
2024/3/26
27
图的存储结构
01
邻接矩阵表示法
用一个二维数组表示图中顶点间的 关系,适用于稠密图
十字链表表示法
用于有向图,可以方便地找到任一 顶点的入边和出边
03
2024/3/26
02
邻接表表示法
用链表表示图中顶点间的关系,适 用于稀疏图
入栈操作将元素添加到栈顶,出栈操作将栈顶元素删 除,取栈顶元素操作返回栈顶元素但不删除,判断栈
是否为空操作检查栈中是否有元素。
2024/3/26
12
栈的表示和实现
栈可以用数组或链表来实现。
用数组实现时,需要预先分配一块连续的内存空间,用一个变量指示栈顶位置。入栈和出栈操作都可以 通过移动栈顶位置来实现。
22
二叉树的定义和基本操作
二叉树的定义
二叉树是一种特殊的树,每个节点最 多有两个子节点,分别称为左子节点 和右子节点。
数据结构 严蔚敏 清华大学出版社 习题及答案
第1章绪论 (2)1、填空题 (2)2、应用题 (2)第2章线性表 (3)1、填空题 (3)2、选择题 (3)3、判断题 (4)4、程序设计题 (4)第3章栈和队列 (6)1、填空题 (6)2、选择题 (6)3、判断题 (7)第4章串 (7)1、选择题 (7)2、判断题 (7)第5章数组和广义表 (7)1、填空题 (7)2、选择题 (7)3、判断题 (8)第6章树和二叉树 (8)1、填空题 (8)2、选择题 (9)3、判断题 (9)4、应用题 (9)5、读程序写结果 (16)第7章图 (17)1、填空题 (17)2、选择题 (17)3、判断题 (18)4、应用题 (18)5、程序设计题 (22)第8章动态存储管理 (23)1、填空题 (23)2、选择题 (23)3、判断题 (23)4、应用题 (23)5、程序设计题 (23)第9章查找 (23)1、选择题 (23)2、判断题 (24)3、应用题 (24)4、程序设计题 (26)第10章内部排序 (27)1、填空题 (27)2、选择题 (27)3、判断题 (27)4、应用题 (28)第11章外部排序 (28)第12章文件 (28)第1章绪论1、填空题1.常见的数据结构有_线性__结构,__树形___结构,__图形__结构等三种。
2.常见的存储结构有__顺序存储_______结构,__链式存储____结构等两种。
3.数据的基本单位是_数据元素___,它在计算机中是作为一个整体来处理的。
4.数据结构中的结构是指数据间的逻辑关系,常见的结构可分为两大类,__线性结构____和__非线性结构___。
2、应用题1、给出以下算法的时间复杂度.void fun(int n){int i=1,k=100;while(i<n){k=k+1;i=i+2;}}时间复杂度为____O(n)_____。
2、给出以下算法的时间复杂度.void fun2(int n){int i=1,k=100;while(i<n){i=i*10;k=k+1;}}时间复杂度为____O(log n)___________。
严蔚敏数据结构课件10:哈希表
1. 直接定址法
此类函数直接取关键字或关键字的某个线性函数 线性函数值 线性函数 作为散列地址: Hash ( key ) = a * key + b { a, b为常数 } 这类散列函数是一对一的映射,一般不会产生冲突。 但是,它要求散列地址空间的大小与关键字集合的 大小相同。
2. 数字分析法 设有n个d位数,每一位可能有r种不同的符号。这 r 种不同的符号在各位上出现的频率不一定相同,可能 在某些位上分布均匀些;在某些位上分布不均匀,只 有某几种符号经常出现。可根据散列表的大小,选取 其中各种符号分布均匀的若干位作为散列地址。
查找关键字时所需对桶的平均访问次数
从图中可以看出,链地址法优于开放定址法;在散列函 数中,用除留余数法作散列函数优于其它类型的散列函 数,最差的是折叠法。
用不同的方法溢出处理冲突时散列表的平均查找长度 如图所示
处 理 溢 出 的 方 法 开 放 定 址 法 伪随机探查法 二次探查法 双散列法 链 地 址 法 (同义词子表法)
1 + α 2
平 均 搜 索 长 度 ASL 搜索成功 Sn
1 1 1 + 2 1 − α
搜索不成功(登入新记录) Un
1 2 1 1 + 2 (1 − α )
线性探查法
1 − log α
e (1 − α )
1 1− α
α + e −α ≈ α
散列 (Hashing)
在线性表、树结构中查找纪录是通过与关键 字的“比较”完成的。
• 顺序查找,比较的结果为“=”或“≠” • 非顺序查找,比较的结果为“<”,“=”,“>”
散列的思想: 根据纪录的关键字直接找到记录的存储位置, 即为关键字和记录的存储位置建立一个对应 关系f,使每个关键字和结构中一个唯一的 存储位置相对应。 对应关系f为散列函数,按该思想建立的表 为散列表。
数据结构严蔚敏版第十章答案
第十章内部排序10.23void Insert_Sort1(SqList &L)//监视哨设在高下标端的插入排序算法{k=L.length;for(i=k-1;i;--i) //从后向前逐个插入排序if(L.r[i].key>L.r[i+1].key){L.r[k+1].key=L.r[i].key; //监视哨for(j=i+1;L.r[j].key>L.r[i].key;++j)L.r[j-1].key=L.r[j].key; //前移L.r[j-1].key=L.r[k+1].key; //插入}}//Insert_Sort110.24void BiInsert_Sort(SqList &L)//二路插入排序的算法{int d[MAXSIZE]; //辅助存储x=L.r.key;d=x;first=1;final=1;for(i=2;i<=L.length;i++){if(L.r[i].key>=x) //插入前部{for(j=final;d[j]>L.r[i].key;j--)d[j+1]=d[j];d[j+1]=L.r[i].key;final++;}else //插入后部{for(j=first;d[j]<L.r[i].key;j++)d[j-1]=d[j];d[(j-2)%MAXSIZE+1]=L.r[i].key;first=(first-2)%MAXSIZE+1; //这种形式的表达式是为了兼顾first=1的情况 }}//forfor(i=first,j=1;d[i];i=i%MAXSIZE+1,j++)//将序列复制回去L.r[j].key=d[i];}//BiInsert_Sortvoid SLInsert_Sort(SLList &L)//静态链表的插入排序算法{L.r[0].key=0;L.r[0].next=1;L.r[1].next=0; //建初始循环链表for(i=2;i<=L.length;i++) //逐个插入{p=0;x=L.r[i].key;while(L.r[L.r[p].next].key<x&&L.r[p].next)p=L.r[p].next;q=L.r[p].next;L.r[p].next=i;L.r[i].next=q;}//forp=L.r[0].next;for(i=1;i<L.length;i++) //重排记录的位置{while(p<i) p=L.r[p].next;q=L.r[p].next;if(p!=i){L.r[p]<->L.r[i];L.r[i].next=p;}p=q;}//for}//SLInsert_Sort10.26void Bubble_Sort1(int a[ ],int n)//对包含n个元素的数组a进行改进的冒泡排序{change=n-1; //change指示上一趟冒泡中最后发生交换的元素while(change){for(c=0,i=0;i<change;i++)if(a[i]>a[i+1]){a[i]<->a[i+1];c=i+1; //c指示这一趟冒泡中发生交换的元素}change=c;}//while}//Bubble_Sort1void Bubble_Sort2(int a[ ],int n)//相邻两趟是反方向起泡的冒泡排序算法{low=0;high=n-1; //冒泡的上下界change=1;while(low<high&&change){change=0;for(i=low;i<high;i++) //从上向下起泡if(a[i]>a[i+1]){a[i]<->a[i+1];change=1;}high--; //修改上界for(i=high;i>low;i--) //从下向上起泡if(a[i]<a[i-1]){a[i]<->a[i-1];change=1;}low++; //修改下界}//while}//Bubble_Sort210.28void Bubble_Sort3(int a[ ],int n)//对上一题的算法进行化简,循环体中只包含一次冒泡{int b[ 3 ]; //b[0]为冒泡的下界,b[ 2 ]为上界,b[1]无用d=1;b[0]=0;b[ 2 ]=n-1; //d为冒泡方向的标识,1为向上,-1为向下change=1;while(b[0]<b[ 2 ]&&change){change=0;for(i=b[1-d];i!=b[1+d];i+=d) //统一的冒泡算法if((a[i]-a[i+d])*d>0) //注意这个交换条件{a[i]<->a[i+d];change=1;}b[1+d]-=d; //修改边界d*=-1; //换个方向}//Bubble_Sort310.29void OE_Sort(int a[ ],int n)//奇偶交换排序的算法{change=1;while(change){change=0;for(i=1;i<n-1;i+=2) //对所有奇数进行一趟比较if(a[i]>a[i+1]){a[i]<->a[i+1];change=1;}for(i=0;i<n-1;i+=2) //对所有偶数进行一趟比较if(a[i]>a[i+1]){a[i]<->a[i+1];change=1;}}//while}//OE_Sort分析:本算法的结束条件是连续两趟比较无交换发生10.30typedef struct {int low;int high;} boundary; //子序列的上下界类型void QSort_NotRecurve(int SQList &L)//快速排序的非递归算法{low=1;high=L.length;InitStack(S); //S的元素为boundary类型while(low<high&&!StackEmpty(S)) //注意排序结束的条件{if(high-low>2) //如果当前子序列长度大于3且尚未排好序 {pivot=Partition(L,low,high); //进行一趟划分if(high-pivot>pivot-low){Push(S,{pivot+1,high}); //把长的子序列边界入栈high=pivot-1; //短的子序列留待下次排序}else{Push(S,{low,pivot-1});low=pivot+1;}}//ifelse if(low<high&&high-low<3)//如果当前子序列长度小于3且尚未排好序{Easy_Sort(L,low,high); //直接进行比较排序low=high; //当前子序列标志为已排好序}else //如果当前子序列已排好序但栈中还有未排序的子序列{Pop(S,a); //从栈中取出一个子序列low=a.low;high=a.high;}}//while}//QSort_NotRecurveint Partition(SQList &L,int low,int high)//一趟划分的算法,与书上相同{L.r[0]=L.r[low];pivotkey=L.r[low].key;while(low<high){while(low<high&&L.r[high].key>=pivotkey)high--;L.r[low]=L.r[high];while(low<high&&L.r[low].key<=pivotkey)low++;L.r[high]=L.r[low];}//whileL.r[low]=L.r[0];return low;}//Partitionvoid Easy_Sort(SQList &L,int low,int high)//对长度小于3的子序列进行比较排序{if(high-low==1) //子序列只含两个元素if(L.r[low].key>L.r[high].key) L.r[low]<->L.r[high];else //子序列含有三个元素{if(L.r[low].key>L.r[low+1].key) L.r[low]<->L.r[low+1];if(L.r[low+1].key>L.r[high].key) L.r[low+1]<->L.r[high];if(L.r[low].key>L.r[low+1].key) L.r[low]<->L.r[low+1];}}//Easy_Sort10.31void Divide(int a[ ],int n)//把数组a中所有值为负的记录调到非负的记录之前{low=0;high=n-1;while(low<high){while(low<high&&a[high]>=0) high--; //以0作为虚拟的枢轴记录a[low]<->a[high];while(low<high&&a[low]<0) low++;a[low]<->a[high];}}//Divide10.32typedef enum {RED,WHITE,BLUE} color; //三种颜色void Flag_Arrange(color a[ ],int n)//把由三种颜色组成的序列重排为按照红,白,蓝的顺序排列{i=0;j=0;k=n-1;while(j<=k)switch(a[j]){case RED:a[i]<->a[j];i++;j++;break;case WHITE:j++;break;case BLUE:a[j]<->a[k];k--; //这里没有j++;语句是为了防止交换后a[j]仍为蓝色的情况}}//Flag_Arrange分析:这个算法中设立了三个指针.其中,j表示当前元素;i以前的元素全部为红色;k以后的元素全部为蓝色.这样,就可以根据j的颜色,把其交换到序列的前部或者后部.10.33void LinkedList_Select_Sort(LinkedList &L)//单链表上的简单选择排序算法{for(p=L;p->next->next;p=p->next){q=p->next;x=q->data;for(r=q,s=q;r->next;r=r->next) //在q后面寻找元素值最小的结点if(r->next->data<x){x=r->next->data;s=r;}if(s!=q) //找到了值比q->data更小的最小结点s->next{p->next=s->next;s->next=q;t=q->next;q->next=p->next->next;p->next->next=t;} //交换q和s->next两个结点}//for}//LinkedList_Select_Sort10.34void Build_Heap(Heap &H,int n)//从低下标到高下标逐个插入建堆的算法{for(i=2;i<n;i++){ //此时从H.r[1]到H.r[i-1]已经是大顶堆j=i;while(j!=1) //把H.r[i]插入{k=j/2;if(H.r[j].key>H.r[k].key)H.r[j]<->H.r[k];j=k;}}//for}//Build_Heap10.35void TriHeap_Sort(Heap &H)//利用三叉树形式的堆进行排序的算法{for(i=H.length/3;i>0;i--)Heap_Adjust(H,i,H.length);for(i=H.length;i>1;i--){H.r[1]<->H.r[i];Heap_Adjust(H,1,i-1);}}//TriHeap_Sortvoid Heap_Adjust(Heap &H,int s,int m)//顺序表H中,H.r[s+1]到H.r[m]已经是堆,把H.r[s]插入并调整成堆{rc=H.r[s];for(j=3*s-1;j<=m;j=3*j-1){if(j<m&&H.r[j].key<H.r[j+1].key) j++;if(j<m&&H.r[j].key<H.r[j+1].key) j++;H.r[s]=H.r[j];s=j;}H.r[s]=rc;}//Heap_Adjust分析:本算法与课本上的堆排序算法相比,只有两处改动:1.建初始堆时,i的上限从H.length/3开始(为什么?) 2.调整堆的时候,要从结点的三个孩子结点中选择最大的那一个,最左边的孩子的序号的计算公式为j=3*s-1(为什么?)10.36void Merge_Sort(int a[ ],int n)//归并排序的非递归算法{for(l=1;l<n;l*=2) //l为一趟归并段的段长for(i=0;(2*i-1)*l<n;i++) //i为本趟的归并段序号{start1=2*l*i; //求出待归并的两段的上下界end1=start1+l-1;start2=end1+1;end2=(start2+l-1)>(n-1)?(n-1):(start2+l-1);//注意end2可能超出边界Merge(a,start1,end1,start2,end2); //归并}}//Merge_Sortvoid Merge(int a[ ],int s1,int e1,int s2,int e2)//将有序子序列a[s1]到a[e1]和a[s2]到a[e2]归并为有序序列a[s1]到a[e2]{int b[MAXSIZE]; //设立辅助存储数组bfor(i=s1,j=s2,k=s1;i<=e1&&j<=e2;k++){if(a[i]<a[j]) b[k]=a[i++];else b[k]=a[j++];}while(i<=e1) b[k++]=a[i++];while(j<=e2) b[k++]=a[j++]; //归并到b中for(i=s1;i<=e2;i++) //复制回去a[i]=b[i];}//Merge10.37void LinkedList_Merge_Sort1(LinkedList &L)//链表结构上的归并排序非递归算法{for(l=1;l<L.length;l*=2) //l为一趟归并段的段长for(p=L->next,e2=p;p->next;p=e2){for(i=1,q=p;i<=l&&q->next;i++,q=q->next);e1=q;for(i=1;i<=l&&q->next;i++,q=q->next);e2=q; //求出两个待归并子序列的尾指针if(e1!=e2) LinkedList_Merge(L,p,e1,e2); //归并}}//LinkedList_Merge_Sort1void LinkedList_Merge(LinkedList &L,LNode *p,LNode *e1,LNode *e2)//对链表上的子序列进行归并,第一个子序列是从p->next到e1,第二个是从e1->next到e2 {q=p->next;r=e1->next; //q和r为两个子序列的起始位置while(q!=e1->next&&r!=e2->next){if(q->data<r->data) //选择关键字较小的那个结点接在p的后面{p->next=q;p=q;q=q->next;}else{p->next=r;p=r;r=r->next;}}//whilewhile(q!=e1->next) //接上剩余部分{p->next=q;p=q;q=q->next;}while(r!=e2->next){p->next=r;p=r;r=r->next;}}//LinkedList_Merge10.38void LinkedList_Merge_Sort2(LinkedList &L)//初始归并段为最大有序子序列的归并排序,采用链表存储结构{LNode *end[MAXSIZE]; //设立一个数组来存储各有序子序列的尾指针for(p=L->next->next,i=0;p;p=p->next) //求各有序子序列的尾指针if(!p->next||p->data>p->next->data) end[i++]=p;while(end[0]->next) //当不止一个子序列时进行两两归并{j=0;k=0; //j:当前子序列尾指针存储位置;k:归并后的子序列尾指针存储位置for(p=L->next,e2=p;p->next;p=e2) //两两归并所有子序列{e1=end[j];e2=end[j+1]; //确定两个子序列if(e1->next) LinkedList_Merge(L,p,e1,e2); //归并end[k++]=e2; //用新序列的尾指针取代原来的尾指针j+=2; //转到后面两个子序列}}//while}//LinkedList_Merge_Sort2void LinkedList_Merge(LinkedList &L,LNode *p,LNode *e1,LNode *e2)//对链表上的子序列进行归并,第一个子序列是从p->next到e1,第二个是从e1->next到e2 {q=p->next;r=e1->next;while(q!=e1->next&&r!=e2->next){if(q->data<r->data){p->next=q;p=q;q=q->next;}else{p->next=r;p=r;r=r->next;}}//whilewhile(q!=e1->next){p->next=q;p=q;q=q->next;}while(r!=e2->next){p->next=r;p=r;r=r->next;}}//LinkedList_Merge,与上一题完全相同10.39void SL_Merge(int a[ ],int l1,int l2)//把长度分别为l1,l2且l1^2<(l1+l2)的两个有序子序列归并为有序序列{start1=0;start2=l1; //分别表示序列1和序列2的剩余未归并部分的起始位置for(i=0;i<l1;i++) //插入第i个元素{for(j=start2;j<l1+l2&&a[j]<a[start1+i];j++); //寻找插入位置k=j-start2; //k为要向右循环移动的位数RSh(a,start1,j-1,k);//将a[start1]到a[j-1]之间的子序列循环右移k位start1+=k+1;start2=j; //修改两序列尚未归并部分的起始位置}}//SL_Mergevoid RSh(int a[ ],int start,int end,int k)//将a[start]到a[end]之间的子序列循环右移k 位,算法原理参见5.18{len=end-start+1;for(i=1;i<=k;i++)if(len%i==0&&k%i==0) p=i; //求len和k的最大公约数pfor(i=0;i<p;i++) //对p个循环链分别进行右移{j=start+i;l=start+(i+k)%len;temp=a[j];while(l!=start+i){a[j]=temp;temp=a[l];a[l]=a[j];j=l;l=start+(j-start+k)%len; //依次向右移}a[start+i]=temp;}//for}//RSh10.40书后给出的解题思路在表述上存在问题,无法理解.比如说,"把第一个序列划分为两个子序列,使其中的第一个子序列含有s1个记录,0<=s1<s,第二个子序列有s个记录."可是题目中并没有说明,第一个序列的长度<2s.请会做的朋友提供解法.10.41void Hash_Sort(int a[ ])//对1000个关键字为四位整数的记录进行排序{int b[10000];for(i=0;i<1000;i++) //直接按关键字散列{for(j=a[i];b[j];j=(j+1)%10000);b[j]=a[i];}for(i=0,j=0;i<1000;j++) //将散列收回a中if(b[j]){for(x=b[j],k=j;b[k];k=(k+1)%10000)if(b[k]==x){a[i++]=x;b[k]=0;}}//if}//Hash_Sort10.42typedef struct {int gt; //大于该记录的个数int lt; //小于该记录的个数} place; //整个序列中比某个关键字大或小的记录个数int Get_Mid(int a[ ],int n)//求一个序列的中值记录的位置{place b[MAXSIZE];for(i=0;i<n;i++) //对每一个元素统计比它大和比它小的元素个数gt和ltfor(j=0;j<n;j++){if(a[j]>a[i]) b[i].gt++;else if(a[j]<a[i]) b[i].lt++;}mid=0;min_dif=abs(b[0].gt-b[0].lt);for(i=0;i<n;i++) //找出gt值与lt值最接近的元素,即为中值记录if(abs(b[i].gt-b[i].lt)<min_dif) mid=i;return mid;}//Get_Mid10.43void Count_Sort(int a[ ],int n)//计数排序算法{int c[MAXSIZE];for(i=0;i<n;i++) //对每一个元素{for(j=0,count=0;j<n;j++) //统计关键字比它小的元素个数if(a[j]<a[i]) count++:c[i]=count;}for(i=0;i<n;i++) //依次求出关键字最小,第二小,...,最大的记录{min=0;for(j=0;j<n;j++)if(c[j]<c[min]) min=j; //求出最小记录的下标mina[i]<->a[min]; //与第i个记录交换c[min]=INFINITY; //修改该记录的c值为无穷大以便下一次选取}}//Count_Sort10.44void Enum_Sort(int a[ ],int n)//对关键字只能取v到w之间任意整数的序列进行排序{int number[w+1],pos[w+1];for(i=0;i<n;i++) number[a[i]]++; //计数for(pos[0]=0,i=1;i<n;i++)pos[i]=pos[i-1]+num[i]; //pos数组可以把关键字的值映射为元素在排好的序列中的位置for(i=0;i<n;i++) //构造有序数组cc[pos[a[i]]++]=a[i];for(i=0;i<n;i++)a[i]=c[i];}//Enum_Sort分析:本算法参考了第五章三元组稀疏矩阵转置的算法思想,其中的pos数组和那里的cpot数组起的是相类似的作用.10.45typedef enum {0,1,2,3,4,5,6,7,8,9} digit; //个位数类型typedef digit[3] num; //3位自然数类型,假设低位存储在低下标,高位存储在高下标void Enum_Radix_Sort(num a[ ],int n)//利用计数实现基数排序,其中关键字为3位自然数,共有n个自然数{int number ,pos ;num c[MAXSIZE];for(j=0;j<3;j++) //依次对个位,十位和百位排序{for(i=0;i<n;i++) number[a[i][j]]++; //计数for(pos[0]=0,i=1;i<n;i++)pos[i]=pos[i-1]+num[i]; //把关键字的值映射为元素在排好的序列中的位置for(i=0;i<n;i++) //构造有序数组cc[pos[a[i][j]]++]=a[i];for(i=0;i<n;i++)a[i]=c[i];}//for}//Enum_Radix_Sort分析:计数排序是一种稳定的排序方法.正因为如此,它才能够被用来实现基数排序.10.46typedef struct {int key;int pos;} Shadow; //影子序列的记录类型void Shadow_Sort(Rectype b[ ],Rectype &a[ ],int n)//对元素很大的记录序列b进行排序,结果放入a中,不移动元素{Shadow d[MAXSIZE];for(i=0;i<n;i++) //生成影子序列{d[i].key=b[i].key;d[i].pos=i;}for(i=n-1,change=1;i>1&&change;i--) //对影子序列执行冒泡排序 {change=0;for(j=0;j<i;j++)if(d[j].key>d[j+1].key){d[j]<->d[j+1];change=1;}}//forfor(i=0;i<n;i++) //按照影子序列里记录的原来位置复制原序列 a[i]=b[d[i].pos];}//Shadow_Sort。
严蔚敏数据结构C语言版习题集答案
严蔚敏《数据结构(C语言版)习题集》答案第一章绪论void print_descending(int x,int y,int z)....+f[m-k]=f[m-1]+f[m-2]+......+f[m-k]+f[m-k-1]-f[m-k-1]=2*f[m-1]-f[m-k-1]所以上述算法的时间复杂度仅为O(m). 如果采用递归设计,将达到O(k^m). 即使采用暂存中间结果的方法,也将达到O(m^2).typedef struct{char *sport;enum{male,female} gender;char schoolname; port!=NULL){switch(result[i].schoolname){case 'A':score[ 0 ].totalscore+=result[i].score;if(result[i].gender==0) score[ 0 ].malescore+=result[i].score;else score[ 0 ].femalescore+=result[i].score;break;case 'B':score[ 0 ].totalscore+=result[i].score;if(result[i].gender==0) score[ 0 ].malescore+=result[i].score;else score[ 0 ].femalescore+=result[i].score;break;………………}i++;}for(i=0;i<5;i++){printf("School %d:\n",i);printf("Total score of male:%d\n",score[i].malescore);printf("Total score of female:%d\n",score[i].femalescore);printf("Total score of all:%d\n\n",score[i].totalscore);}}void polyvalue(){float temp;float *p=a;printf("Input number of terms:");scanf("%d",&n);printf("Input value of x:");scanf("%f",&x);printf("Input the %d coefficients from a0 to a%d:\n",n+1,n);p=a;xp=1;sum=0;Status Insert(LinkList &L,int i,int b)void merge1(LinkList &A,LinkList &B,LinkList &C)void SqList_Intersect(SqList A,SqList B,SqList &C)void LinkList_Intersect_Delete(LinkList &A,LinkList B,LinkList C)iList为带头结点的单循环链表类型.{s=L->next;A=(CiList*)malloc(sizeof(CiLNode));p=A;B=(CiList*)malloc(sizeof(CiLNode));q=B;C=(CiList*)malloc(sizeof(CiLNode));r=C; .4,2的顺序重排双向循环链表L中的所有结点{p=;while(p->next!=L&&p->next->next!=L){p->next=p->next->next;p=p->next;} 同时进行调整的话,必须使用堆栈保存偶数结点的指针,否则将会破坏链表结构,造成结点丢失.DuLNode * Locate_DuList(DuLinkedList &L,int x) int x;int y;} coordinate;void Repaint_Color(int g[m][n],int i,int j,int color)归形式的算法该怎么写呢?void NiBoLan(char *str,char *new)题中暂不考虑串的具体操作的实现,而将其看作一种抽象数据类型stringtype,对其可以进行连接操作:c=link(a,b).Status g(int m,int n,int &s)void InitCiQueue(CiQueue &Q)Status EnCyQueue(CyQueue &Q,int x)省掉这一句,则在某些情况下,会引起不希望的后果,虽然在大多数情况下没有影响.请思考:设S='place', T='ace', V='face',则省掉i+=Strlen(V);运行时会出现什么结果?int Delete_SubString(Stringtype &s,Stringtype t)读者用此程序取代作者早些时候对题给出的程序.void StrAssign(Stringtype &T,char chars&#;)h&&T[j].ch!=c) j++; h) T[j].num++;else T[j]={c,1};}h;j++)printf("%c: %d\n",T[j].ch,T[j].num);}前一个程序的区别在于,串s业已存在.{for(p=s->next,q=t->next;p&&q;p=p->next,q=q->next){p->ch=q->ch;pre=p;}while(q){p=(LStrNode*)malloc(sizeof(LStrNode));p->ch=q->ch;pre->next=p;pre=p;}p->next=NULL;}算法的思想是,依次把串S的一个副本S2向右错位平移1格,2格,3格,...与自身S1相匹配,如果存在最长重复子串,则必然能在此过程中被发现.用变量lrs1,lrs2,maxlen来记录已发现的最长重复子串第一次出现位置,第二次出现位置和长度.题目中未说明"重复子串"是否允许有重叠部分,本算法假定允许.如不允许,只需在第二个for语句的循环条件中加上k<=i即可.本算法时间复杂度为O(Strlen(S)^2).void Get_LPubSub(Stringtype S,Stringtype T) for(k=0,j=jmin;j<=jmax;j++){if(A[j]==B[j-i]) k++;else k=0;if(k>maxlen){lps1=j-k+1;lps2=j-i-k+1;maxlen=k;}}一的区别是,由于A,B互不相同,因此B不仅要向右错位,而且还要向左错位,以保证不漏掉一些情况.当B相对于A的位置不同时,需要匹配的区间的计算公式也各不相同,请读者自己画图以帮助理解.本算法的时间复杂度是o(strlrn(s)*strlen(t))。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、什么是排序?
排序是计算机内经常进行的一种操作, 其目的是将一组“无序”的记录序列调 整为“有序”的记录序列。
例如:将下列关键字序列 52, 49, 80, 36, 14, 58, 61, 23, 97, 75
调整为
14, 23, 36, 49, 52, 58, 61 ,75, 80, 97 .页 08.06.2020
10. 2 插入排序
.页 08.06.2020
一趟直接插入排序的基本思想:
有序序列R[1..i-1]
无序序列 R[i..n]
R[i]
有序序列R[1..i]
无序序列 R[i+1..n]
.页 08.06.2020
实现“一趟插入排序”可分三步进行:
1.在R[1..i-1]中查找R[i]的插入位置,
R[1..j].key R[i].key < R[j+1..i-1].key;
有序序列区 无 序 序 列 区
经过一趟排序
08.06.2020
有序序列区 无 序 序 列 区
.页
基于不同的“扩大” 有序序列长 度的方法,内部排序方法大致可分 下列几种类型:
插入类 交换类 选择类
归并类 其它方法
.页 08.06.2020
#待de排fin记e M录A的XS数IZ据E 类10型00定// 义待排如顺下序:表最大长度
第十章 排序
.页 08.06.2020
【课前思考】
1. 你熟悉排序吗?你过去曾经学过哪些排序方法? 在第一章中曾以选择排序和起泡排序为例讨论算 法实践复杂度,不知你还记得吗? 2. 你自己有没有编过排序的程序?是用的什么策 略?
.页 08.06.2020
【学习目标】
1.理解排序的定义和各种排序方法的特点,并能 加以灵活应用。排序方法有不同的分类方法,基于"关 键字间的比较"进行排序的方法可以按排序过程所依据 的不同原则分为插入排序、交换排序、选择排序、归 并排序和计数排序等五类。
int
length;
// 顺序表长度
} SqList;
08.06.2020
.页 // 顺序表类型
1. 插入类
将无序子序列中的一个或几 个记录“插入”到有序序列中, 从而增加记录的有序子序列的长 度。
.页 08.06.2020
2. 交换类
通过“交换”无序序列中的记 录从而得到其中关键字最小或最大 的记录,并将它加入到有序子序列 中,以此方法增加记录的有序子序 列的长度。
08.06.2020
【重点和难点】
希尔排序、快速排序、堆排序和归并排序等高效方 法是本章的学习重点和难点。
【知识点】
排序、直接插入排序、折半插入排序、表插入排 序、希尔排序、起泡排序、快速排序、简单选择 排序、堆排序、2-路归并排序、基数排序、排序方 法的综合比较 。
.页 08.06.2020
【学习指南】
2.将R[j+1..i-1]中的所有记录均后移
一个位置;
3.将R[i] 插入(复制)到R[j+1]的位置上。
.页 08.06.2020
不同的具体实现方法导致不同的算法描述
直接插入排序(基于顺序查找) 折半插入排序(基于折半查找) 表插入排序(基于链表存储) 希尔排序(基于逐趟缩小增量)
.页 08.06.2020
一、直接插入排序
利用 “顺序查找”实现
“在R[1..i-1]中查找R[i]的插入位置”
08.06.2020
二、内部排序和外部排序
若整个排序过程不需要访问外存便 能完成,则称此类排序问题为内部排 序;
反之,若参加排序的记录数量很大, 整个序列的排序过程不可能在内存中 完成,则称此类排序问题为外部排序。
.页 08.06.2020
三、内部排序的方法
内部排序的过程是一个逐步扩大 记录的有序序列长度的过程。
.页
08.06.2020
10.1 概述
10.2 插入排序
10.3 快速排序
10.4 堆排序 10.5 归并排序
10.6 基数排序
10.7 各种排序方法的综合比较
08.06.2020
10.8 外.页 部排序
10.1 概 述
一、排序的定义 二、内部排序和外部排序 三、内部排序方法的分类
.页 08.06.2020
typedef int KeyType; // 关键字类型为整数类型
typedef struct {
KeyType key;
// 关键字项
InfoType otherinfo; // 其它数据项
} RcdType;
// 记录cdType r[MAXSIZE+1]; // r[0]闲置
2.掌握各种排序方法的时间复杂度的分析方法。 能从"关键字间的比较次数"分析排序算法的平均情况 和最坏情况的时间性能。按平均时间复杂度划分,内 部排序可分为三类:O (n2) 的简单排序方法,O (n·logn) 的高效排序方法和O (d·n)的基数排序方法。
3.理解排序方法"稳定"或"不稳定"的含义,弄清 楚在什么情况下要求应用的.页排序方法必须是稳定的。
.页 08.06.2020
3. 选择类
从记录的无序子序列中“选择” 关键字最小或最大的记录,并将它 加入到有序子序列中,以此方法增 加记录的有序子序列的长度。
.页 08.06.2020
4. 归并类
通过“归并”两个或两个以上的 记录有序子序列,逐步增加记录有 序序列的长度。
5. 其它方法
.页 08.06.2020
本章学习的要点主要是了解各种排序方法实现 时所依据的原则以及它们的主要操作(“关键字间 的比较”和“记录的移动”)的时间分析。学习中 应注意掌握各种排序方法实现的要点,可通过对基 础知识题中算法的手工执行和比较分析,切实掌握 各种排序过程的排序特点所在,注意同一排序方法 在不同的教科书上可以有不同书写形式描述的算法。 在学习本章过程中需练习的算法设计题为:10.23, 10.25,10.27 , 10.32, 10.34, 10.38, 10.42 和 10.45。
一般情况下, 假设含n个记录的序列为{ R1, R2, …, Rn } 其相应的关键字序列为 { K1, K2, …,Kn }
这些关键字相互之间可以进行比较,即在 它们之间存在着这样一个关系 :
Kp1≤Kp2≤…≤Kpn
按此固有关系将上式记录序列重新排列为 { Rp1, Rp2, …,Rpn }
的操作称作排序。 .页