知识总结7:数据结构中的经典排序算法总结(用Python实现各种排序算法)

Table of Contents

一.Bubble Sort(冒泡排序)

二. Selection Sort (选择排序)

三. Insertion Sort(插入排序)

四.Shell Sort(希尔排序)

五. Quick Sort(快速排序)

六.Merge Sort(归并排序)

七. Heap Sort(堆排序)

八. Radix Sort / Count Sort(基数排序 / 计数排序)

九.内部排序和外部排序


一.Bubble Sort(冒泡排序)


过程: 
1. 从0位置开始,比较相邻两个数的大小,如果后面的数小于前面,则交换位置。 
2. 遍历一遍下来,最后一个数为整个数组中的最大值。 
3. 把最后一个数排除,继续比较剩下的数组。 
4. 总共比较次数为N*N,时间复杂度为O(n²)。

def bubble_sort(blist):
    count = len(blist)
    for i in range(0, count):
        for j in range(i + 1, count):
            if blist[i] > blist[j]:
                blist[i], blist[j] = blist[j], blist[i]
    return blist
 
 
blist = bubble_sort([4, 5, 6, 7, 3, 2, 6, 9, 8])
print(blist)

 

二. Selection Sort (选择排序)

过程:

  1. 遍历一遍,找到整个数组中最小的数,与位置0的数交换位置。
  2. 从1位置开始,继续遍历,找到最小的数,与1位置交换。以此类推。

冒泡排序,复杂度为O(n²)。

def select_sort(slist):
    for i in range(len(slist) - 1):
        x = i
        for j in range(i, len(slist)):
            if slist[j] < slist[x]:
                x = j
        slist[i], slist[x] = slist[x], slist[i]
    return slist
 
slist = select_sort([4,5,6,7,3,2,6,9,8])
print slist

 

三. Insertion Sort(插入排序)


过程:

1.从1位置开始,比较与前面数的大小,如果小于前面的数,则交换位置,直到不再小于停止。
2.接着从2位置开始,重复这个过程。直到最后位置为止。
3.时间复杂度取决于数组的排序情况,当数组基本有序时候,复杂度很低,接近O(n)。当数组完全无序时,每个数都要经过多次移动,复杂度趋近于O(n²)。

def insert_sort(ilist):
    for i in range(len(ilist)):
        for j in range(i):
            if ilist[i] < ilist[j]:
                ilist.insert(j, ilist.pop(i))
                break
    return ilist
 
ilist = insert_sort([4,5,6,7,3,2,6,9,8])
print ilist

 

四.Shell Sort(希尔排序)


过程: 
1. 过程类似于插入排序,算是插入排序的一种优化。 
2. 首先,需要确定一个步长k,根据步长,把数组分为N/k部分,每一部分单独排序。 
3. 把步长缩短,继续排序,直到步长为1。 
4. 通过步长,减少了数组需要移动的次数,从而降低了复杂度。 
5. 所以复杂度的高低完全取决于步长的好坏,是一种特别不稳定的算法,也是一种实现简单分析困难的算法。

 

五. Quick Sort(快速排序)


需要重点掌握:

快速排序是一种很重要也很常用的排序,也有一些很重要的应用,比如说BFPRT算法,荷兰国旗问题。
快速排序如果每次都选到最大值,或者最小值,就会产生最坏的情况,使复杂度达到O(n²)级别。但是可以通过随机选择partition值,从数学期望上避免这种情况的发生。所以可以默认其复杂度为O(N * lg N)。
一般默认快速排序是非稳定的。
过程:

1.随机选出一个partition值,把大于partition值的放在它右边,小于它的放在它左边。
2.从partition值的左右两边分割,调用自己,开始递归。
3.这里有一点优化,因为partition值在数组中可能不止一个,因此返回一个长度为2的数组,代表partition的左右边界,从边界两端进行递归,更加快速。

def quick_sort(qlist):
    if qlist == []:
        return []
    else:
        qfirst = qlist[0]
        qless = quick_sort([l for l in qlist[1:] if l < qfirst])
        qmore = quick_sort([m for m in qlist[1:] if m >= qfirst])
        return qless + [qfirst] + qmore
 
qlist = quick_sort([4,5,6,7,3,2,6,9,8])
print (qlist)

 

六.Merge Sort(归并排序)

 

需要重点掌握:

归并排序的优势很明显,它是稳定排序。同时相对于快排,它占用较多的空间。
递归的思想很重要,分治法的应用也很广泛,把大问题分解成小问题一步步解决。
递归过程要掌握,递归过程一定要有一个终止条件。
压栈的过程,空间的占用要理解。
默认空间复杂度 O(n)。
过程:

1.把数组分成两部分,分别比较大小,最后合并。
2.递归调用自己。

 

七. Heap Sort(堆排序)


重点:

堆排序是一种复杂度很稳定的算法,没有最差或者最好,稳定的 n * lg N。
堆排序可以拓展到优先队列的实现,在贪心算法中经常用到。
过程:

可以按照顺序来建立完全二叉树

首先用数组构造一个大根堆。
把大根堆队顶和最后位置的元素交换位置,最后一个元素脱离大根堆,即数组长度减一。
队顶下沉,再次构造大根堆,重复这个过程,直至完全排序。

 

八. Radix Sort / Count Sort(基数排序 / 计数排序)


桶排序(Bucket Sort)属于非比较排序,因此适用范围很窄,但是在特定问题上可以把时间复杂度做到 O(n)。
桶排序只是一个概念,一种非比较排序的思想。基数排序和计数排序都算桶排序的一种落地(实现)。
计数排序(Count Sort)
适用范围:

计数排序适用于明确范围的数字排序
过程:

找的数组最大值max,new出来max+1个桶。
遍历整个数组,把数组里的数全部扔到对应的桶里。
从第一个桶开始遍历所有桶,把遍历的值填充到原来的数组中。
其他:

计算排序其实可以优化,但这个瓶颈会一直存在。即必须为一定范围内的数组集合。

基数排序(Radix Sort)
过程:

首先需要理解一点:当个位排好顺序时,再对十位开始排序时,个位的相对位置不变。
什么叫相对位置?比如对23,26,58,93进行排序,个位排好后是23,93,26,58。
这时再对十位进行排序,23,26的相对位置是不会变的,排序结束为23,26,58,93。
这个思维过程有点像动态规划,把问题分为n个小步骤,每个下一步都会用到上一步的结果。


 排序的稳定性指的是排序算法的空间和时间复杂度不随待排序序列的变化而变化

九.内部排序和外部排序

由于待排序的记录数量不同,使得排序过程中涉及的存储器不同,可将排序方法分为两大类:内部排序与外部排序。

概念

内部排序:待排序记录存放在计算机随机存储器中(说简单点,就是内存)进行的排序过程。

外部排序:待排序记录的数量很大,以致于内存不能一次容纳全部记录,所以在排序过程中需要对外存进行访问的排序过程。

从概念我们可以清晰的看到二者的区别

衡量效率的方法

内部排序:比较次数,也就是时间复杂度

外部排序:IO次数,也就是读写外存的次数

排序方法

内部排序:插入排序、快速排序、选择排序、归并排序、基数排序等

外部排序:多路平衡归并;置换-选择排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值