排序算法總結以及python代碼實現

最近在找工作面試的時候總是會被問到排序算法的種種,現在對排序算法進行一個系統的總結。也算是再複習一遍的,有好多自己也忘得差不多了。


排序有內部排序和外部排序兩大類。內部排序值得是所有的排序是在內存中進行;外部排序則是因爲數據量太大,一次不能將全部數據放在內存中,在排序過程中,需要訪問外存。

spacer.gifwKioL1YbcrmA3MCeAAHx5kBeWIE174.jpg

關於時間複雜度和空間複雜度

    由於時間關係,我沒有自己畫,以下的表格是在別處轉的,詳見常用排序算法總結

                        wKiom1Ybc7WyN_ktAAOUTdyWHXg570.jpg  

wKioL1Ybc9LzvHuHAAIqJuh3C8w016.jpg

1.插入排序--直接插入排序(Straight Insertion Sort)

基本思想:

將一個記錄插入到已經有序的表中,從而得到一個新的,記錄數+1的有序表。即:先將序列的第一個記錄看成是一個有序的子序列,然後從第二個記錄逐個進行插入,直至整個序列有序爲止。

如果遇到元素相等時,那麼將插入的元素插入到與其相等的元素之後。相等元素的前後順序並沒有改變,所以插入排序是穩定的。

算法的實現:

def insertion_sort(arr):
        arrlen = len(arr)
        for i in range(1, arrlen):
            insert(arr, i)
    
def insert(arr, i):
        tmp = arr[i]
        j = i
        # 查找第i的元素應該的位置, 並且
        # 順便把比它大的元素往後挪 
        # 其實是用了心思在裏面的
        while j > 0 and tmp < arr[j - 1]:
            arr[j] = arr[j - 1]
            j -= 1
            arr[j] = tmp
a = [65,6,3,5,54,65]
insertion_sort(a)
print a

 2.希爾排序

基本思想:

希爾排序又叫做縮小增量排序。先將整個序列分割成若干個子序列,並對每個子序列進行直接插入排序,再對全部序列進行直接插入排序。

                        wKiom1YbiaHi_7B_AAEWU2ohFCA072.jpg


算法實現:

def shell_sort(seq):
    incr = len(seq)/2
    while(incr>=1):
        for i in range(incr,len(seq)):
            tmp=seq[i]
            pos=i;
            for j in range(i-incr,-1,-incr):
                if seq[j]>tmp:
                    seq[j+incr]=seq[j]
                    pos=j
            seq[pos]=tmp
        incr = incr/2  
    return seq
if __name__ == '__main__':  
    A = [10, -3, 5, 7, 1, 3, 7]    
    print 'Before sort:',A    
    shell_sort(A)    
    print 'After sort:',A

3.選擇排序--簡單選擇排序

基本思想:

在要排序的一組數中,選出最小(或者最大)的一個數與第1個位置的數交換;然後在剩下的數當中再找最小(或者最大)的與第2個位置的數交換,依次類推,直到第n-1個元素(倒數第二個數)和第n個元素(最後一個數)比較爲止。

算法實現:

def selectionSort(seq):
    length=len(seq)
    for i in range(length):
        mini=min(seq[i:])
        if seq[i]>mini:
            j=seq.index(mini,i)
            seq[i],seq[j]=seq[j],seq[i]


if __name__=='__main__':
    seq=[3,4,5,9,3,1,5,7,90,-2,]
    selectionSort(seq)
    print(seq)


效率:

最壞情況下,即待排序記錄初始狀態是按第一條記錄最大,之後的記錄從小到大順序排列,則需要移動記錄的次數最多爲3(n-1)。簡單選擇排序過程中需要進行的比較次數與初始狀態下待排序的記錄序列的排列情況無關。當i=1時,需進行n-1次比較;當i=2時,需進行n-2次比較;依次類推,共需要進行的比較次數是(n-1)+(n-2)+…+2+1=n(n-1)/2,即進行比較操作的時間複雜度爲O(n^2),進行移動操作的時間複雜度爲O(n)。(百度百科

簡單選擇排序是不穩定排序。



簡單選擇排序的改進——二元選擇排序

簡單選擇排序,每趟循環只能確定一個元素排序後的定位。我們可以考慮改進爲每趟循環確定兩個元素(當前趟最大和最小記錄)的位置,從而減少排序所需的循環次數。改進後對n個數據進行排序,最多隻需進行[n/2]趟循環即可。


4.選擇排序--堆排序

基本思想:

堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,它是選擇排序的一種。可以利用數組的特點快速定位指定索引的元素。堆分爲大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即A[PARENT[i]] >= A[i]。在數組的非降序排序中,需要使用的就是大根堆,因爲根據大根堆的要求可知,最大的值一定在堆頂。

堆排序的過程相對來說比較複雜,現只給出算法實現,詳細過程請參照另外一篇博文:堆排序學習筆記

算法實現:

def fixDown(a,k,n): #自頂向下堆化,從k開始堆化
	N=n-1
	while 2*k<=N:
		j=2*k
		if j<N and a[j]<a[j+1]: #選出左右孩子節點中更大的那個
			j+=1
		if a[k]<a[j]:
			a[k],a[j]=a[j],a[k]
			k=j
		else:
			break

def heapSort(l):
	n=len(l)-1
	for i in range(n//2,0,-1):
		fixDown(l,i,len(l))
	while n>1:
		l[1],l[n]=l[n],l[1]
		fixDown(l,1,n)
		n-=1
	return l[1:]

l=[-1,26,5,77,1,61,11,59,15,48,19] #第一個元素不用,佔位
res=heapSort(l)
print(res)

wKiom1YbntywVGmvAAD91O9CnxA624.jpg

5.交換排序--冒泡排序

基本思想:

在要排序的一組數中,對當前還未排好序的範圍內的全部數,自上而下對相鄰的兩個數依次進行比較和調整,讓較大的數往下沉,較小的數往上冒。即:每當相鄰的數比較後,發現排序不符合要求時,將他們互換。

示例:

wKiom1Ybwe_yBhTDAAHwxegrlhM430.jpgpython代碼實現:

#!/usr/bin/env python
#coding:utf-8
def bubbleSort(seq):
    length=len(seq)
    for i in range(length):
        for j in range(length-1,i,-1):
            if seq[j-1]>seq[j]:
                seq[j-1],seq[j]=seq[j],seq[j-1]


if __name__=='__main__':
    seq=[2,9,7,7,4,3,2,-4,54,-7,0]
    bubbleSort(seq)
    print(seq)

冒泡排序算法的改進(兩種)


    1. 設置一標誌性變量pos,用於記錄每趟排序中最後一次進行交換的位置。由於pos位置之後的記錄均已交換到位,故在進行下一趟排序時只要掃描到pos位置即可。

    2. 傳統冒泡排序中每一趟排序操作只能找到一個最大值或最小值,我們考慮利用在每趟排序中進行正向和反向兩遍冒泡的方法一次可以得到兩個最終值(最大者和最小者) , 從而使排序趟數幾乎減少了一半。

6. 交換排序—快速排序(Quick Sort)

本思想:

1)選擇一個基準元素,通常選擇第一個元素或者最後一個元素,

2)通過一趟排序講待排序的記錄分割成獨立的兩部分,其中一部分記錄的元素值均比基準元素值小。另一部分記錄的 元素值比基準值大。

3)此時基準元素在其排好序後的正確位置

4)然後分別對這兩部分記錄用同樣的方法繼續進行排序,直到整個序列有序。

示例:

                                      wKioL1YbxtCCsAz8AADuk4NPmU4294.jpg

python代碼實現:

#!/usr/bin/env python
#coding:utf-8
def qsort(seq):
    if seq==[]:
        return []
    else:
        pivot=seq[0]
        lesser=qsort([x for x in seq[1:] if x<pivot])
        greater=qsort([x for x in seq[1:] if x>=pivot])
        return lesser+[pivot]+greater

if __name__=='__main__':
    seq=[5,6,78,9,0,-1,2,3,-65,12]
    print(qsort(seq))

7. 歸併排序(Merge Sort)

基本思想:

歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分爲若干個子序列,每個子序列是有序的。然後再把有序子序列合併爲整體有序序列。

wKiom1Yb0_GR1OnFAAJj-LTFvpw029.jpg代碼實現:

def mergesort(seq):
	if len(seq)<=1:
		return seq
	mid=int(len(seq)/2)
	left=mergesort(seq[:mid])
	right=mergesort(seq[mid:])
	return merge(left,right)

def merge(left,right):
	result=[]
	i,j=0,0
	while i<len(left) and j<len(right):
		if left[i]<=right[j]:
			result.append(left[i])
			i+=1
		else:
			result.append(right[j])
			j+=1
	result+=left[i:]
	result+=right[j:]
	return result

if __name__=='__main__':
	seq=[4,5,7,9,7,5,1,0,7,-2,3,-99,6]
	print(mergesort(seq))	

效率:

時間複雜度不管在什麼情況下都爲n(nlogn)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章