总觉得,如果说什么是算法的起点,那就是排序算法,所以今天打算记录下跟排序算法相关的内容。
排序算法有太多类了,但最容易入门的,经典的,自然是冒泡排序。

冒泡排序

冒泡这个词很形象,就是大的或者小的,往单向传递:

  1. A(1)>A(2),则两者交换位置,从A(2)继续,直到A(n)是最大的。
  2. 再从A(1)开始,直到A(n-1)是第二轮最大的。
    ...
import numpy as np
import random
class Solution:
    def bubbleSort(self,arr):
        print('UnSortedArr',arr)
        n = len(arr)
        for i in range(n-1):
            for j in range(n-i-1):
                if arr[j]>arr[j+1]:
                    arr[j],arr[j+1]=arr[j+1],arr[j]
        print('SortedArr:',arr)
        return arr

f = Solution()
arr = list(np.random.randint(low=0,high=101,size=10))
f.bubbleSort(arr)

UnSortedArr [20 37 24 30 40 3 79 51 87 71]
SortedArr: [ 3 20 24 30 37 40 51 71 79 87]

这里的两个print用于初次引用函数时,对内部的数据进行简单监视,后面的按照自己的需求来。

归并排序

核心:分而治之
先看整体,如果一个数列,被砍成了两半,然后left,right中都是排好序了,那么把它们再合并成一个整体,过程就是不停对比left[0],right[0],谁小谁先放。
而left,right可以利用递归,按照相同的办法进行排序。
值得注意的是,Python内置的sorted算法就是归并算法,只是利用了底层实现,省却了很多开销,比我们用python编写的要快很多。

class Solution:
    def mergeSort(self,arr):
        if len(arr)<2:return arr

        middle = int(len(arr)/2)    # 砍成两部分
        left = self.mergeSort(arr[:middle])  # 调用递归
        right = self.mergeSort(arr[middle:])

        result = []  # 合并
        while left and right:
            result.append(left.pop(0) if left[0]<right[0] else right.pop(0))
        result.extend(left if left else right)

        return result

快速排序

20世纪最伟大的十大算法之一登场
核心思想:分而治之
随机取一个数,然后把比这个数小的都放left,大的都放right,然后对左右做同样的事。

class Solution:
    def quickSort(self,arr):
        if len(arr)<=1:return arr
        pivot = arr[0]  # 选取的轴心
        left = [x for x in arr[1:] if x<=pivot] # 这个等号不能漏,否则漏数
        right = [x for x in arr[1:] if x>pivot ]
        return self.quickSort(left)+[pivot]+self.quickSort(right)

基排序

对于数字来说,就说简单的正数吧,是由基构成的,789的基就是个位,十位,百位,基有3个,分别按照各个基来放进去就OK了,这个排序办法很符合人类对各个数的判断。先从高位判断和先从低位判断不影响最终结果。

class Solution:
    def baseSort(self,arr):
        arrStr= [str(x) for x in arr]
        maxN = max(arrStr,key=len)

        for i in range(1,len(maxN)+1):
            bracket = [[] for _ in range(10)]
            for x in arrStr:
                bracket[0].append(x) if len(x)<i else bracket[int(x[-i])].append(x)

            arrStr=[]
            for x in bracket:
                arrStr+=x
        return [int(x) for x in arrStr]

计数排序

把基排序的基拓展到极限,就是每一个数都有一个bracket,然后放进去。
开一个数列空间,大小为O(Max-Min),然后分别计数,最后输出。
值得注意的是,这个速度真的超级快啊,尤其是数据比较密集的时候。但是大分布小数据就比较不适合,根据业务不同要区别对待。

class Solution:
    def countSort(self,arr):
        minNum=min(arr)
        maxNum=max(arr)
        tmp = (maxNum-minNum+1)*[0]
        for i in arr:
            tmp[i-minNum]+=1

        res = []
        for i in range(len(tmp)):
            if tmp[i]:
                res+=[i+minNum]*tmp[i]
        return res

桶排序

桶排序其实应该是介于基排序与计数排序之间的,它比较灵活,可以自由拆解组合。
计数排序是每个数给个桶,这下桶的数量会有点多,如果按照每10个数给个桶,然后桶内用插入排序,就会很快,因为桶内一直是有序的,插入排序就会很快。

class Solution:
    def bucketSort(self,arr):
        maxNum=max(arr)
        bucket = [[] for x in range(int(maxNum/10)+1)]

        for i in arr:
            n=int(i/10)
            if bucket[n]==[]:
                bucket[n].append(i)
            else:   
                m= len(bucket[n])
                for j in range(m):
                    if i<=bucket[n][j]:
                        bucket[n].insert(j,i)
                        break
                if len(bucket[n])==m:
                    bucket[n].append(i)

        res = []
        for i in bucket:
            res+=i
        return res

最重要的,是掌握归并排序和快速排序,其它的了解思想即可,当有针对性业务时,才会有比较好的效果。