python学习笔记:算法之排序(sorting)

第一大类:基本排序算法

一、选择排序(selection sort)

打个比方:妈妈跟小朋友玩扑克牌,牌面数字分别是3、5、8、10、4

  • round 1: 妈妈问:“5个数字里哪个最小呀?”,小朋友回答:“3”,“对!”,于是妈妈拿走了3。
  • round 2:妈妈再问:“剩下的4个数字里哪个最小呀?”,小朋友再回答:“4”,妈妈再拿走了4。
  • round 3:“3个里面哪个最小?”,“5”,拿走5。
  • round 4:“2个里面哪个最小?”,“8”,拿走8。
  • round 5:最后,妈妈排好了序:3 4 5 8 10 。

>>核心思想:搜索整个列表,找到最小项的位置,如果该位置不是列表的第1个位置,则交换这两个位置的项;然后回到第2个位置,搜索除第1个位置外的剩余列表,找到最小项的位置,如果该位置不是列表的第2个位置,则交换这两个位置;如此重复,直到末项。
>>为什么叫选择排序?因为,每次会选择出一个最小项。

1.1 代码示例

"""
This function has no return and the original list is changed
"""
def selectionSort(lst):
    n=len(lst)
    if n>1:
        for i in range(n-1):
            minIndex=i
            for j in range(i+1,n):
                if lst[j]<lst[minIndex]:
                    minIndex=j
            if minIndex!=i:
                lst[i],lst[minIndex]=lst[minIndex],lst[i]

1.2 时间复杂度

(1) 最好情况: O ( n 2 ) O(n^2) O(n2)
(2) 最坏情况: O ( n 2 ) O(n^2) O(n2)
(3) 平均情况: O ( n 2 ) O(n^2) O(n2)

情况情况分析
最好情况如果列表本身已经排好序,那么需执行 n − 1 n-1 n1次寻找最小项的操作,每次执行 n − 1 、 n − 2 、 . . . 、 1 n-1、n-2、...、1 n1n2...1次比较操作,即: O ( n 2 ) O(n^2) O(n2)
最坏情况如果列表是倒序的,那么算法需执行 n n n次寻找最小项的操作,且每次需分别执行 n − 1 n-1 n1 n − 2 n-2 n2、… 1 1 1次赋值操作和 1 1 1次位置交换操作,即: O ( n 2 ) O(n^2) O(n2)
平均情况 O ( n 2 ) O(n^2) O(n2)

1.3 算法过程

l s t = [ 1 , 3 , 4 , 8 , 9 , 2 , 5 ] 为 例 lst=[1,3,4,8,9,2,5]为例 lst=[1,3,4,8,9,2,5]
selection sort

二、冒泡排序(bubble sort)

妈妈跟小朋友继续用五张牌(3、5、8、10、4)玩游戏:

  • round 1:妈妈问:“3和5哪个大呀?”,答:“5大。”, 牌面不动。
  • round 2:“5和8哪个大呀?”,答:“8大。”,牌面不动。
  • round 3:“8和10哪个大呀?”,答:“10大。”,牌面不动。
  • round 4:“10和4哪个大呀?”,答:“10大。”,妈妈交换了4和10的位置,把10放一边:3、5、8、4、10
  • round 5:妈妈再从头问一遍:“3和5?”,答:“5”,牌面不动。(虽然有点傻)
  • round 6:“5和8?”,“8”,牌面不动。(傻 2 ^2 2
  • round 7:“8和4?”,“8“,交换8和4的位置,把8放一边:3、5、4、8、10
  • round 8:从头再来一遍:“3和5?”,“5”,牌面不动。
  • round 9:“5和4?”,“5”,交换5和4的位置。
  • round 10:“5和8?”,“8”,牌面不动,把5放一边:3、4、5、8、10
  • round 11:“3和4?”,“4”,牌面不动,结束

>>核心思想: repeatedly compare and swap ( if necesarily) two elements. (循环遍历输入列表进行两两比较,依次获得最大/小值)

2.1 代码示例

def bubbleSort(lst):
    n=len(lst)
    while n>1:
         for i in range(n-1):
             if lst[i]>lst[i+1]:
                lst[i],lst[i+1]=lst[i+1],lst[i]
        n-=1

2.2 时间复杂度

(1) 最好情况: O ( n 2 ) O(n^2) O(n2)
(2) 最坏情况: O ( n 2 ) O(n^2) O(n2)
(3) 平均情况: O ( n 2 ) O(n^2) O(n2)

情况情况分析
无论什么情况算法都需执行 n − 1 n-1 n1次冒泡操作,每次冒泡分别需执行 n − 1 、 n − 2... 、 1 n-1、n-2...、1 n1n2...1次比较操作(+交换操作),即: O ( n 2 ) O(n^2) O(n2)

2.3 算法过程

l s t = [ 1 , 3 , 4 , 8 , 2 , 5 , 9 ] lst=[1,3,4,8,2,5,9] lst=[1,3,4,8,2,5,9]为例:
bubble sort

三、插入排序(insertion sort)

这个算法类似于抓扑克牌:将新抓的1张牌插入手中牌里正确的位置,显然,手里的牌是排好序的,关键在于如何正确判断新牌的正确位置。
我们假设手里有: 1 、 2 、 3 、 8 1、2、3、8 1238 四张牌,新的牌为 5 5 5,先判断 5 5 5 8 8 8的关系( 5 &lt; 8 5&lt;8 5<8),继续判断 5 5 5 3 3 3的关系( 5 &gt; 3 5&gt;3 5>3),至此可以判断 5 5 5应该插入到 3 3 3后面的位置, 5 5 5一定比 &lt; 3 &lt;3 <3的前序数字大。>>>即,新数字插入第一个比它小的数字后面。

3.1 算法示例

def insertionSort(lst):
    n=len(lst)
    if n>1:
    for i in range(1,n):
        j=i-1
        while(j>=0):
            if lst[i]<lst[j]:
                j-=1
            else:
                break
        lst.insert(j+1,lst.pop(i))

3.2 时间复杂度

(1) 最好情况: O ( n ) O(n) O(n)
(2) 最坏情况: O ( n 2 ) O(n^2) O(n2)
(3) 平均情况: O ( n 2 ) O(n^2) O(n2)

情况情况分析
最好情况如果列表本身已经排好序,那么只需执行 n − 1 n-1 n1次比较操作,即: O ( n ) O(n) O(n)
最坏情况如果列表是倒序的,那么算法需分别执行 1 1 1 2 2 2、… n − 1 n-1 n1次比较操作和1次插入操作,即: O ( n 2 ) O(n^2) O(n2)
平均情况从最好情况到最坏情况,关键在于比较操作次数,比较操作平均次数近似等于 ( 1 + . . . + n ( n − 1 ) / 2 ) / ( n ( n − 1 ) / 2 ) 即 : (1+...+n(n-1)/2)/(n(n-1)/2)即: (1+...+n(n1)/2)/(n(n1)/2)O(n^2)$

第二大类快速排序算法

一、算法策略

快速排序算法是基于分而治之(divide-and-conquer)的思想,大致策略如下:

  • 从列表中选取一项作为基准点(可以是任意项、首项、尾项、中间项等各种选取方法);
  • 以基准点为基准,划分列表,使得所有小于基准点的项移动到基准点左边,其他项移动到基准点右边,一次划分结束后,基准点的位置就确定了;
  • 分而治之,对在基准点分割列表后形成的子列表递归地重复上述两个步骤,直至子列表少于2项,此时结束。

二、算法特点

  • 基准点选取方法的不同会使得每次分割后形成的2个子列表长度不同,进而导致算法时间复杂度的差异。例如:若每次分割后的子列表长度相等,即实现了“二分”,那么,经过 l o g n logn logn此分割后结束,算法性能为 O ( n l o g n ) O(nlogn) O(nlogn);若每次分割形成长度为1和长度为X-1的子列表,则大约需 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2次后结束,算法性能为 O ( n 2 ) O(n^2) O(n2)
    因此,快速排序策略的时间复杂度如下:
    • 最好情况: O ( n l o g n ) O(nlogn) O(nlogn)
    • 最坏情况: O ( n 2 ) O(n^2) O(n2)

四、归并排序(merge sort)

>>核心思想:分治法sort blocks of 1’s into 2’s, 2’s into 4’s, etc, on each pass merging sorted blocks into sorted larger blocks.(将输入列表分为长度1为的n个子序列,循环进行两两合并排序)
>>Note: This is the theoretical best-possible Big-O for comparison-based sorting! (理论上,归并排序是时间复杂度最优的基于比较策略的排序算法)

  • 时间复杂度: O ( N l o g N ) O(NlogN) O(NlogN)

  • 第一步,将 N N N个元素看作 N N N个子序列,将 N N N个子序列两两合并并排序,长度为 2 2 2 N / 2 N/2 N/2个子序列均得到了排序。

  • 第二步,将 N / 2 N/2 N/2个子序列两两合并并排序,长度为 2 2 2^2 22 N / 2 2 N/2^2 N/22个子序列得到了排序。

  • k k k步,将2个子序列合并排序,即长度为 2 k = N 2^k=N 2k=N的序列得到了排序。

    显然, k = l o g 2 N k=log_2N k=log2N,每一步需进行复杂度为 O ( N ) O(N) O(N)的比较和拷贝等操作, k ∗ O ( N ) = O ( N l o g N ) k*O(N)=O(NlogN) kO(N)=O(NlogN)。这里, l o g N 表 示 l o g 2 N logN表示log_2N logNlog2N
    merge-sort
    注:https://blog.csdn.net/xiaozhimonica/article/details/89470129

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值