常用排序算法
概述
在程序设计中,经常需要将一组数列进行排序,这样更加方便统计与 查询。常用的排序方法有:冒泡排序、选择排序、插入排序、快速排序等。
排序算法的分类:
稳定排序:假设在待排序的文件中,存在两个或两个以上的记录具有相同的关键字,在用某种排序法排序后,若这些相同关键字的元素的相对次序仍然不变,则这种排序方法是稳定的。其中冒泡,插入,基数,归并属于稳定排序,选择,快速,希尔,堆属于不稳定排序。
就地排序:若排序算法所需的辅助空间并不依赖于问题的规模n,即辅助空间为O(1),则称为就地排序。
一 冒泡排序
冒泡排序是最常用的排序算法之一,它的排序过程:总是将小数往前放,大数向后放,类似水中气泡往上升的动作,故称为冒泡排序
1.1 基本思想
冒泡排序的基本思路是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到前面,将大的元素值移动到后面,这样较小的元素就像气泡一样从底部上升到顶部。每经过一轮就能够将无序区最大值移动到有序区的的第一个位置。
经过上面的描述,可知冒泡算法由双层循环实现,其中外层循环用于控制排序轮数,一般为待排序的数列长度减去1,因为最后一次循环只剩下一个元素,不需要再比较。而内层循环主要用于对比数列中两个相邻元素的大小,以确定是否需要交换位置,对比和交换次数随排序轮数而减少。这样我们可以得出,冒泡排序需要进行的比较次数为: (n-1) + (n-2) + ... + 1 = n*(n-1) / 2,因此冒泡排序的时间复杂度为O(n^2)。
1.2 算法图解
一个拥有6个元素的列表,在排序过程中的每一次循环的排序过程如下图所示:
第一轮外层循环时将最大的元素值45移动到了最后,第二轮外层循环不再对比最后一个元素值45,因为它已经被确认为最大,需要移动和对比的是其他剩余元素,这次将35移动到了45的前一个位置。其他循环依次类推,完成排序工作。
1.3 代码实现
L = [1, 35, 24, 18, 45, 9]
for i in range(1,len(L)): # 外层循环,控制排序轮数
for j in range(len(L)-i): # 内层循环,相邻元素比较,无序区,范围为:[0,len(L)-i]
if L[j] > L[j + 1]:
L[j],L[j + 1] = L[j + 1],L[j] # 满足条件,元素交换顺序
print(L) # [1, 9, 18, 24, 35, 45]
1.4 优缺点
优点:稳定
缺点:慢,每次只能移动相邻两个数据
二 选择排序
2.1 基本思想
每一趟从待排序的数列元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
具体操作为:将指定排序位置与其他元素分别对比,如果满足条件就交换元素值,注意这里区别冒泡排序,不是交换相邻元素,而是把满足条件的元素与指定的排序位置交换。举个例子:有一堆杂乱无章的物件,编号为1-10,现在需求将这些物件按照1,2,3…10的顺序排列,我们第一次选出1,放在第一个位置,第二次选出2,放在第二个位置,以此类推,直到找到9放在8的后面,剩下的10就不用选择了,放在最后即可。这样一共需要进行n-1趟比较,第k趟比较需要进行的数组元素的两两比较的次数为n-k次,所以共需要的比较次数为n*(n-1) / 2,因此选择排序算法的时间复杂度与冒泡排序一样,也为O(n^2)。
与冒泡排序相比,直接选择排序的交换次数要少得多,所以速度会快一点。
2.2 算法图解
还是以拥有6个元素的列表进行图解说明:
2.3 代码实现
L = [11, 35, 24, 18, 45, 9]
for i in range(len(L)-1): # 循环次数
min_index = i # 指定最小数索引
for j in range(i + 1, len(L)): # 从i+1索引开始向后循环
if L[j] < L[min_index]: # 两个位置依次进行比较,如果后面的一个比最小的那个位置还小,重新赋值最小值索引
min_index = j
L[i], L[min_index] = L[min_index], L[i] # 指定位置元素与最小值进行替换
print(L) # [9, 11, 18, 24, 35, 45]
说明:内循环每次比较后,满足条件将最小数索引重新赋值,循环结束后才真正进行元素值交换。
2.4 优缺点
优点:移动数据的次数已知(n-1次)。
缺点:比较次数多,不稳定。
三 插入排序
3.1 基本思想
先描述一下生活中玩扑克抓牌的情形,通常我们用右手抓牌,每抓一张牌,就放到左手上,抓下一张牌后,会把这张牌依次与左手上的牌比较,并把它插入到一个合适的位置(通常按照牌面大小)。上述的过程即为插入排序的过程,假设待排序数组为L,我们从L[1]开始,让L[1]与L[0]比较,若L[1]较小,则让L[1]和L[0]交换位置,此时L[0]和L[1]就相当于已经放入左手中的牌。然后我们再让L[2]与L[1]、L[0]比较,并为它找到一个合适的位置,以此类推,直到为数列的最后一个元素找到了合适的位置。
理解了插入排序的思想后,我们便能够得到它的时间复杂度。对于n个元素,一共需要进行n-1轮比较,而第k轮比较需要进行k次数组元素的两两比较,因此共需要进行的比较次数为:1 + 2 + ... + (n-1),所以插入排序的时间复杂度同冒泡排序一样,也为O(n^2)。
3.2 算法图解
3.3 代码实现
L = [11, 35, 24, 18, 45, 9]
for i in range(1,len(L)):
tmp = L[i] # 无序区的第一个数,可以理解为摸到的牌
j = i-1 # 有序区最后一个元素索引位置
while L[j] > tmp and j >= 0: # 依次与有序区元素比较,满足条件则将有序区元素向后移动,不满足条件则说明找到合适位置,跳出循环,执行下一步
L[j+1] = L[j]
j -= 1
L[j+1] = tmp # 找到合适位置,赋值
print(L) # [9, 11, 18, 24, 35, 45]
3.4 优缺点
优点:稳定,快
缺点:比较次数不一定,比较次数越多,插入点后的数据移动越多,特别是当数据总量庞大的时候,但用链表可以解决这个问题
四 快速排序
4.1 基本思想
假设有一个元素个数为n的待排序数列L,需将其按升序排列,首先任取数据L[x]作为基准,比较L[x]与其它数据并排序,使L[x]排在数据的第k位,并且使L[0]~L[k-1]中的每一个数据小于等于L[x],L[k+1]~L[n-1]中的每一个数据大于L[x],这样就使得前半部分的任何一个数从此以后都不再跟后半部分的数进行比较了,大大减少了数字间的比较次数,这个过程称为一趟快速排序。然后采用分治策略分别对L[0]~L[k-1]和L[k+1]~L[n-1]两组数据进行快速排序。这样我们很明显的得到快速排序的时间复杂度为:O(nlog2n)。
4.2 算法图解
假定有这样一个列表:
创建变量i=0(指向第一个数据), j=5(指向最后一个数据), k=11(赋值为第一个数据的值)。
我们要把所有比k小的数移动到k的左面,所以我们可以开始寻找比11小的数,从j开始,从右往左找,不断递减变量j的值,我们找到第一个下标4的数据比11小,于是把下标4的数据9移到下标0的位置,把下标0的数据11移到下标4,完成第一次比较,结果如下:
接着,开始第二次比较,这次要变成找比k大的了,而且要从前往后找了。递加变量i,发现下标1的数据是第一个比k大的,于是用下标1的数据35和j指向的下标5的数据的11做交换,数据状态变成下表:
我们称上面两次比较为一个循环。
接着,再重复上面的循环,直到i和j“碰头”,此时,i、j均为2,具体执行如下:
然后,对k两边的数据,再分组分别进行上述的过程,直到不能再分组为止。
4.3 代码实现
def quick_sort(lis, left, right):
'''
:param left: 列表的第一个索引
:param right: 列表的最后一个索引
'''
if right > left:
i = left
j = right
key = lis[i] # 第一个值
while i < j: # 只要左右未遇见
while i < j and lis[j] > key: # 找到列表右边比key小的值为止
j -= 1
# 把lis[i]跟lis[j]进行交换
lis[i] = lis[j]
lis[j] = key
while i < j and lis[i] <= key: # 找到key左边比key大或者等的值为止
i += 1
# 把lis[j](此时应该刚存成了key)跟这个比key大的lis[i]进行调换
lis[j] = lis[i]
lis[i] = key
quick_sort(lis, left, i - 1) # 用同样的方式对分出来的左边的小组进行同上的做法
quick_sort(lis, i + 1, right) # 用同样的方式对分出来的右边的小组进行同上的做法
if __name__ == '__main__':
lis = [11, 35, 24, 18, 45, 9]
print("before sort:", lis)
quick_sort(lis, 0, len(lis) - 1)
print("after sort:", lis)
4.4 优缺点
优点:极快,数据移动少
缺点:不稳定
未完待续。。。
优秀文章链接:
https://www.cnblogs.com/absfree/p/5469212.html
https://www.cnblogs.com/heyuquan/archive/2014/07/17/bubble-quick-sort.html










浙公网安备 33010602011771号