| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 9. 数据结构--内排序 -> 正文阅读 |
|
[数据结构与算法]9. 数据结构--内排序 |
内排序首先学这一章的时候发现,标题是内排序 但是之后也没学外排序,那么内排序和外排序到底是啥意思类?知识盲区了哈哈哈,以下是百度的结果: 大纲
排序的基本概念给定一组记录r1,r2,…rn,其排序码分别为 k 1 , k 2 , … , k n k_1,k_2, …,k_n k1?,k2?,…,kn?,将这些记录排成顺序为 r s 1 , r s 2 , … , r s n r_{s1},r_{s2},…,r_{sn} rs1?,rs2?,…,rsn?的一个序列S,满足条件 k s 1 ≤ k s 2 ≤ k s n k_{s1}≤k_{s2}≤k_{sn} ks1?≤ks2?≤ksn?
一、三种代价为 O ( n 2 ) O(n^2) O(n2)的排序方法1. 直接插入排序1.1 算法基本思想和过程1. 基本思想逐个处理待排序的记录。每个新记录与前面已排序的子序列进行比较,将它插入到子序列中正确的位置。 2. 算法过程1.在A[1…i-1]中查找A[i]的插入位置,A[1…j].key ≤ A[i].key < A[j+1…i-1].key; 1.2 算法示例1.3 算法伪代码定义了一个swap函数,用于交换数组中两个位置的元素
第二个循环在干什么? 1.4 算法分析问题:
1.5 特点
2. 冒泡排序2.1 算法基本思想和过程1. 基本思想比较并交换相邻元素对, 直到所有元 素都被放到正确的地方为止 2. 算法过程输入一个记录数组A,存放着n条记录 湖大的冒泡与众不同(尴尬): 每次都从数组的底部(存放最后一个记录)开始,
2.2 算法示例2.3 算法伪代码
问题:改进点在哪? 2.4 算法分析问题:
2.5 特点
3. 选择排序3.1 算法基本思想和过程1. 基本思想第i次时“选择”序列中第i小的记录,并把该记录放到序列的第i个位置上。 2. 算法过程输入一个记录数组A,存放着n条记录
3.2 算法示例3.3 算法伪代码
3.4 算法分析最好最坏,比较次数都相同,对n个记录进行简单选择排序,所需进行的关键字间的比较次数总计为 3.5 特点
4. 总结二、希尔排序动机: 插入排序算法简单,在n值较小时,效率比较高; 在n值很大时,若序列按关键码基本有序,效率依然较高,其时间效率可提高到O(n)。 1. 算法基本思想和过程1.1 基本思想基本思想: 先将整个待排记录序列分割成若干个较小的子序 列,对子序列分别进行插入排序,然后把有序子序列组合起来;待整个序列中的记录“基本有序 ”时, 再对全体记录进行一次插入排序 1.2 算法过程希尔排序过程: 输入一个记录数组A,存放着n条记录,以及一个(递 减)增量序列数组按照递减的次序(例如 8 4 2 1)
基于增量的插入排序: 输入一个记录数组A,起始位置i,结束位置n,增量incr
2. 算法示例3. 算法伪代码
4. 算法分析分析Shell排序是很困难的,因此我们必须不加证明地承认Shell排序的平均运行时间是 Θ ( n 1 . 5 ) Θ(n^1.5) Θ(n1.5)(对于选 择“增量每次除以3”递减)。选取其他增量序列 可以减少这个上界。因此,Shell排序确实比插入 排序或任何一种运行时间为 θ ( n 2 ) \theta (n^2) θ(n2)的排序算法要快 有人在大量实验的基础上推出,当n在某个特定范围 内,所需比较和移动次数约为 n 1 . 3 n^1.3 n1.3 当 n → ∞ n \rightarrow \infty n→∞ 时,可减少到$n(log_2n)^2 $ 5.特点
三、快速排序动机: 分治思想:划分交换排序 1. 算法基本思想和过程1.1 基本思想在待排序记录中选取一个记录R(称为轴值pivot), 通过一趟排序将其余待排记录分割(划分)成独立 的两部分,比R小的记录放在R之前,比R大的记录 放在R之后,然后分别对R前后两部分记录继续进行 同样的划分交换排序,直至待排序序列长度等于1, 这时整个序列有序 1.2 算法过程快速排序过程:快速排序(划分过程)用递归实现。
选取轴值,划分序列的过程: 记录数组A,待排子序列左、右两端的下标i和j 选取待排序子序列中间位置的记录为轴值 交换轴值和位置j的值 依据在位置j的轴值, 将数组i-1到j之间的待排序记录划分为两个部分(i到k-1之间的记录比轴值小,k到j-1之间的 记录比轴值大) 从数组i-1到j之间的待排序序列两端向中间移动下标, 必要时交换记录,直到两端的下标相遇为止(相遇的位 置记为k) 交换轴值和位置k的值 PS :基准数的选择具体看题目 2. 算法示例选取第一个数为基准数为例: 先从右往左找一个小于pivot的数,再从左往右找一个大于pivot的数,然后交换他们。 这里可以用两个变量i 和 j,分别指向序列最左边和最右边。 刚开始的时候让i指向序列的最左边,指向0位置。让j指向序列的最右边,指向n-1。 首先j开始移动,找到第一个小于pivot的位置,然后i向右移动,找到第一个大于pivot的位置 以选取中间位置为pivot为例 描述一下第一趟的过程吧! 3. 算法伪代码
4. 算法分析时间开销: T ( n ) = { D ( 1 ) n < = 1 D ( n ) + T ( I 1 ) + T ( I 2 ) n > 1 T(n)=\begin{cases} {D(1)}&&n <=1\\ {D(n)+T(I_1)+T(I_2)}&&n>1 \end{cases} T(n)={D(1)D(n)+T(I1?)+T(I2?)??n<=1n>1?
空间开销
5. 特点
快速排序的优化:
四、归并排序动机: 分治思想 1. 算法基本思想和过程1.1 基本思想基本思想: 将两个或多个有序表归并成一个有序表 1.2 算法过程2 路归并排序
合并两个有序子序列的过程:记录数组A,起始位置left,结束位置right,中间点mid
2. 算法示例3. 算法伪代码
4. 算法分析设需排序元素的数目为n,递归的深度为$logn $(简单起见,设n是2的幂) 第一层递归是对一 个长度为n的数组排序,下一层是对两个长度为 n/2的子数组排序,…,最后一层对n个长度为1 的子数组排序。 时间复杂度:T(n)=O(nlog2n) 在最佳、平均、最差情况下,时间复杂度为 θ ( n l o g n ) \theta(n log n) θ(nlogn) 递归代码的空间复杂度并不能像时间复杂度那样累加。尽管每次合并操作都需要申请额外的内存空间,但在合并完成之后,临时开辟的内存空间就被释放掉了。在任意时刻,CPU 只会有一个函数在执行,也就只会有一个临时的内存空间在使用。临时内存空间最大也不会超过 n 个数据的大小,所以空间复杂度是 O(n)。 5. 特点
五、堆排序选择排序:树形选择排序,最值堆 1. 算法基本思想和过程1.1 基本思想首先将数组转化为一个满足堆定义的序列。 然后将堆顶的最值取出,再将剩下的数排成堆,再 取堆顶数值,…,如此下去,直到堆为空,就可 得到一个有序序列 1.2 算法过程还记得堆的移除堆顶操作吗? 建堆:将输入序列用数组存储,利用堆的构建函数将数组转化为一个满足堆定义的序列(如果是递增排序, 则构建最大值堆,反之,构建最小值堆) 然后将堆顶的最大元素取出,再将剩下的数排成堆,再 取堆顶数值,…,如此下去,直到堆为空。 每次应将堆顶的最大元素取出放到数组的最后。 假设n个元素存于数组中的0到n-1位置上。把堆顶元 素取出时,应该将它置于数组的第n-1个位置。这时 堆中元素的数目为n-1个。再按照堆的定义重新排列 堆,取出最大值并放入数组的第n-2个位置。到最后 结束时,就排出了一个由小到大排列的数组
2. 算法示例3. 算法伪代码之前都有,懒得翻了我 之前的博客呀 4. 算法分析堆排序的时间代价:
堆排序的空间代价: 常数辅助空间: θ ( 1 ) \theta(1) θ(1) 过程有些复杂,总之堆排序的时间复杂度为 θ ( n l o g n ) \theta(nlogn) θ(nlogn) 5. 特点? 基于堆数据结构,具有许多优点: 整棵树是平衡的,而且它的数组实现方式 对空间的利用率也很高,可以利用有效 的建堆函数一次性把所有值装入数组中。 堆排序的最佳、平均、最差执行时间均为 θ ( n l o g n ) \theta(nlogn) θ(nlogn),空间开销也是常数 堆排序是不稳定的排序算法 更适合于外排序,处理那些数据集太大而不适合在内存中排序的情况 六、 分配排序桶排序和基数排序均属于分配排序。分配排序的基本思想:排序过程无须比较关键字,而是通过用额外的空间来"分配"和"收集"来实现排序,它们的时间复杂度可达到线性阶:O(n)。简言之就是:用空间换时间,所以性能与基于比较的排序才有数量级的提高! 1. 基数排序基数排序是对桶排序的一种改进,这种改进是让“桶排序”适合于更大的元素值集合的情况,而不是提高性能。 从最次的关键字开始排序,再从第二次的关键字排序,过程中参考第一次排序后元素间的相对顺序,以此类推直到最高关键字参考了次高关键的顺序而排序完成,排序结束。 比如字符串“abcd” “aesc” “dwsc” "rews"就可以把每个字符看成一个关键字。另外还有整数 425、321、235、432也可以每个位上的数字为一个关键字。 基数排序的思想就是将待排数据中的每组关键字依次进行桶分配。比如下面的待排序列:
我们将每个数值的个位,十位,百位分成三个关键字: 278 -> k1(个位)=8 ,k2(十位)=7 ,k3=(百位)=2。 然后从最低位个位开始(从最次关键字开始),对所有数据的k1关键字进行桶分配(因为,每个数字都是 0-9的,因此桶大小为10),再依次输出桶中的数据得到下面的序列。
再对上面的序列接着进行针对k2的桶分配,输出序列为:
最后针对k3的桶分配,输出序列为:
很明显,基数排序的性能比桶排序要略差。每一次关键字的桶分配都需要O(N)的时间复杂度,而且分配之后得到新的关键字序列又需要O(N)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2N) ,当然d要远远小于N,因此基本上还是线性级别的。但是,对比桶排序,基数排序每次需要的桶的数量并不多。而且基数排序几乎不需要任何“比较”操作,而桶排序在桶相对较少的情况下,桶内多个数据必须进行基于比较操作的排序。 待排序数组[62,14,59,88,16]简单点五个数字 分配10个桶,桶编号为0-9,以个位数数字为桶编号依次入桶,变成下边这样 | 0 | 0 | 62 | 0 | 14 | 0 | 16 | 0 | 88 | 59 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |桶编号 将桶里的数字顺序取出来, 输出结果:[62,14,16,88,59] 再次入桶,不过这次以十位数的数字为准,进入相应的桶,变成下边这样: 由于前边做了个位数的排序,所以当十位数相等时,个位数字是由小到大的顺序入桶的,就是说,入完桶还是有序 | 0 | 14,16 | 0 | 0 | 0 | 59 | 62 | 0 | 88 | 0 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |桶编号 因为没有大过100的数字,没有百位数,所以到这排序完毕,顺序取出即可 最后输出结果:[14,16,59,62,88] 对于n个数据的序列,假设基数为r,这个算法需要k趟 分配工作。每趟分配的时间为Θ(n+r),因此总的时间开 销为Θ(nk+rk)。因为r是基数,它一般是比较小的。可 以把它看成是一个常数。变量k与关键码长度有关,它是 以r为基数时关键码可能具有的最大位数。在一些应用中 我们可以认为k是有限的,因此也可以把它看成是常数。 在这种假设下,基数排序的最佳、平均、最差时间代价 都是Θ(n),这使得基数排序成为我们所讨论过的具有最 好渐近复杂性的排序算法 2. 桶排序基本思想:设置若干个箱子,依次扫描待排序的记录 array[0],array[1],…,array[n - 1],把关键字等于 k 的记录全都装入到第 k 个箱子里(分配),然后按序号依次将各非空的箱子里的记录收集起来,从而完成排序。 举个例子:一年的全国高考考生人数为500万,分数使用标准分,最低100,最高900,没有小数,你把这500万元素(内容为分数)的数组排个序。 我们抓住了这么个非常特殊的条件,就能在毫秒级内完成这500万的排序,那就是:最低100,最高900,没有小数,那一共可出现的分数可能有多少种呢?一共有900-100+1=801,那么多种,想想看,有没有什么“投机取巧”的办法?方法就是创建801个“桶”,从头到尾遍历一次数组,对不同的分数给不同的“桶”加料. 比如有个考生考了500分,那么就给500分的那个桶(下标为500-100)加1,完成后遍历一下这个桶数组,按照桶值,填充原数组,100分的有1000人,于是从0填到999,都填1000,101分的有1200人,于是从1000到2019,都填入101.于是经过这次遍历之后所有记录都是有序的了。 很显然,如果分数不是从100到900的整数,而是从0到2亿,那就要分配2亿个桶了,这是不可能的,所以桶排序有其局限性,适合元素值集合并不大的情况。 当然桶里也可不止装一个元素,比如下图,在决定往那个桶插入的过程是用的关键字映射,但是实际插入具体桶时,可以用插入排序。 结论时间:
空间:
稳定排序?
参考资料: [1]https://blog.csdn.net/zcxwww/article/details/51439206 [2]杨晓波老师PPT |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 8:52:09- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |