常見(jiàn)排序算法心得-侏儒,快速,冒泡,選擇

幾種算法實(shí)例

-- 記錄了幾種比較常用的算法,具體的也參考了很多文章,下面是我自己記錄.侏儒 ,冒泡,選擇,插入,快速排序,歸并排序

首先我們介紹一個(gè)測(cè)試時(shí)間的利器,通常情況我們會(huì)使用time包來(lái)測(cè)試,但是只能測(cè)試總共的時(shí)間,而這個(gè)cProfile能測(cè)試具體步驟的時(shí)間,可以看得非常清楚瓶頸在哪里.

import cProfile   #測(cè)試間的利器
def add(a,b):
    return a+b
def for_func():
    result = 0
    for i in range(1000000):
        result += i 
    return result
def main(a,b):
    print 'this is the result for a + b'
    result = add(a,b)
    print result
    print 'test for function'
    print for_func()
cProfile.run('main(1,2)')
this is the result for a + b
3
test for function
499999500000
         115 function calls in 0.144 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <ipython-input-56-3130e18dd725>:1(add)
        1    0.114    0.114    0.143    0.143 <ipython-input-57-827e3096c393>:1(for_func)
        1    0.000    0.000    0.144    0.144 <ipython-input-58-19c5a6c13393>:1(main)
        1    0.000    0.000    0.144    0.144 <string>:1(<module>)
        9    0.001    0.000    0.001    0.000 iostream.py:180(schedule)
        8    0.000    0.000    0.000    0.000 iostream.py:284(_is_master_process)
        8    0.000    0.000    0.000    0.000 iostream.py:297(_schedule_flush)
        8    0.000    0.000    0.001    0.000 iostream.py:342(write)
        9    0.000    0.000    0.000    0.000 iostream.py:87(_event_pipe)
        9    0.000    0.000    0.000    0.000 threading.py:570(isSet)
        9    0.000    0.000    0.000    0.000 threading.py:986(isAlive)
        8    0.000    0.000    0.000    0.000 utf_8.py:15(decode)
        8    0.000    0.000    0.000    0.000 {_codecs.utf_8_decode}
        8    0.000    0.000    0.000    0.000 {isinstance}
        8    0.000    0.000    0.000    0.000 {method 'decode' of 'str' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        8    0.000    0.000    0.000    0.000 {nt.getpid}
        9    0.000    0.000    0.000    0.000 {nt.urandom}
        1    0.029    0.029    0.029    0.029 {range}
# 這個(gè)表示正無(wú)窮,同理-inf表示負(fù)無(wú)窮,下面我們會(huì)用到
float('inf')
inf

侏儒排序法

從第一個(gè)數(shù)字開(kāi)始和前面的進(jìn)行比較,如果小于前面的數(shù)字就交換位置然后將指針減少1然后繼續(xù)循環(huán)檢測(cè)下一個(gè). 最后的結(jié)果就是講最小的移到第一位,然后從第一位在開(kāi)始往后就像在紙上來(lái)回畫(huà)直線(xiàn)一樣每次將最小的數(shù)字放到最前面然后從最前面依次往后檢測(cè),知道在找到滿(mǎn)足條件的再次將數(shù)字移到前面.

seq = [5,4,3,2,1]
def gnomesort(seq):
    i = 0 
    while i <len(seq):
        if i == 0 or seq[i-1] <= seq[i]:
            i += 1
        else:
            seq[i-1], seq[i] = seq[i], seq[i-1]
            i -= 1
    return seq
gnomesort(seq)

[1, 2, 3, 4, 5]

插入排序

從第一個(gè)開(kāi)始,用這個(gè)數(shù)字和之前的每一個(gè)數(shù)字進(jìn)行比較直到比他前一個(gè)數(shù)字小為止,那么這個(gè)數(shù)字的位置就可以確定了-放到他的前面.當(dāng)然這個(gè)排序是從index = 0 開(kāi)始的.

seq = [5,4,3,2,1]
# 遞歸版插入排序
def ins_sort_rec(seq,i):
    '''
    遞歸是從最低層開(kāi)始排序的也就是從索引為0的地方開(kāi)始排序的
    seq 是一個(gè)列表,i是列表的長(zhǎng)度減1,也就是最后一個(gè)元素索引的位置.返回一個(gè)排序好的列表
    '''
    if i == 0:return seq
    ins_sort_rec(seq,i-1)   # 這個(gè)遞歸的使用可以理解為替換,將函數(shù)替換為這個(gè)函數(shù)的除去函數(shù)體的其他部分.
    j = i 
    while j > 0 and seq[j-1]> seq[j]:
        seq[j-1],seq[j] = seq[j],seq[j-1]
        j -= 1
    return seq
        
ins_sort_rec(seq,len(seq)-1)
[1, 2, 3, 4, 5]
# 插入排序 普通版
def ins_sort_nor(seq,i):
    '''seq 是一個(gè)列表,i是列表長(zhǎng)度-1,這里用這個(gè)數(shù)字和他前一個(gè)數(shù)字進(jìn)行比較如果小于就互換位置,互換后繼續(xù)檢查和前一個(gè)的大小比較,直到小于位置.
    '''
    for x in range(0,i):
        while x > 0 and seq[x-1] > seq[x]:
            seq[x-1],seq[x] = seq[x], seq[x-1]
            x -= 1
    return seq
    
ins_sort_nor(seq,len(seq)-1)
[1, 2, 3, 4, 5]

選擇排序

選擇排序:第一次將最大的放到最后,然后將剩下的所有中最大的放到最后,依次放到最后一個(gè).

這個(gè)排序是從數(shù)列的最后一位開(kāi)始的.

seq = [5,4,3,2,1]
# 遞歸版選擇排序
def sel_sort_res(seq,i):
    if i == 0: return seq
    max_j = i 
    for x in range(i):
        if seq[x] > seq[max_j]:
            seq[x],seq[max_j] = seq[max_j],seq[x]
    return sel_sort_res(seq,i-1)
sel_sort_res(seq,len(seq)-1)
[1, 2, 3, 4, 5]
def sel_sort_nor(seq):
    for i in range(len(seq)-1,0,-1):
        max_j = i 
        for j in range(i):
            if seq[j] >seq[max_j]:max_j = j
        seq[i],seq[max_j] = seq[max_j],seq[i]
    return seq
sel_sort_nor([2,4,1])
[1, 2, 4]

快速排序

快速排序的邏輯是: 每次選中一個(gè)參考值,然后把大于參考值的放到右邊小于參考值的放到左邊,這樣就可以確定參考值的位置,每次確定一個(gè)參考值的位置,循環(huán)往復(fù)就可以逐步確認(rèn)每個(gè)數(shù)字的位置了

def QuickSort(myList,start,end):
    #判斷l(xiāng)ow是否小于high,如果為false,直接返回
    if start < end:
        i,j = start,end
        #設(shè)置基準(zhǔn)數(shù)
        base = myList[i]  

        while i < j:  
            #如果列表后邊的數(shù),比基準(zhǔn)數(shù)大或相等,則前移一位直到有比基準(zhǔn)數(shù)小的數(shù)出現(xiàn)
            while (i < j) and (myList[j] >= base):  
                j = j - 1  

            #如找到,則把第j個(gè)元素賦值給第個(gè)元素i,此時(shí)表中i,j個(gè)元素相等
            myList[i] = myList[j]

            #同樣的方式比較前半?yún)^(qū)
            while (i < j) and (myList[i] <= base):
                i = i + 1
            myList[j] = myList[i]
        #做完第一輪比較之后,列表被分成了兩個(gè)半?yún)^(qū),并且i=j,需要將這個(gè)數(shù)設(shè)置回base
        myList[i] = base

        #遞歸前后半?yún)^(qū)
        QuickSort(myList, start, i - 1)
        QuickSort(myList, j + 1, end)
    return myList


myList = [49,38,65,97,76,13,27,49]
print("Quick Sort: ")
QuickSort(myList,0,len(myList)-1)
print(myList)
Quick Sort: 
[13, 27, 38, 49, 49, 65, 76, 97]
# 快速排序
def quick_sort(seq,start,end):
    if i < j: 
        i,j = start,end
        base = seq[i]
        while i <j:
            while i < j and seq[j] >= base:
                j -= 1
            seq[i] = seq[j]
            while i < j and seq[i] <= base:
                i += 1
            seq[j] = seq[i]
        seq[i] = base
    
    quick_sort(seq,start, i -1)
    quick_sort(seq,j+1,end)
    
    return seq
myList = [49,38,65,97,76,13,27,49]
print("Quick Sort: ")
quick_sort(myList,0,len(myList)-1)
print(myList)
Quick Sort: 
[13, 27, 38, 49, 49, 65, 76, 97]

冒泡排序

def bubble_sort(seq,order=1):
    end = len(seq)-1
    for x in range(end,0,-1):
        for y in range(x):
            if order == 1:
                if seq[y] > seq[y+1]:
                    seq[y],seq[y+1] = seq[y+1],seq[y]
            
    return seq
alist = [4,3,2,1,5,7,4,5,4,3,2,4,5,6,7,78,87,6,54,3,3]
bubble_sort(alist)
[1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 54, 78, 87]

這個(gè)算法中,最好的時(shí)間復(fù)雜度是 n, 最差的時(shí)間復(fù)雜度是n**2 所以是時(shí)間復(fù)雜度應(yīng)該介于這兩者之間

歸并排序法

def mergesort(seq):
    mid = len(seq)//2
    lft, rgt = seq[:mid],seq[mid:]
    if len(lft) > 1 : lft = mergesort(lft)
    if len(rgt) > 1 : rgt = mergesort(rgt)
    res = []
    while lft and rgt:
        if lft[-1] >= rgt[-1]:
            res.append(lft.pop())
        else:
            res.append(rgt.pop())
    res.reverse()
    return (lft or rgt) + res    

如何從某一個(gè)數(shù)字列表中找出彼此最接近但是不相等的兩個(gè)數(shù):

思路: 找出兩個(gè)數(shù)字的絕對(duì)差最小,兩次遍歷整個(gè)列表,兩個(gè)數(shù)的差值比較如果比上一個(gè)小那么就取用這個(gè)差值和這兩個(gè)數(shù)字

alist = [1,2,5,3,5,3.122,12,23.43,79,4,8.1,8.12]
dd = float('inf')
for x in alist:
    for y in alist:
        if x == y : continue
        d = abs(x - y)
        if d < dd:
            xx, yy,dd = x, y,d
xx,yy  # 對(duì)于這個(gè)算法來(lái)說(shuō),時(shí)間復(fù)雜度是平方級(jí)的
(8.1, 8.12)

如果使用排序好的列表進(jìn)行排序速度將會(huì)提高

newlist = sorted(alist)  # 如果使用list.sort() 方法那么原本的list的排序就會(huì)改變慎用
i = 0
dd = float('inf')
while i < len(newlist)-1:
    if newlist[i] == newlist[i+1]: 
        i +=1
    else:
        d = abs(newlist[i] - newlist[i+1])
        if d < dd:
            x,y,dd = newlist[i],newlist[i+1],d
        i += 1
x,y
(1, 2)

幾種排序的思想以及方法

冒泡算法思想:

每次相鄰元素進(jìn)行比較靠瞎,如果發(fā)現(xiàn)較小的元素在后面府瞄,就交換兩個(gè)相鄰的元素,每次循環(huán)都將最大是數(shù)據(jù)排列到結(jié)尾處.

選擇排序算法思想:

在冒泡排序上做了優(yōu)化床估,減少了交換次數(shù)肾档,在首輪選擇最大的數(shù)放在第一項(xiàng)臊旭,一輪之后第一項(xiàng)是有序的了,第二輪從第二項(xiàng)開(kāi)始選擇最大的數(shù)放在第二項(xiàng)颖医,以此類(lèi)推庐完,直到整個(gè)數(shù)組完全有序

插入排序算法思想:

和前倆種排序不同,插入排序在排序過(guò)程中是局部有序分井,隨著插入項(xiàng)的增多车猬,有序部分的項(xiàng)的位置會(huì)發(fā)生改變,而冒泡排序和選擇排序每輪確定的項(xiàng)數(shù)的位置是永遠(yuǎn)不變的尺锚。在首輪珠闰,選擇第二項(xiàng)作為插入項(xiàng),然后取出這一項(xiàng)放在一個(gè)變量中瘫辩,和前一項(xiàng)比較而且小伏嗜,則前一項(xiàng)后移到第二項(xiàng)的位置,然后第二項(xiàng)也就是插入項(xiàng)放在前一項(xiàng)的位置伐厌,第二輪選擇第三項(xiàng)作為插入項(xiàng)然后取出和前一項(xiàng)也就是第二項(xiàng)比較如果小承绸,第二項(xiàng)后移到插入項(xiàng),然后插入相在和第一項(xiàng)比較如果小挣轨,則第一項(xiàng)后移到第二項(xiàng)军熏,插入項(xiàng)放在第一項(xiàng),以此類(lèi)推卷扮。

總結(jié):

冒泡算法荡澎,每次比較如果發(fā)現(xiàn)較大的元素在后面,就交換兩個(gè)相鄰的元素晤锹。而選擇排序算法的改進(jìn)在于:先并不急于調(diào)換位置摩幔,先從Aarray[0]開(kāi)始逐個(gè)檢查,看哪個(gè)數(shù)最大就記下該數(shù)所在的位置j鞭铆,等一躺掃描完畢或衡,再把Arraymax和A[0]對(duì)調(diào),這時(shí)Array[0]到Array[6]中最大的數(shù)據(jù)就換到了最前面的位置。所以薇宠,選擇排序每掃描一遍數(shù)組,只需要一次真正的交換艰额,而冒泡可能需要很多次澄港,比較的次數(shù)是一樣的。插入排序算法比冒泡快一倍柄沮,比選擇排序略快一點(diǎn)

seq = [7,5,3,56,7,8,3,12,2]
# 冒泡排序
def bubble_sort(seq):
    # 索引的位置
    i = len(seq)-1
    for x in range(i,0,-1):
        for y in range(x):
            if seq[y]<seq[y+1] :
                seq[y+1] , seq[y] = seq[y] ,seq[y+1]
    return seq    
bubble_sort(seq)
[56, 12, 8, 7, 7, 5, 3, 3, 2]
seq
[7, 7, 7, 7, 7, 7, 7, 12, 12]
# 侏儒算法
def gon_sort(seq,end):
    i = 0
    while i < end:
        if  i == 0 or seq[i-1] <= seq[i]:
            i += 1
        else:
            seq[i-1],seq[i] = seq[i],seq[i-1]
            i -= 1
    return seq
seq = [7,5,3,56,7,8,3,12,2,5,3,21,6]
end = len(seq)
gon_sort(seq,end)
[2, 3, 3, 3, 5, 5, 6, 7, 7, 8, 12, 21, 56]
def quick_sort(seq,start,end):
    if start < end:
        i,j = start,end
        base = seq[i]
        while i < j:
            while i < j and seq[j] >= base:
                j -= 1
            seq[i] = seq[j]
            while i < j and seq[i] <= base:
                i += 1
            seq[j] = seq[i] 
        seq[i] = base
        
        quick_sort(seq,start,i-1)
        
        quick_sort(seq,j+1,end)
    return seq
seq = [7,5,3,56,7,8,3,12,2,5,3,21,6]
start = 0
end = len(seq)-1
quick_sort(seq,start,end)
[2, 3, 3, 3, 5, 5, 6, 7, 7, 8, 12, 21, 56]
def select_sort(seq,end):
    for x in range(end,0,-1):
        max_j = end 
        for y in range(x):
            if seq[y]>seq[max_j]: max_j = y
        
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末回梧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子祖搓,更是在濱河造成了極大的恐慌狱意,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拯欧,死亡現(xiàn)場(chǎng)離奇詭異详囤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)镐作,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)藏姐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人该贾,你說(shuō)我怎么就攤上這事羔杨。” “怎么了杨蛋?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵兜材,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我逞力,道長(zhǎng)曙寡,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任寇荧,我火速辦了婚禮卵皂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘砚亭。我一直安慰自己灯变,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布捅膘。 她就那樣靜靜地躺著添祸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寻仗。 梳的紋絲不亂的頭發(fā)上刃泌,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼耙替。 笑死亚侠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的俗扇。 我是一名探鬼主播硝烂,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼铜幽!你這毒婦竟也來(lái)了滞谢?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤除抛,失蹤者是張志新(化名)和其女友劉穎狮杨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體到忽,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡橄教,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喘漏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颤陶。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖陷遮,靈堂內(nèi)的尸體忽然破棺而出滓走,到底是詐尸還是另有隱情,我是刑警寧澤帽馋,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布搅方,位于F島的核電站,受9級(jí)特大地震影響绽族,放射性物質(zhì)發(fā)生泄漏姨涡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一吧慢、第九天 我趴在偏房一處隱蔽的房頂上張望涛漂。 院中可真熱鬧,春花似錦检诗、人聲如沸匈仗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悠轩。三九已至,卻和暖如春攻泼,著一層夾襖步出監(jiān)牢的瞬間火架,已是汗流浹背鉴象。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留何鸡,地道東北人纺弊。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像骡男,于是被迫代替她去往敵國(guó)和親淆游。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容