排序算法原理及实现

稳定性:

例:原序列中假设(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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值