数据结构部分
1.概念
数据定义:
数据:是描述客观事物的数值,字符以及能输入机器能被处理的各种符号集合。
数据元素:组成数据的基本单位,一个数据元素可由一个或者多个数据项组成,数据项是有独立含义的最小单位。
数据对象:是性质相同的数据元素的集合,是数据的一个子集。
数据结构:是指相互之间存在一种或者多种特定关系的数据元素集合。
算法定义:
特性:
(1)有限性:有限步骤之内正常结束,不能形成无穷循环
(2)确定性:算法中的每一步必须有确定含义,无二义性
(3)输入:有多个或者零个输入
(4)输出:至少一个输出
(5)可行性:原则上能精确进行
2.线性表
2.1 基本概念
定义:由n个类型相同的数据元素组成的有限序列
特点:
同一性:线性表由同类型数据元素组成
有穷性:线性表由有限个数据元素组成
有序性:相连元素之间存在序偶关系,除首尾元素外,每个元素都存在唯一的首元素和唯一的尾元素
2.2 线性表的存储结构
2.2.1 顺序存储结构
定义:指用一组地址连续的存储单元依次存储线性表中的各元素,使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中
基本运算:查找、插入、删除、合并
优点:
(1)无需为表示节点间的逻辑关系而增加额外的存储空间(逻辑上相邻的元素其存储的物理位置上也相连)
(2)可方便随机存取表中的任一元素
确定:
(1)插入和删除运算不方便,除尾部的位置外,在表中其它位置进行操作时必须移动大量的元素
(2)存储分配只能预先进行静态分配,当表长变化较大时,难以确定合适的规模
2.2.2 链式存储结构
分类:单链表、双向链表和循环链表
单链表:包含两个域,数据域(用来存储结点的值)和指针域(用来存储数据元素的直接后继的位置),由于链表的每个结点只有一个指针域,故称为单链表
基本运算:初始化,查找,插入,删除,求长度
双向链表:包含三个域,前驱指针域(用来存储数据元素的直接前驱的位置),数据域(用来存储结点的值)和后驱指针域(用来存储数据元素的直接后继的位置)
基本运算:插入,删除,交换
循环链表:循环链表是(单、双)链表的另一种形式,它是一个首尾相连的链表
比较:顺序表和链表
基于空间考虑:线性表的长度变化较大,难以估计其存储规模是,采取动态链表结构存储,反之,采用顺序表存储
基于时间考虑:主要执行查询操作,很少做插入和删除,采用顺序表存储,反之,链表存储
3 限定性线性表
3.1 栈
3.1.1 定义
栈是一种限定性线性表,是将线性表的插入和删除操作限制在表的一端进行。允许插入和删除操作的一端称为栈顶,另一端称为栈底。插入也叫作入栈,删除叫出栈
3.1.2 基本操作和特点
基本操作:初始化,判空,判满,,读栈顶元素,入栈和出栈
特点:先进后出
3.1.3 栈的实现存储结构
顺序栈、链栈
顺序栈:用顺序存储结构实现的栈,由于栈的操作的特殊性,必须设一个位置指针top(栈顶指针)来动态表示栈顶元素在顺序栈中的位置。通常以top = -1表示空栈。
链栈:采用链表作为存储结构实现的栈。
3.1.4 典型应用
- 括号匹配
实现:
(1)设置一个栈,读取括号序列
(2)若是左括号,直接入栈,等待相匹配的同类右括号
(3)若是右括号,且与当前栈顶的左括号同类型,则二者匹配,将栈顶的左括号出栈,否则属于不合法的情况,判断结束
(4)输入序列已读尽,而栈中仍有等待匹配的左括号,属于不合法情况,判断结束
- 递归调用
原理:递归函数调用时,应按照“后调用 先返回”的原理处理调用过程,因此上述之间的信息传递和控制转移必须通过栈来实现。系统整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时,就为它分配一个存储区,每当从一个函数退出时,就释放它的存储区。当前正在运行的函数的数据区必在栈顶。
问题1:数据结构中的栈和堆,与内存中的栈区和堆区的区别是什么?
参考:https://www.cnblogs.com/jzssuanfa/p/7068147.html
3.2 队列
3.2.1 定义
是一种限定性的线性表,它只允许在表的一端插入,而在另一端删除。允许插入的一端叫做 队尾,允许删除的一端叫做 队头。
3.2.2 基本操作和特点
基本操作:初始化、判空、进队、出队、取队头元素、队列置空、队列销毁
特点:先进先出
3.2.3 队列的实现存储结构
顺序队列和链式队列
链式队列:采用带头结点的链表结构,并设置一个队头指针和一个队尾指针,队头指针始终指向头结点,队尾指针始终指向当前最后一个元素。空的链式队列的队头指针和队尾指针均指向头结点。
循环队列:是队列的一中顺序表示和实现方法。
3.2.4 应用
- 键盘输入缓冲区问题
4 字符串
说明: 字符串(简称串),可以将其看作是种特殊的线性表,其特殊性在于线性表的数据元素的类型总是字符,字符串的数据对象约束为字符集。
4.1 定义
是零个或者多个字符组成的有限序列,S = "a1a2...an"(n >= 0),其中 S 是串名,引号中字符序列是串的值,ai 可以是字母、数字、或其他字符。
空串:n = 0 时的串
子串:串中任意连续的字符组成的子序列
主串:包含子串的串,即S
相等:两个串长度相等,且对应位置的字符相等
空格串:由一个或者多个空格字符组成的串,其长度为空格的个数。注意区别与 空串
4.2 基本操作
初始化、插入、删除、复制、判空、合并、替换、判断长度
4.3 串实现的存储结构
定长顺序串、堆串、块链串
定长顺序串:与线性表顺序存储结构类似,用一组连续地址单元存储串的字符序列
堆串:仍然以一组地址连续的存储单元存放串的字符序列,但他们的存储空间在执行过程中动态分配
块链串:采用链式存储,由于串的特殊性,在实现是,每个结点既可以存放一个字符,也可以放多个字符。每个结点称为块。整个链表称为块链结构。
5 数组和广义表
5.1 定义
数组可以看成一般线性表的扩充,二维数组可以看成线性表的线性表。其特殊性不像栈和队列那样对数据元素的操作受限,而是反映在数据元素的构成上。线性表中,每个数据元素是不可再分的原子类型;而数组和广义表的数据元素可以推广为一种特定结构的数据。
5.2 数组操作
(1)获取特定位置的元素值
(2)修改特定位置的元素值
5.3 数组的顺序存储结构
原理:内存的结构是一维的,用一维内存表示多维数组,必须按某种次序,将数组元素排成一个线性序列,然后将这个线性序列存放在存储器中。
实现:
数组顺序存储结构有两种:按行存储、按列存储
5.4 特殊矩阵压缩存储
矩阵通常可以用二维数组的形式来描述。有些高阶矩阵中,非零元素较少,此时若仍采用二维数组存放就不合适了。压缩原则就是对有规律的元素和值相同的元素只分配一个存储空间,对零元素不分配空间。
5.4.1 有规律的特殊矩阵
(1)上三角矩阵
(2)下三角矩阵
(3)带状矩阵
方法:找到矩阵的位置特点,只存放非零元素到一维数组中
5.4.2 无规律的特殊矩阵
- 稀疏矩阵:矩阵中大多数元素为零的矩阵
方法:
(1)三元组表表示法
(2)十字链表(链式存储)技巧:因为分布没规律,所以必须储存一些辅助信息,即行号row和列号col
right:用于链接同行中的下一个元素
down:用于链接同列中的下一个元素
note:在进行加、减、乘除等操作运算时,相比三元组表,可避免了大量移动元素
5.5 广义表
特点:
广义表中的数据元素既可以是单个元素,也可以是子表。
6 树和二叉树
6.1 树的定义
树是 n 个结点的有限集合,当 n - 0 时,称为空树;当 n > 0 时,满足如下条件:
(1)必有一个称为 根 的节点,它没有直接前驱,但有零个或多个直接后继。
(2)其余 n-1 个节点可以划分成 m 个互不相交的有限集,称为 根 的子树。每个子树的根结点有且仅有一个直接前驱,但有零个或多个直接后继。
特点:一 对 多
6.2 有关树的术语
结点:包含一个数据元素及若干指向其它结点的分支信息
结点的度:一个结点子树个数称为结点的度
叶结点:度为0的结点
分支结点:度不为0的结点
孩子结点:一个结点的直接后继称为该结点的孩子结点
父结点:一个结点的直接前驱称为该结点的父节点
兄弟结点:同一个父节点的孩子结点之间称为兄弟结点
树的度:树种所有结点的度的最大值
结点的层次:从根结点开始定义,根结点层次为1,根直接后继结点为2,以此类推
树的高度(深度):树种所有结点的层次的最大值
有序树:各子树之间是有先后次序的
森林:m 棵互不相交的树的集合
6.3 基本操作
增删改查
6.4 二叉树
6.4.1 定义
(1)每个节点的度都不大于2
(2)每个结点的孩子不能任意颠倒
满二叉树:深度为 k 且有 2^k - 1 个结点的二叉树。
完全二叉树:深度为 k ,结点为 n 的二叉树,如果其结点1-n 的位置序号与满二叉树的结点位置序号一一对应,则为完全二叉树
二叉查找树:又被称为二叉搜索树。设x为二叉查找树中的一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。
6.4.2 二叉树性质
性质1:在二叉树第 i 层上至多有 2^(i-1) 个结点
性质2:深度为 k 的二叉树至多有 2^k-1 个结点
性质3:对任意一棵二叉树,若叶结点数为 n0,其度数为2的结点为 n2,则 n0 = n2 + 1.
性质4: 具有 n 个结点的完全二叉树的深度为[log2n] + 1
性质5:n 个结点的完全二叉树,按照从上向下和从左到右的顺序对二叉树的所有结点从1开始顺序编号,则对任意的序号为i的节点有
(1)i = 1,则序号为i的结点为根结点,无双亲结点;如 i > 1,则序号为 i 的 双亲结点序号为[i/2]
(2)2 * i > n,则i结点无左孩子,反之 2*i 为其左孩子
(3)2 * i + 1 > n,则i结点无左孩子,反之 2*i+1 为其左孩子
6.4.3 二叉树的存储结构
顺序存储结构和链式存储结构
顺序存储结构:用一组连续的存储单元存放二叉树的数据元素
存储如下:
note:存储时按照完全二叉树,如果不是完全二叉树,则用空格补全
存储如下:
链式存储结构:存储单元可以不连续,存放二叉树的数据元素至少包含以下三个域
LChild:指向该结点的左孩子
Data:记录该结点的信息
RChild:指向该结点的右孩子
6.4.4 二叉树的遍历
定义:按照一定规律对二叉树每个结点进行访问且仅访问一次
常用的三种遍历方式:对根的访问先后顺序定的,执行时按照递归的原则进行
- 先序遍历(DLR):
(1)访问根结点
(2)按先序遍历左子树
(3)按先序遍历右子树
- 中序遍历(LDR)
(1)按中序遍历左子树
(2)访问根结点
(3)按中序遍历右子树
- 后序遍历(LRD)
(1)按后序遍历左子树
(2)按后序遍历右子树
(3)访问根结点
6.5 红黑树
6.5.1 定义
全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。
6.5.2 性质
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
注意:
(1) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。
(2) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树
示意图:
6.5.3 应用
红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。
例如,Java集合中的TreeSet和TreeMap,C++ STL中的set、map,以及Linux虚拟内存的管理,都是通过红黑树去实现的。
6.5.4 基本操作
- 左、右旋转
红黑树的基本操作是添加、删除。在对红黑树进行添加或删除之后,都会用到旋转方法。为什么呢?道理很简单,添加或删除红黑树中的节点之后,红黑树就发生了变化,可能不满足红黑树的5条性质,也就不再是一颗红黑树了,而是一颗普通的树。而通过旋转,可以使这颗树重新成为红黑树。简单点说,旋转的目的是让树保持红黑树的特性
- 插入
首先,将红黑树当作一颗二叉查找树,将节点插入;然后,将节点着色为红色;最后,通过旋转和重新着色等方法来修正该树,使之重新成为一颗红黑树
- 删除
首先,将红黑树当作一颗二叉查找树,将该节点从二叉查找树中删除;然后,通过"旋转和重新着色"等一系列来修正该树,使之重新成为一棵红黑树
6.6 哈夫曼树及其应用
6.6.1 哈夫曼树
定义:又称最优二叉树,是由 n 个带权叶子结点构成的所有二叉树中带权路劲长度WPL最短的二叉树。
基本概念:
路径:从一个结点到另一个结点之间的分支序列
路径长度:从一个结点到另一个结点所经过的分支数目
结点的权:每个结点赋予一个具有某种实际意义的实数
带权路径长度:从树根到某一点的路径长度与该结点权的乘积
树的带权路径长度:所有叶子结点的带权路径长度之和,即为WPL
哈夫曼算法:
给定数列{w1,...,wn},以n个权值构成n棵单根树的森林F;将F={T1,...,Tn}按权从大到小排列;取T1和T2合并成一棵树,使其根结点的权值 T= T1 + T2,再按大小插入F,直到为一棵树为止。
特点:权值越大的叶子离根越近
6.6.2 典型应用
- 哈夫曼编码
利用哈夫曼树可以得到平均长度最短的编码。从而减少程序的总长度和增加指令所能表示的操作信息和地址信息。
6.7 B树和B+树
B+ 树的优点:
由于B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。
B+树的叶子结点都是相链的,因此对整棵树的便利只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好
B树的优点:
B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速
7 图
7.1 定义
G = (V,R)
其中,V称为顶点,R称为顶点之间的关系。
分类:有向图和无向图(根据R有无方向性划分)
特点:多对多
7.2 基本术语
无向完全图:每个顶点和剩余n-1 个顶点都有边相连
有向完全图:每个顶点和剩余n-1 个顶点都有弧相连
邻居点:G=(V,{E}),如果边(v1,v2)∈E,则称顶点v1、v2互为邻居点
度:顶点v的度是指与v相关联边的数目,即TD(v)
入度:有向图中,顶点v为弧头的弧的数目称为该顶点的入度,即ID(v)
出度:顶点v为弧尾的弧的数目称为该顶点的出度,即OD(v)
TD = ID + OD
e = all(TD)/2
权:每一条边都有与它相关的树,称为权
网:将带权的图叫做赋权图或网
路径:从顶点v1到vn是一个顶点序列,若表示路径的顶点序列中的顶点各不相同,则称为简单路径
回路:v1 = vn 时,该路径为一个回路,若除了第一个和最后一个顶点外,其余各顶点均不重复的回路称为简单回路
连通图:对于图中任意两个顶点都是连通的,则称该无向图G为连通图
强连通:对任意两个顶点vi、vj,从vi到vj和vj到vi都有路径,则称该有向图为强连通图
生成树:一个连通图的生成树是指一个极小连通子图,它包含图中的全部顶点,如果在一棵生成树上添加一条边,则必定构成一个环。
7.3 基本操作
创建、插入、删除、查找
7.4 图的存储结构
7.4.1 邻接矩阵表示法
定义:采用两个数组来表示图:一个是用来存储顶点信息的一维数组;另一个是用来存储图中顶点之间关联关系的二维数组,这个关联关系数组被称为邻接矩阵
性质:
(1)对无向图而言,其邻接矩阵第i行元素之和就是图中第i个顶点的度
(2)对于有向图而言,其邻接矩阵第i行元素之和就是图中第i个顶点的出度
(3)对于有向图而言,其邻接矩阵第i列元素之和就是图中第i个顶点的入度
优点:运算方便
缺点:对于稀疏图来讲,用邻接矩阵的表示法会造成存储空间的很大浪费
7.4.2 邻接表表示法(不太清楚)
定义:对于图G中的每个顶点vi,该方法把所有邻接于vi的顶点vj链成一个带头结点的单链表,这个单链表就称为顶点vi的邻接表(Adjacency List);
特点:实际上是图的一种链式存储结构,基本思想是只存储有关联的信息,对于图中存在的边信息则存储,不相连的的顶点则不保存。
基本概念:
7.4.3 十字链表
7.4.4 邻接多重表
7.5 图的遍历
定义:就是从图中的某个顶点出发,按照某种方法对图中的所有顶点访问且仅访问一次
可参考:https://www.cnblogs.com/weizhixiang/p/5815994.html
7.5.1 深度优先搜索
基本思想:类似于树的先根遍历
(1)从图中某店v0 出发,首先访问v0
(2)找出刚访问过的顶点的第一个未被访问的邻接点,然后访问该点,以该点为新顶点,重复本步骤,直到当前顶点无未被访问的邻接点为止
(3)返回前一个访问过的且仍有未被访问的邻接点的顶点,找出并访问该顶点的下一个未被访问的邻接点,然后执行步骤(2)
7.5.2 广度优先搜索
基本思想:类似于树的层次遍历
(1)从图中某个顶点v0出发,首先访问v0
(2)依次访问v0的各个未被访问的邻接点
(3)分别从这些邻接点出发,依次访问他们的各个未被访问的邻接点
7.6 图的连通性
算法部分
8 查找
8.1 基本概念
平均查找长度:
ASL = P1C1 +... + PnCn ,其中P1 为查找列表中第i个元素的概率,Ci为找到列表中第i个元素时,
已经进行过的关键字比较次数
查找基本方法:比较式查找和计算式查找
比较式查找:分为 基于线性表的查找法 和 基于树的查找法
计算式查找法:HASH(哈希)查找法
8.2 基于线性表的查找法
分为:顺序查找、折半查找、分块查找
8.2.1 顺序查找
基本思想:用所给关键字与线性表中各元素的关键字逐个比较,直到成功或失败。
8.2.2 折半查找(二分查找)
基本思想:将表中间的位置记录的关键字与查找关键字比较,如果相等,则查找成功,否则将表分为前、后两个子表,如果中间位置
记录的关键字大于查找关键字,则进一步查找前半子表(假设从前外后依次增大),否则查找后半子表。
特点:这种方法要求带查找的列表必须是按照关键字大小有序排列的顺序表
优点:比较次数少,查找速度快
缺点:要求待查表为有序表,且插入删除困难,适用于不经常变动且查找频繁的有序表
8.2.3 分块查找
8.3 基于树的查找法
分为:二叉排序树,平衡二叉树,B_树
8.3.1 二叉排序树
定义:二叉排序树或者是一棵空树,或者具有如下性质:
(1)左子树非空,则左子树上所有结点的值均小于根结点的值
(2)右子树非空,则右子树上所有结点的值均大于根结点的值
(3)他的左右子树也分别是二叉排序树
8.3.2 平衡二叉树
定义:平衡二叉树或者是一棵空树,或者具有如下性质
(1)左子树与右子树的高度差的绝对值小于等于1
(2)左子树和右子树也是平衡二叉树
8.3.3 B_树
- m路查找树
定义:一棵m路查找树,或是一棵空树,或者满足如下性质:
(1)每个结点最多有m棵子树,m-1个关键字,结构如下:
其中n为关键字个数,Pi为指向子树根结点的指针,Ki为关键字
(2)Ki
(4)子树P0中的关键字均小于K1,而子树Pn中的所有关键字均大于Kn
(5)子树Pi也是m路查找树
- B_树
定义:一棵B_树是一棵平衡的m路查找树,它或是空树,或满足如下性质
(1)树中每个结点最多有m棵子树
(2)根结点至少有两颗子树
(3)除根结点外,所有非叶子结点至少[m/2]棵子树
(4)所有叶子结点出现在同一层并且不包含信息,通常称为失败结点。
8.4 计算式查找法-哈希法
8.4.1 基本思想和概念
基本思想:在元素的关键字k和元素存储位置p之间建立一个对应关系,是的p=H(k),H称为哈希函数,
以后当查找元素k时,利用哈希函数计算除该元素的存储地址,从而达到按关键字直接存取元素的目的。
冲突:关键字不同的元素k1、k2,可能会映射到哈希表的同一个地址上,这种现象叫做冲突
同义词:k1和k2就是同义词
8.4.2 哈希函数的构造方法
原则:(1)函数本身便于计算;(2)计算出来的地址分布均匀,即对任一关键字k,H(k)对应不同地址的概率相等,目的是为减少冲突;
1.数字分析法
2.平方取中法
3.分段叠加法
4.除留取余法
基本思想:
5.伪随机数法
基本思想:采用一个伪随机函数作为哈希函数,即H(key)=random(key)
8.4.3 处理冲突的方法
构造性能良好的哈希函数,可以减少冲突,但不能完全避免
1.开放定址法(再散列法)
基本思想:由关键码得到的哈希地址一旦产生了冲突,也就是说,该地址已经存放了数据元素,按照某种探测规则去寻找下一个空的哈希地址,
只要哈希表足够大,空的哈希地址总能找到,并将数据元素存入。
探测规则:线性探测、二次探测、伪随机探测
2.再哈希法
基本思想:同时构造多个不同的哈希函数,Hi=RHi(key),当哈希地址H1发生冲突时,在计算H2...直到冲突不再产生
3.链地址法
基本思想:将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因此
查找、插入和删除主要在同义词链中进行。适用于经常插入和删除的情况。
4.建立公共溢出区
基本思想:将哈希表分为基本表和溢出表两部分,凡是与基本表发生冲突的元素一律填入溢出表。
8.4.4 哈希表查找过程
基本思想:查找过程与创建过程是一致的。当查找关键字为K的元素时,首先计算Po = H(K),若Po为空,则所查元素不存在,反之,则找到所查元素;
否则重复解决冲突的过程,按解决冲突的方法,找出下一个哈希地址pi,如果pi为空,则所查元素不存在,反之,找到所查元素。
8.4.5 哈希法性能分析
哈希法中影响关键字比较次数的因素有三个:哈希函数、处理冲突的方法、哈希表的装填因子。
哈希表装填因子 a = 哈希表中元素个数/哈希表的长度
9 排序
9.1 基本概念
内部排序:整个排序过程完全在内存中进行
外部排序:排序时需要借助外部存储设备才能完成
稳定排序:待排序的记录序列中可能存在两个或两个以上关键字相等的记录。排序前的序列中Ri领先于Rj(即i
9.2 插入类排序
基本思想:在一个已排好序的记录子集上,每一步将下一个待排序的记录有序的插入已排好序的记录子集中,直到所有待排序记录全部插入为止。
9.2.1 直接插入排序
基本思想:把n个待排序的元素看成一个有序表和一个无序表,第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从前向后扫描,
把第三个数按大小插入到有序表中依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
时间复杂度:T = O(n^2)
空间复杂度:S = O(1)
稳定性:稳定
9.2.2 折半插入排序(直接插入的改良版)
基本思想:与直接插入排序一样,与直接插入算法的区别在于:在有序表中寻找待排序数据的正确位置时,使用了折半查找/二分查找
时间复杂度:T = O(n^2)
稳定性:稳定
9.2.3 表插入排序
基本思想:采用链表存储结构进行插入排序。先在带插入记录之前的有序子链表中查找应插入位置,然后将带插入记录插入链表。
由于只修改指针,所以表插入排序提高排序效率
时间复杂度:T = O(n^2)
稳定性:稳定
9.2.4 希尔排序(直接插入的改良版)
基本思想:先将待排序记录序列分割成若干个“较稀疏的”子序列,分别进行直接插入排序。经过上述粗略调整,整个序列中的记录
已经基本有序,最后再对全部记录进行一次直接插入排序。
稳定性:不稳定
9.3 交换类排序法
基本思想:通过交换逆序元素进行排序的方法
9.3.1 冒泡排序
基本思想:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。
然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成
稳定性:稳定
时间复杂度:O(n^2)
空间复杂度:O(1)
9.3.2 快速排序(冒泡排序改良版)
基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据
分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
稳定性:不稳定
时间复杂度:logn - n^2
9.4 选择类排序
基本思想:每一趟在n-i+1个记录中选取关键字最小的记录作为有序序列中第i个记录
9.4.1 简单选择排序
基本思想:第i趟简单排序是指通过n-i次关键字比较,从n-i+1个记录中选出最小的记录,并与第i个记录进行交换,直到所有记录排序完为止。
稳定性:不稳定
时间复杂度:O(n^2)
9.4.2 树形选择排序
基本思想:首先把待排序的n个记录关键字两两比较,取较小者,然后再在[n/2]个较小者中,采取同样方法进行比较,选出每两个中的较小者,
如此反复,直到选出最小关键字为止。再重复上述过程,直到所有记录全部输出为止。
稳定性:
时间复杂度:nlogn
9.4.3 堆排序(树形选择排序的改良)
基本思想:堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关
键字的记录变得简单。
大根堆:根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者的堆
小根堆:根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆
需要解决的两个问题:
- 堆调整
将完全二叉树根结点中的记录移除,此时根结点相当于空结点,从空结点的左右子结点中选出一个关键字较大(小)的记录,如果该记录的关键字大于待调
整记录的关键字,则将该记录上移至空结点中。此时,原来关键字较大的子结点相当于空结点,重复上述移动,直到空结点左右子结点的关键字均不大于待调整
记录关键字,此时将待调整记录放入空结点即可。
- 初建堆
一个任意序列可以看成对应的完全二叉树,由于叶子结点可以视为单元素的堆,因而可以反复利用堆调整,自底向上逐层把所有以非叶子结点为根的子树调
整为堆,直到将整个完全二叉树调整为堆。
稳定性:不稳定
时间复杂度:nlogn
9.5 归并排序
基本思想:将两个或两个以上的有序表合成一个新的有序表。
稳定性:稳定
时间复杂度:nlogn
空间复杂度:n
9.6 分配类排序
9.6.1 多关键字排序
9.6.2 链式基数排序
9.7 各种排序方法的综合比较