幾種排序算法的學習,利用Python和C實現

以前學過的都忘了,也沒好好作過總結,如今總結一下。python

 

 

時間複雜度和空間複雜度的概念:算法

一、空間複雜度:
是程序運行因此須要的額外消耗存儲空間,通常的遞歸算法就要有o(n)的空間複雜度了,簡單說就是遞歸集算時一般是反覆調用同一個方法,遞歸n次,就須要n個空間。

二、時間複雜度:
一個算法花費的時間與算法中語句的執行次數成正比例,哪一個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度或時間頻度。記爲T(n)。
通常狀況下,算法中基本操做重複執行的次數是問題規模n的某個函數,用T(n)表示,如有某個輔助函數f(n),使得當n趨近於無窮大時,T(n)/f (n)的極限值爲不等於零的常數,則稱f(n)是T(n)的同數量級函數。記做T(n)=O(f(n)),稱O(f(n)) 爲算法的漸進時間複雜度,簡稱時間複雜度。
在各類不一樣算法中,若算法中語句執行次數爲一個常數,則時間複雜度爲O(1),另外,在時間頻度不相同時,時間複雜度有可能相同,如T(n)=n2+3n+4與T(n)=4n2+2n+1它們的頻度不一樣,但時間複雜度相同,都爲O(n2)。

按數量級遞增排列,常見的時間複雜度有:

常數階O(1),對數階O(log2n),線性階O(n),

線性對數階O(nlog2n),平方階O(n2),立方階O(n3),...,

目前我已經學過的排序算法包括數組

一、二次排序:app

     一、插入排序dom

     二、選擇排序函數

二、遞歸排序:spa

   一、歸併排序code

   二、快速排序htm

三、希爾排序blog

四、冒泡排序

 

1、冒泡排序

原理:  冒泡排序就是把小的元素往前調或者把大的元素日後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。

評價:是效率最低的一種排序算法。

時間複雜度:最差和平均均爲O(n2)

穩定性:因爲相等的元素不須要交換,因此比較穩定

代碼:

C實現:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int msort(int array[],int n)
{
    int exchange = 0;
        int i,j;
        i=j=0;
    for(i=0;i<n;i++)
    {
        j=n-1;
        while(j > i)
        {
            int temp=0;
            //printf("%d",array[j]);
            if (array[j]<array[j-1])
            {
                temp = array[j];
                printf("%d",temp);
                array[j] = array[j-1];
                array[j-1] = temp;
                exchange = 1;
            }
            j=j-1;
        }
        if (exchange == 0)
            break;
    }
    for(i=0;i<n;i++)
        printf("%d\n",array[i]);
}

int main(void)
{
    int SIZE=9;
    int array[9]={5,2,8,2,7,9,10,20,15};
    int i=0;
    for(i=0;i<SIZE;i++)
        printf("%d\n",array[i]);
    msort(array,SIZE);
    return 0;
}


                

 

Python實現:

import timeit

def  msort(array):
    exchange=False
    for i in xrange(len(array)):
        j=len(array)-1
        while(j>i):
            if array[j]<array[j-1]:
                array[j-1],arra[j]=array[j],array[j-1]
                exchange=True
            j=j-1
        if exchange!=True:
            break

    print array

def main():
    array=list(range(0,10000))
    msort(array)

        

if __name__=="__main__":
    t=timeit.Timer("main()",'from __main__ import main')
    print t.timeit(1)

 

2、選擇排序

原理:簡單點說就是從數組第一個位置開始,給每一個位置在剩餘的元素中都找到最小的值放上去。

評價:因爲每次都要尋找最值,因此選擇排序效率不高

時間複雜度:最壞,最優和平均時間複雜度都是O(n2).

穩定性:因爲交換,可能致使相等元素的先後順序發生變化,因此不穩定。好比 舉個例子,序列5 8 5 2 9, 咱們知道第一遍選擇第1個元素5會和2交換,那麼原序列中25的相對先後順序就被破壞了

代碼:

C實現:

#include<stdio.h>
#include<stdlib.h>

void ssort(int array[],int n)
{
    int i,j;
    int small;
    for(i=0;i<n;i++)
    {
        small=i;
        for(j=i+1;j<n;j++)
        {
            if (array[j]<array[small])
                small=j;
        }
        int temp=0;
        if (small!=i)
        {
            temp=array[i];
            array[i]=array[small];
            array[small]=temp;
        }
    }
    for(i=0;i<n;i++)
        printf("%d ",array[i]);

}


int main(void)
{
    int array[7]={7,3,1,6,4,2,8};
    ssort(array,7);
}

 

Python實現:

def ssort(array):

    for i in xrange(0,len(array)):
        j=i+1
        small=i
        while j<len(array):
            if array[j]<array[small]:
                small=j;
            j+=1
        if i!=small:
            array[small],array[i] = array[i],array[small]

    return array




array=[2,62,7,3,8,1,1]
print 'any',all(array)
print ssort(array)

 

 

3、插入排序:

原理:爲當前有序序列插入元素,插入到正確的位置。 固然,剛開始這個有序的小序列只有1個元素,就是第一個元素。比較是從有序序列的末尾開 始,也就是想要插入的元素和已經有序的最大者開始比起,若是比它大則直接插入在其後面,不然一直往前找直到找到它該插入的位置。

評價:對於比較有序的數組列表來講,效率是線性的,至關快。

穩定度:若是遇見一個和插入元素相 等的,那麼插入元素把想插入的元素放在相等元素的後面。因此,相等元素的先後順序沒有改變,從原無序序列出去的順序就是排好序後的順序,因此插入排序是穩 定的。

時間複雜度:最差的狀況是逆序的,須要O(n2),平均也是O(n2),最優的是線性的。

C實現

#include<stdio.h>
#include<stdlib.h>

int isort(int array[],int n)
{
    int i=0;
    int j;
    for(i=1;i<n;i++)
    {
        int temp=array[i];
        for(j=i;j>0&&array[j-1]>temp;j--)
        {
            array[j]=array[j-1];
        }
        array[j]=temp;
    }
    for(i=0;i<7;i++)
    {
        printf("%d ",array[i]);
}
}


int main(void)
{
    int array[7]={8,2,7,1,9,3,0};
    int result[7];
    isort(array,7);
}

Python實現:

def isort(array):
    for i in xrange(1,len(array)):
        temp=array[i]
        j=i
        while j>0 and array[j-1]>temp:
            array[j]=array[j-1]
            j=j-1
        array[j]=temp
    return array

    

print isort([6,3,2,1,8,4])

 

4、歸併排序

原理:採用分治法,將數組分紅兩部分元素,如此下去,知道只剩下一個元素,採用遞歸調用。兩部分數組比較,須要一個臨時數組,存儲有序值。

評價:算法很快,可是須要分配臨時數組,耗費內存。

穩定度:因爲在比較時,兩個相等值能夠保證位置不變,因此是穩定的。

時間複雜度:最優,最差和平均都是O(nlogn)

代碼:

Python:

def merge(L1,L2):
    sorted_array=[]
    while L1 and L2:
        if L1[0] <= L2[0]:
            sorted_array.append(L1.pop(0))
        else:
            sorted_array.append(L2.pop(0))          
    if L1:
        sorted_array.extend(L1)             
    if L2:
        sorted_array.extend(L2)
    return sorted_array

def mersort(array):
    if len(array)<=1:
        return array
    center=int(len(array)/2)
    return merge(mersort(array[:center]),mersort(array[center:]))


if __name__=="__main__":
    array=[8,20,15,4,6,3,7,2,1,9]
    print mersort(array)
    

 

5、快速排序

原理:和歸併排序的思想是相同的,都採用分治法,可是不一樣的是須要選擇一個基準數,根據基準數把數組分爲兩段,比基準數小的在左邊,比基準數大的在右邊。左右兩邊再分別採用這種方法,如此遞歸調用下去,知道只剩下一個元素。

評價:關鍵是找到基準數,基準數通常是隨機選擇三個值,選擇中間值,或者選擇數組第一個元素,可是若是第一個元素是最小的或最大的就糟糕了。

穩定性:不穩定。 好比序列爲 5 3 3 4 3 8 9 10 11, 如今基準元素53(5個元素,下標從1開始計)交換就會把元素3的穩定性打亂,因此快速排序是一個不穩定的排序算法

時間複雜度:最壞的狀況是O(n2),最好喝平均都是O(nlogn)

python實現:

import random

def partition(array,left,right):
    
    if right-left==1:
        if array[left]>array[right]:
            array[left],array[right]=array[right],array[left]
        return None

    base=array[left]
    big_index,small_index = left+1,right
    while big_index < small_index:
        while array[big_index] <= base and big_index < right:
            big_index += 1
        while array[small_index] >= base and small_index > left:
            small_index -=1
        if big_index < small_index:
            array[big_index],array[small_index] = array[small_index],array[big_index]
    array[left],array[small_index] = array[small_index],base
    return small_index

def qsort(array,left,right):
    if  right > left:
        mid=partition(array,left,right)
        if mid is not None:
            qsort(array,left,mid)
            qsort(array,mid+1,right)



if __name__=="__main__":
    array=[]
    for i in xrange(0,50):
        array.append(random.randint(0,30))
    qsort(array,0,(len(array)-1))
    print array




      

其實快速排對大數組頗有效率,但若是小數組,插入排序比較好,經驗代表,元素數目小於15時,能夠改成插入排序

Python:

import random
from insert.isort import import isort
def partition(array,left,right):
    
    if right-left==1:
        if array[left]>array[right]:
            array[left],array[right]=array[right],array[left]
        return None

    base=array[left]
    big_index,small_index = left+1,right
    while big_index < small_index:
        while array[big_index] <= base and big_index < right:
            big_index += 1
        while array[small_index] >= base and small_index > left:
            small_index -=1
        if big_index < small_index:
            array[big_index],array[small_index] = array[small_index],array[big_index]
    array[left],array[small_index] = array[small_index],base
    return small_index

def qsort(array,left,right):
    if  right-left>15:
        mid=partition(array,left,right)
        if mid is not None:
            qsort(array,left,mid)
            qsort(array,mid+1,right)
    else:
        isort(array)
        



if __name__=="__main__":
    array=[]
    for i in xrange(0,50):
        array.append(random.randint(0,30))
    qsort(array,0,(len(array)-1))
    print array

 

 

6、希爾排序

原理:採用不一樣的步長,分別進行插入排序,直到步長爲1.原理解釋最直觀的以下:

例如,假設有這樣一組數[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],若是咱們以步長爲5開始進行排序,咱們能夠經過將這列表放在有5列的表中來更好地描述算法,這樣他們就應該看起來是這樣:

13 14 94 33 82

25 59 94 65 23

45 27 73 25 39

10

而後咱們對每列進行排序:

10 14 73 25 23

13 27 94 33 39

25 59 94 65 82

45

將上述四行數字,依序接在一塊兒時咱們獲得:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].這時10已經移至正確位置了,而後再以3爲步長進行排序:

10 14 73

25 23 13

27 94 33

39 25 59

94 65 82

45

排序以後變爲:

10 14 13

25 23 33

27 25 59

39 65 73

45 94 82

94

最後以1步長進行排序(此時就是簡單的插入排序了)。

 

評價:選擇步長是關鍵,選擇好了,比較快,通常步長初始選擇數組長度除以2,一直除以2,一直到步長爲1.

穩定度:不穩定,不一樣部分數組排序,頗有可能打破相等元素的順序。

時間複雜度:(摘抄):

須要大量的輔助空間,和歸併排序同樣容易實現。希爾排序是基於插入排序的一種算法, 在此算法基礎之上增長了一個新的特性,提升了效率。希爾排序的時間複雜度與增量序列的選取有關,例如希爾增量時間複雜度爲O(n²),而Hibbard增量的希爾排序的時間複雜度爲O(

),可是現今仍然沒有人能找出希爾排序的精確下界。希爾排序沒有快速排序算法快 O(n(logn)),所以中等大小規模表現良好,對規模很是大的數據排序不是最優選擇。可是比O(

)複雜度的算法快得多。而且希爾排序很是容易實現,算法代碼短而簡單。 此外,希爾算法在最壞的狀況下和平均狀況下執行效率相差不是不少,與此同時快速排序在最壞的狀況下執行的效率會很是差。專家們提倡,幾乎任何排序工做在開始時均可以用希爾排序,若在實際使用中證實它不夠快,再改爲快速排序這樣更高級的排序算法. 本質上講,希爾排序算法是直接插入排序算法的一種改進,減小了其複製的次數,速度要快不少。 緣由是,當n值很大時數據項每一趟排序須要的個數不多,但數據項的距離很長。當n值減少時每一趟須要和動的數據增多,此時已經接近於它們排序後的最終位置。 正是這兩種狀況的結合才使希爾排序效率比插入排序高不少。

 

Python實現:

def shsort(array):
    interval = len(array)/2
    while interval >= 1:
        i = interval
        while i < len(array):
            if array[i] < array[i-interval]:
                j=i-interval
                temp=array[i]
                while j >=0 and array[j] >temp:
                    array[j+interval]=array[j]
                    j-=interval
                array[j+interval]=temp
            i+=1
        interval/=2

    return array


if __name__=="__main__":

    array=[3,6,9,5,7,4,8,2,1]
    print shsort(array)

 7、基數排序

原理:又名桶子排序,有10個桶。首先把個位數按照順序放到桶子中,個位數相同的就放在同一個桶子裏;而後再按照十位數的大小順序放到桶子裏,依次類推,最後獲得結果。

評價:基數排序的時間複雜度是 O(k·n),其中n是排序元素個數,k是數字位數。注意這不是說這個時間複雜度必定優於O(n·log(n)),k的大小取決於數字位的選擇(好比比特位數),和待排序數據所屬數據類型的全集的大小;k決定了進行多少輪處理,而n是每輪處理的操做數目。

以排序n個不一樣整數來舉例,假定這些整數以B爲底,這樣每位數都有B個不一樣的數字,k = logB(N),N是待排序數據類型全集的勢。雖然有B個不一樣的數字,須要B個不一樣的桶,但在每一輪處理中,判斷每一個待排序數據項只須要一次計算肯定對應數位的值,所以在每一輪處理的時候都須要平均n 次操做來把整數放到合適的桶中去,因此就有:

  • k 約等於 logB(N)

因此,基數排序的平均時間T就是:

T ~= log B( Nn

其中前一項是一個與輸入數據無關的常數,固然該項不必定小於logn

穩定度:很穩定. 基數排序基於分別排序,分別收集,因此其是穩定的排序算法

時間複雜度:O(k·n)

Python實現:

def rsort(array):
    length = len(str(max(array)))
    locat = 0
    while locat < length:
        bucket = []
        for n in xrange(0,10):
            bucket.append([])
        for i in array:
            index=i%10 if not locat else i/(locat*10)%10
            bucket[index].append(i)    
                
        array = []
        for i in bucket:
            array.extend(i)
        locat += 1
    return array
   
    
    
   
print rsort([35,8611,84,36,745,154,39,4,3])
        

 8、堆排序

原理:構成堆,將末端值與根節點交換

穩定度:不穩定

時間複雜度:nlogn

Python實現:

def make_heap(array,start,end):
    lchild = lambda x:2*x+1
    rchild = lambda x:2*x+2
    root = start
    while True:
        left = lchild(root)
        if left > end:
            break
        right = rchild(root)
        child = right if right <= end and array[left]<array[right] else left
        if array[child] <= array[root]:
            break
        else:
            array[root],array[child] = array[child],array[root]
            root = child

        
def list_heap(array):
    for i in xrange(len(array)/2,-1,-1):
        make_heap(array,i,len(array)-1)
  

def hsort(array):
    list_heap(array)
    for end in xrange(len(array)-1,0,-1):
        array[0],array[end] = array[end],array[0]
        make_heap(array,0,end-1)
    return array


if __name__=="__main__":    array=[3,7,1,8,230,56,100,34,12,40,9,54,67,24,26]   print hsort(array)

相關文章
相關標籤/搜索