1. 程式人生 > >python對八大常見排序演算法的總結和實現以及時間消耗分析

python對八大常見排序演算法的總結和實現以及時間消耗分析

    昨晚上開始總結了一下常見的幾種排序演算法,由於之前我已經寫了好幾篇排序的演算法的相關博文了現在總結一下的話可以說是很方便的,這裡的目的是為了更加完整詳盡的總結一下這些排序演算法,為了複習基礎的東西,從氣泡排序、直接插入排序、選擇排序、歸併排序、希爾排序、桶排序、堆排序。快速排序入手來分析和實現,在最後也給出來了簡單的時間統計,重在原理、演算法基礎,其他的次之,這些東西的熟練掌握不算是對之後的工作或者接下來的準備面試都是很有幫助的,演算法重在理解內在含義和理論基礎,在實現的時候才能避開陷阱少出錯誤,這不是說練習的時候有錯誤不好而是說,有些不該出現的錯誤儘量還是少出現的好,畢竟好的程式設計習慣是離不開嚴格的約束的,好了,這裡就不多說了,複習一下基礎知識,共同學習吧,下面是具體實現,註釋應該都很詳細,就不解釋了:

#!usr/bin/env python
#encoding:utf-8

'''
__Author__:沂水寒城
功能:八大排序演算法
'''

import time
import random

time_dict={}

def time_deco(sort_func):
    '''
    時間計算的裝飾器函式,可用於計算函式執行時間
    '''
    def wrapper(num_list):
        start_time=time.time()
        res=sort_func(num_list)
        end_time=time.time()
        time_dict[str(sort_func)]=(end_time-start_time)*1000
        print '耗時為:',(end_time-start_time)*1000
        print '結果為:', res
    return wrapper


def random_nums_generator(max_value=1000, total_nums=20):
    '''
    隨機數列表生成器
    一些常用函式:
    random隨機數生成 
    random.random()用於生成一個0到1之間的隨機數:0 <= n < 1.0; 
    random.uniform(a, b),用於生成一個指定範圍內的隨機符點數,兩個引數其中一個是上限,一個是下限。min(a,b) <= n <= max(a,b); 
    randdom.randint(a, b), 用於生成一個指定範圍內的整數,其中a是下限,b是上限: a<= n <= b; 
    random.randrange(start, stop, step), 從指定範圍內,按指定基數遞增的集合獲取一個隨機數; 
    random.choice(sequence), 從序列中獲取一個隨機元素; 
    random.shuffle(x), 用於將一個列表中的元素打亂; 
    random.sample(sequence, k), 從指定序列中隨機獲取指定長度的片斷; 
    '''
    num_list=[]
    for i in range(total_nums):
        num_list.append(random.randint(0,max_value))
    return num_list


#@time_deco
def Bubble_sort(num_list):
    '''
    氣泡排序,時間複雜度O(n^2),空間複雜度O(1),是穩定排序
    '''
    for i in range(len(num_list)):
        for j in range(i,len(num_list)):
            if num_list[i]>num_list[j]:  #這裡是升序排序
                num_list[i], num_list[j]=num_list[j], num_list[i]
    return num_list


#@time_deco
def Insert_sort(num_list):
    '''
    直接插入排序,時間複雜度O(n^2),空間複雜度O(1),是穩定排序
    '''
    for i in range(len(num_list)):
        for j in range(0,i):
            if num_list[i]<num_list[j]:  #這裡是升序排序,跟氣泡排序差別在於,冒泡是向後遍歷,這個是向前遍歷
                num_list[i], num_list[j]=num_list[j], num_list[i]
    return num_list


#@time_deco
def Select_sort(num_list):
    '''
    選擇排序,時間複雜度O(n^2),空間複雜度O(1),不是穩定排序
    '''
    for i in range(len(num_list)):
        min_value_index=i 
        for j in range(i, len(num_list)):
            if num_list[j]<num_list[min_value_index]:
                min_value_index=j #乍一看,感覺冒泡,選擇,插入都很像,選擇跟冒泡的區別在於:冒泡是發現大
                                  #小數目順序不對就交換,而選擇排序是一輪遍歷結束後選出最小值才交換,效率更高
        num_list[i], num_list[min_value_index]=num_list[min_value_index], num_list[i] 
    return num_list


#@time_deco
def Merge_sort(num_list):
    '''
    歸併排序,時間複雜度O(nlog₂n),空間複雜度:O(1),是穩定排序
    '''
    if len(num_list)==1:
        return num_list
    length=len(num_list)/2
    list1=num_list[:length]
    list2=num_list[length:]
    result_list=[]
    while len(list1) and len(list2):
        if list1[0]<=list2[0]:
            result_list.append(list1[0])
            del list1[0]  #這裡需要刪除列表中已經被加入到加過列表中的元素,否則最後比較完後列表
        else:              #中剩餘元素無法新增
            result_list.append(list2[j])
            del list1[0] 
    if len(list1):  #遍歷比較完畢後列表中剩餘元素的新增
        result_list+=list1 
    else:
        result_list+=list2 
    return result_list


#@time_deco
def Shell_sort(num_list):  
    '''
    希爾排序,時間複雜度:O(n),空間複雜度:O(n^2),不是穩定排序演算法
    '''
    new_list = []  
    for one_num in num_list:  
        new_list.append(one_num)      
    count=len(new_list)  
    step=count/2;  
    while step>0:  
        i=0  
        while i<count:  
            j=i+step  
            while j<count:  
                t=new_list.pop(j)  
                k=j-step  
                while k>=0:  
                    if t>=new_list[k]:  
                        new_list.insert(k+1, t)  
                        break  
                    k=k-step                         
                if k<0:  
                    new_list.insert(0, t)  
                #print '---------本輪結果為:--------'  
                #print new_list                         
                j=j+step  
                #print j             
            i=i+1  
            #print i         
        step=step/2     #希爾排序是一個更新步長的演算法    
    return new_list


#@time_deco
def Tong_sort(num_list):  
    '''
    桶排序,時間複雜度O(1),空間複雜度與最大數字有關,可以認為是O(n),典型的空間換時間的做法
    '''
    original_list =  []  
    total_num=max(num_list)  #獲取桶的個數
    for i in range(total_num+1): #要注意這裡需要的陣列元素個數總數比total_num數多一個因為下標從0開始  
        original_list.append(0)  
    for num in num_list:  
        original_list[num] += 1  
    result_list = []  
    for j in range(len(original_list)):  
        if original_list[j] != 0:  
            for h in range(0,original_list[j]):  
                result_list.append(j)    
    return result_list  



def Quick_sort(num_list):
    '''
    快速排序,時間複雜度:O(nlog₂n),空間複雜度:O(nlog₂n),不是穩定排序
    '''   
    if len(num_list)<2:    
        return num_list    
    left_list = []  #存放比基準結點小的元素  
    right_list = []  #存放比基準元素大的元素  
    base_node = num_list.pop(0) #在這裡採用pop()方法的原因就是需要移除這個基準結點,並且賦值給base_node這個變數  
                                #在這裡不能使用del()方法,因為刪除之後無法再賦值給其他變數使用,導致最終資料缺失  
                                #快排每輪可以確定一個元素的位置,之後遞迴地對兩邊的元素進行排序  
    for one_num in num_list:    
        if one_num < base_node:    
            left_list.append(one_num)    
        else:    
            right_list.append(one_num)    
    return Quick_sort(left_list) + [base_node] + Quick_sort(right_list) 
 


def Heap_adjust(num_list, i, size):  
    left_child = 2*i+1  
    right_child = 2*i+2  
    max_temp = i  
    #print left_child, right_child, max_temp  
    if left_child<size and num_list[left_child]>num_list[max_temp]:  
        max_temp = left_child  
    if right_child<size and num_list[right_child]>num_list[max_temp]:  
        max_temp = right_child  
    if max_temp != i:  
        num_list[i], num_list[max_temp] = num_list[max_temp], num_list[i]  
        Heap_adjust(num_list, max_temp, size) #避免調整之後以max為父節點的子樹不是堆  
  
  
def Create_heap(num_list, size):  
    a = size/2-1  
    for i in range(a, -1, -1):  
        #print '**********', i  
        Heap_adjust(num_list, i, size)  
  
  
#@time_deco
def Heap_sort(num_list):
    '''
    堆排序,時間複雜度:O(nlog₂n),空間複雜度:O(1),不是穩定排序
    '''
    size=len(num_list)  
    Create_heap(num_list, size)  
    i = size-1  
    while i > 0:  
        num_list[0], num_list[i] = num_list[i], num_list[0]  
        size -= 1  
        i -= 1  
        Heap_adjust(num_list, 0, size)   
    return num_list 


if __name__ == '__main__':
    num_list=random_nums_generator(max_value=100, total_nums=50)
    print 'Bubble_sort', Bubble_sort(num_list)
    print 'Insert_sort', Insert_sort(num_list)
    print 'Select_sort', Select_sort(num_list)
    print 'Merge_sort', Merge_sort(num_list)
    print 'Shell_sort', Shell_sort(num_list)
    print 'Tong_sort', Tong_sort(num_list)
    print 'Heap_sort', Heap_sort(num_list)
    print  'Quick_sort', Quick_sort(num_list)
    # print '-----------------------------------------------------------------------------'
    # for k,v in time_dict.items():
    #     print k, v
結果如下:
Bubble_sort [34, 49, 63, 67, 71, 72, 75, 120, 128, 181, 185, 191, 202, 217, 241, 257, 259, 260, 289, 293, 295, 304, 311, 326, 362, 396, 401, 419, 423, 456, 525, 570, 618, 651, 701, 711, 717, 718, 752, 774, 813, 816, 845, 885, 894, 900, 918, 954, 976, 998]
Insert_sort [34, 49, 63, 67, 71, 72, 75, 120, 128, 181, 185, 191, 202, 217, 241, 257, 259, 260, 289, 293, 295, 304, 311, 326, 362, 396, 401, 419, 423, 456, 525, 570, 618, 651, 701, 711, 717, 718, 752, 774, 813, 816, 845, 885, 894, 900, 918, 954, 976, 998]
Select_sort [34, 49, 63, 67, 71, 72, 75, 120, 128, 181, 185, 191, 202, 217, 241, 257, 259, 260, 289, 293, 295, 304, 311, 326, 362, 396, 401, 419, 423, 456, 525, 570, 618, 651, 701, 711, 717, 718, 752, 774, 813, 816, 845, 885, 894, 900, 918, 954, 976, 998]
Merge_sort [34, 49, 63, 67, 71, 72, 75, 120, 128, 181, 185, 191, 202, 217, 241, 257, 259, 260, 289, 293, 295, 304, 311, 326, 362, 396, 401, 419, 423, 456, 525, 570, 618, 651, 701, 711, 717, 718, 752, 774, 813, 816, 845, 885, 894, 900, 918, 954, 976, 998]
Shell_sort [34, 49, 63, 67, 71, 72, 75, 120, 128, 181, 185, 191, 202, 217, 241, 257, 259, 260, 289, 293, 295, 304, 311, 326, 362, 396, 401, 419, 423, 456, 525, 570, 618, 651, 701, 711, 717, 718, 752, 774, 813, 816, 845, 885, 894, 900, 918, 954, 976, 998]
Tong_sort [34, 49, 63, 67, 71, 72, 75, 120, 128, 181, 185, 191, 202, 217, 241, 257, 259, 260, 289, 293, 295, 304, 311, 326, 362, 396, 401, 419, 423, 456, 525, 570, 618, 651, 701, 711, 717, 718, 752, 774, 813, 816, 845, 885, 894, 900, 918, 954, 976, 998]
Heap_sort [34, 49, 63, 67, 71, 72, 75, 120, 128, 181, 185, 191, 202, 217, 241, 257, 259, 260, 289, 293, 295, 304, 311, 326, 362, 396, 401, 419, 423, 456, 525, 570, 618, 651, 701, 711, 717, 718, 752, 774, 813, 816, 845, 885, 894, 900, 918, 954, 976, 998]
Quick_sort [34, 49, 63, 67, 71, 72, 75, 120, 128, 181, 185, 191, 202, 217, 241, 257, 259, 260, 289, 293, 295, 304, 311, 326, 362, 396, 401, 419, 423, 456, 525, 570, 618, 651, 701, 711, 717, 718, 752, 774, 813, 816, 845, 885, 894, 900, 918, 954, 976, 998]

    這裡沒有使用到裝飾器,主要自己對這個裝飾器不太瞭解,在快速排序的時候報錯了,也沒有去解決,這裡簡單貼一下一個測試樣例使用裝飾器的結果吧:
Bubble_sort 耗時為: 0.0290870666504
結果為: [5, 45, 46, 63, 81, 83, 89, 89, 89, 90]
None
Insert_sort 耗時為: 0.0209808349609
結果為: [5, 45, 46, 63, 81, 83, 89, 89, 89, 90]
None
Select_sort 耗時為: 0.0259876251221
結果為: [5, 45, 46, 63, 81, 83, 89, 89, 89, 90]
None
Merge_sort 耗時為: 0.0138282775879
結果為: [5, 45, 46, 63, 81, 83, 89, 89, 89, 90]
None
Shell_sort 耗時為: 0.113964080811
結果為: [5, 45, 46, 63, 81, 83, 89, 89, 89, 90]
None
Tong_sort 耗時為: 0.0460147857666
結果為: [5, 45, 46, 63, 81, 83, 89, 89, 89, 90]
None
Heap_sort 耗時為: 0.046968460083
結果為: [5, 45, 46, 63, 81, 83, 89, 89, 89, 90]
None
Quick_sort [5, 45, 46, 63, 81, 83, 89, 89, 89, 90]
-----------------------------------------------------------------------------
<function Shell_sort at 0x7f8ab9d34410> 0.113964080811
<function Select_sort at 0x7f8ab9d34230> 0.0259876251221
<function Insert_sort at 0x7f8ab9d34140> 0.0209808349609
<function Heap_sort at 0x7f8ab9d34758> 0.046968460083
<function Merge_sort at 0x7f8ab9d34320> 0.0138282775879
<function Tong_sort at 0x7f8ab9d34500> 0.0460147857666
<function Bubble_sort at 0x7f8ab9d34050> 0.0290870666504

   接下來有時間的話我想學一下裝飾器的東西,感覺對於模式化的東西裝飾器簡直就是一個神器,但是得明白會用會寫才行哈!

相關推薦

python八大常見排序演算法總結實現以及時間消耗分析

    昨晚上開始總結了一下常見的幾種排序演算法,由於之前我已經寫了好幾篇排序的演算法的相關博文了現在總結一下的話可以說是很方便的,這裡的目的是為了更加完整詳盡的總結一下這些排序演算法,為了複習基礎的東西,從氣泡排序、直接插入排序、選擇排序、歸併排序、希爾排序、桶排序、堆排

常見排序演算法總結實現原理,穩定度,使用場景,時間複雜度)

快速排序是目前基於比較的內部排序中被認為是最好的方法,當待排序的關鍵字是隨機分佈時,快速排序的平均時間最短;堆排序所需的輔助空間少於快速排序,並且不會出現快速排序可能出現的最壞情況。這兩種排序都是不穩定的。若要求排序穩定,則可選用歸併排序。但本章介紹的從單個記錄起進行兩兩歸併的排序演算法並不值得提倡,通常可以

各種排序演算法總結比較

       排序演算法可以說是一項基本功,解決實際問題中經常遇到,針對實際資料的特點選擇合適的排序演算法可以使程式獲得更高的效率,有時候排序的穩定性還是實際問題中必須考慮的,這篇部落格對常見的排序演算法進行整理,包括:插入排序、選擇排序、氣泡排序、快速排序、堆排序、歸併

常見排序演算法總結及效能比較

一.常見排序演算法有哪些 二. 插入排序 1.直接插入排序 基本思想:插入排序是每次將一個待排序的記錄,按照大小,插入到前面已經排好的有序區中適當的位置,直到將所有記錄插入完位置。大概思想是將待

常見的五類排序演算法圖解實現(歸併類:二路歸併排序

歸併類的排序演算法 歸併:將兩個或兩個以上的有序表組合成一個新的有序表。 內部排序中,通常採用的是 2-路歸併排序。即:將兩個位置相鄰的記錄有序子序列歸併為一個記錄有序的序列。歸併排序是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法(Divide and

八大內部排序演算法總結

插入排序:直接插入排序 思想:將資料分為兩組,一組為已排序序列,另一組為待排序序列,不斷的將待排序序列加入已排序序列。最終得到的是已排序序列。 public class InsertionSort implements Sort{ public void sort(i

常見排序演算法總結(基於C++實現

1.插入排序 1.1 直接插入 基本思想: 將待排序表看作左右兩部分,其中左邊為有序區,右邊為無序區,整個排序過程就是將右邊無序區中的元素逐個插入到左邊的有序區中,以構成新的有序區。 template<typename T> void

常見排序演算法總結分析之交換排序與插入排序-C#實現

# 前言 每每遇到關於排序演算法的問題總是不能很好的解決,對一些概念,思想以及具體實現的認識也是模稜兩可。歸根結底,還是掌握不夠熟練。以前只是看別人寫,看了就忘。現在打算自己寫,寫些自己的東西,做個總結。本篇是這個總結的開始,所以我們先來闡述一下本次總結中會用到的一些概念。 排序是如何分類的?可以從不同的的角

常見排序演算法總結分析之選擇排序與歸併排序-C#實現

本篇文章對選擇排序中的簡單選擇排序與堆排序,以及常用的歸併排序做一個總結分析。 [常見排序演算法總結分析之交換排序與插入排序-C#實現](https://www.cnblogs.com/iwiniwin/p/12589405.html)是排序演算法總結系列的首篇文章,包含了一些概念的介紹以及交換排序(冒泡與

必須知道的八大排序演算法【java實現

各種演算法的時間複雜度: package com.lianxi; import java.util.Arrays; public class Sort { /** * 八種排序演算法 */ public static void main(String[] args) {

十大經典排序演算法總結——Java實現

轉自:https://blog.csdn.net/wangqyoho/article/details/52584640#t5 引 這段時間博主逐步替換為Java的實現 //博主留 2017.9.15 //2017.10.10完成氣泡排序的修改

必須知道的八大排序演算法【java實現】(三) 歸併排序演算法、堆排序演算法詳解

一、歸併排序演算法 基本思想:   歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合併為整體有序序列。 歸併排序示例:   合併方法: 設r[i…n]由兩個有序子表r[i…m]和r[m+1…n]組

必須知道的八大排序演算法【java實現】(二) 選擇排序,插入排序,希爾演算法【詳解】

一、選擇排序   1、基本思想:在要排序的一組數中,選出最小的一個數與第一個位置的數交換;然後在剩下的數當中再找最小的與第二個位置的數交換,如此迴圈到倒數第二個數和最後一個數比較為止。   2、例項   3、演算法實現    /** * 選擇排序演算法 * 在未

必須知道的八大排序演算法【java實現】(一) 氣泡排序、快速排序

氣泡排序   氣泡排序是一種簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。   氣泡排序的示例:   氣

常見排序演算法之JavaScript實現

// 被拆分的陣列重新合併 function merge(left, right) { var result = [], left_index = 0, right_index = 0; // 將兩個數組合並 // 合併的時候按從小到大的順序

排序演算法總結 java實現

import java.util.Arrays;public class SortTest {public static void main(String[] args) {// TODO Auto-generated method stubint[] a = {13,25,

常見排序演算法及JAVA實現

排序演算法的分類 先看維基百科中的一張關於排序演算法的表 我們主要了解常見的一些排序演算法。像Bogo排序,臭皮匠排序這類完全不實用的排序可以置之不理。 我們這裡要說的排序演算法都是內排序,也就是隻在記憶體中進行,涉及到對磁碟等外部儲存裝置中的資

路徑最短問題演算法總結實現(Floyd,Dijkstra,SPFA)

題目描述:求兩個點之間的最短路徑輸入:兩個整數n,m(1<=n,m<=100)n的含義是節點的個數,m的含義是邊的個數,接下來的m行輸入三個整數i j c,分別表示開始結束節點和之間的費用輸出:從1到n節點之間的路徑長度Floyd演算法:使用二維陣列ans[i][

7種常見排序演算法的c++實現

今天心血來潮複習了一下基本的排序演算法,實現了一下,就順便發上來咯。。在程式碼裡做了註釋了-。-也就不多說了,直接上程式碼吧。。// order_algorithm.cpp: 定義控制檯應用程式的入口點。 //author: netbin #include "stdafx.

常見排序演算法的Javascript實現

近日準備實習面試,以下是常見排序演算法JS實現,轉載備用。原文連結 JavaScript實現排序演算法 氣泡排序 氣泡排序的基本思想是從頭遍歷要排序的陣列,比較相鄰兩個數,如果前面位置的數大於後面位置的數,那麼就將兩者進行交換,否則不做任何