| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 排序算法原理及实现 -> 正文阅读 |
|
[数据结构与算法]排序算法原理及实现 |
稳定性: 例:原序列中假设(3,1)和(3,7)的顺序是(3,1)(3,7),如果排完序,这两个顺序没变,还是(3,1)(3,7),就说明是稳定的,如果变了,就说明不稳定。 冒泡排序方法:从第一个数开始,每次只对比两个数,如果后面的比前面的小则交换位置,否则不换位置,拿较大的数继续往后比对,一直跑到最后。 两种循环实现冒泡排序: ? 选择排序方法:第一步从序列中选出最小的和第一个换位置;第二步从剩余的数中选出最小的和第二个换位置;依次进行。(不稳定:升序,选择最大的数的时候会不稳定。) 选择排序实现: ? 插入排序方法:把序列分成两部分,第一个数视为第一部分有序数列,剩余的是无序的。从无序中拿出一个和有序数列,从后往前对比,碰到比它大的继续往前比较,直到碰到比它小的停止。 插入排序实现: 希尔排序方法:取一定的步长,根据步长先分出数个序列,对每一个进行插入排序。后减小步长重新分出序列,继续进行插入排序,直到步长为1,或者排序完成。 希尔排序实现: ?代码前问题解决: 1.如何判断排序完成:---没判断,就持续缩短步长去执行,但由于使用的是while 循环,中间有break 跳出,所以如果顺序原本就是正常的,时间复杂度会降低。 2.减去步长后,超出索引范围怎么办?---循环增加条件 i > 0 的时候执行即可。 3.步长怎么选?---可以使用减半的方式,但不能保证是最优的。 4.要搞出子序列再挨个排序好麻烦---没搞出子序列,而是使用一次循环,通过减去步长的方式对“等价子序列”进行了排序。 快速排序方法(重要):设置两个指针,左边定为low(即比抽出的数小),右边定为high(比抽出的数大)。抽出第一个数a,开始移动指针,若low所指的数比a小,则继续移动,反之开始移动high指针,若high所指的数比a大,则继续移动,反之停止,交换两个指针所指的数,重复以上移动指针+交换数据的步骤,直到找到a的正确位置。之后左右两边均执行相同操作。 快速排序实现: 代码过程中问题解决: 1.递归使用时,传入的列表应当是列表本身,并对本身的某段进行处理,才会对列表本身修改。如果递归以切片的形式传入到函数中,其实是对产生的新列表处理,无法达到排序效果。 2.左右两个指针不能使用同一个循环跑,否则第一遍循环可能是对的,但是第二遍的时候就又会对不该处理的指针进行处理。因此,让两个指针有各自的循环最合适。 3.递归终止条件是什么?最终分的每部分只剩1个数据的时候就完成了递归,此时两个指针位置一样,所以索引相等。但不能设置成start == end,而是需要start>=end就终止。否则可能在最后一步,当start就是最后一个数据的时候,传入的数据是start+1,就会出现超出索引(当设置好比end大的时候就会返回,不会出现这个错误。),也可能出现无限递归。 4.时间复杂度最优是O(nlogn),最坏是O(n^2)。 最优:每次分成两半的时候,都正好全是偶数,每一个都正好能分成两半,最终分的每一个都只剩一个,因此会分2*2*2*2...次,每分一次就乘2,所以最终分的次数就是求分了2的多少次才把n分成了单个的(拆分之前用了循环)。也就是log2为底的n,时间复杂度为logn,那么每一次分完都需要进行一次快速排序,相当于遍历一次,时间复杂度是O(n),那么整体的就是O(nlogn)。 最坏:每次分的时候,就分出了一个数据,所以纵向需要分n次。整体就是n*n 归并排序方法:将列表对半拆分,再对小列表对半拆分,再对半一直到所有小列表都只剩1个元素。之后,将每一对小列表按照数据大小顺序合并成中列表,再同样的方法把中列表一步一步合成大列表,最终完成排序。使用递归方法。 归并排序实现: ? 代码过程中问题解决: 1.使用递归时,主要看三个部分:前两层的拆分方式;最后两层的合并方式及返回值;以及拆到头之后的返回值。 2.拆分完列表到哪去了,怎么找到他们使用?--拆分完找不到他们,因为还在通过“前两层的拆分方式”继续拆,只有拆到最后一个了,使用“拆到头之后的返回值”,才可以找到最后一个小列表,然后通过“最后两层的合并方式及返回值”,把小列表合并才能得到上一级列表的返回值。因此使用的时候是通过递归逐步合并,就假装合并完了,想想返回值是什么,直接用返回值进行后面的操作实现就行。 3.归并排序是创建了新的列表,因此原列表并未改变,最终需要将返回值赋给一个新变量才可打印出来。并且由于有新的列表,是需要占额外的存储空间的。 4.拆分的时候,时间复杂度是O(1),因为是直接使用了切片的方式,也没有循环。合并时,横向是n,纵向是logn,类似于快速排序。因此时间复杂度是nlogn。稳定。最好最坏的时间复杂度一致。 搜索:在一个特定的项目集合中找到一个特定的项目。 二分法查找:也叫做折半查找,从序列的中间位置截一下,跟中间数据对比,看看所需要找的数据落在哪一半,就在那一半继续从中间位置截,重复此操作。二分法特点:操作对象必须有序并且有下标,因此只能用顺序表。 二分法递归实现: 二分法非递归实现:非递归操作的是下标,不对列表进行修改。 代码中问题解答: 1.递归的结束条件,应当设置一个条件,在符合这个条件的情况下进行递归,如果不符合就直接返回。 2.和中间位置对比后,无论是前一段还是后一段数据,都不包含中间数据。不要忘记+1等操作进行调整。 3.时间复杂度:最优为O(1),比如第一个中间值就是需要找的。最坏为logn,假设n=4, 第一次减半后,两边为2,第二次减半为1,抵达终点。要求2的多少次方等于n:假如n=4,则结果为2,时间复杂度就是log2为底4的对数 = 2。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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/25 23:43:46- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |