Coco學程式設計(三)--冒泡就是折騰 (轉)

amyz發表於2007-08-15
Coco學程式設計(三)--冒泡就是折騰 (轉)[@more@]

Coco:好久不見,真想大家。由於某人的懶惰,嚴重影響到到我的人氣啊。

我:還好意思說,前段時間我本來是感冒,卻讓你宣揚成了“某種未知的呼吸傳染病”,害得我差點被隔離。

Coco:不把你隔離起來,怎麼能讓你老老實實的寫文章?

我:隔離我也認了,你居然會造謠說我的病會在qq染,難道你要我被隔離到一個不能上網的地方嗎?什麼時候聽說過人類的傳染病會能過網際網路傳染了?

Coco:所以說我說你中的是呀~

我:@#$%^

什麼時候人能中CIH了~

Coco:不可能嗎?

我:可能嗎?

Coco:不可能嗎?

我:可能嗎?

Coco:不可能嗎?

我:可能嗎?

Coco:我只是探討一下,不要那麼激動嘛,不可能嗎?

我:要是我哪天我能中了CIH,乾脆找人把我格式化了重灌算了。

Coco:別忘了裝套,都說這東東好,我還沒用過呢。

我:喂喂喂,我們再這麼胡扯下去,篇幅就都被浪費啦。

Coco:好吧好吧,戴上口罩,繼續工作。這次我們玩兒什麼?

(玩……還真是一語中的啊,本來要把你包裝成一個積極向上的好青年的,這下大家都知道你學是為了好玩兒了……)

我:我們這次玩兒……不對,是要學習一個很親切的排序演算法,氣泡排序。

Coco:這個~是不是太簡單了?好像很多人寫過Hello World之後第二個就是這個東東了。

我:這倒是不假,氣泡排序的特點就是實現非常簡單,基本上所有有流程控制能力的語言都可以實現它,而且也非常容易學習,可以說這是演算法課的“Hello World”。在Python中的實現也不會比其它語言更復雜。現在你寫一個冒泡來對我們一直用的示例陣列排序吧。

Coco:沒有你的日子裡,我寂寞無聊中,自己寫了一些程式,其中就包括這個冒泡~

我:喂~,不要說得那麼肉麻好不好?讓人以為我們有什麼不可告人的關係……先把程式拿來給我看看。

:namespace prefix = o ns = "urn:schemas--com::office" />

def BubSort(theInput):

  #c = 0

  #e = 0

  for i in range(len(theInput)):

  for j in range(1, len(theInput) - i):

  if theInput[j-1] > theInput[j]:

  theInput[j-1], theInput[j] = theInput[j], theInput[j-1]

  #e = e + 1

  #c = c + 1

  #print c

  #print e

return

#Follow is the demo of Bubble up sort.

Array=[6, 16, 10, 9, 15, 5, 11, 1, 19, 4, 14, 17, 18, 0, 13, 3, 12, 2, 8, 7]

print Array

BubSort(Array)

print Array

Coco:那些註釋中的程式碼好像與我無關啊?

我:這是我給你加上的。你的程式碼本身沒什麼問題,執行良好。我加上這些程式碼是為了計算一下排序中進行了多少次操作。只要把關於c的程式碼行註釋符去掉,就可以計算發生了多少次,把關於e的程式碼行註釋符去掉,就可以計算生髮生了多少次比較。

Coco:好像很方便的樣子,我試試嘍。才20個元素的列表,應居要190次比較和108次交換啊。

我:事實上,在這個程式中,比較次數只和元素的個數有關,N個元素的比較次數就是N*(N+1)/2。即使是一個完全排好序,不需要再進行交換的陣列。

Coco:我用[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]試試……還真是這樣子呢。這豈不是做了很多無用功?

我:是呀,針對這個問題,你有沒有什麼好辦法呢?

Coco:我想,可以記住每次遍歷中最後一次發生交換的位置,下次搜尋到這個位置為止就好了,我在程式里加一個標誌試試。

def MrkBubSort(theInput):

#  c = 0

#  e = 0

  i = 0

  bottom = len(theInput)

 

  while i < bottom:

  i = 0

  M = True

 

  for j in range(1, bottom):

  if theInput[j-1] > theInput[j]:

  theInput[j-1], theInput[j] = theInput[j], theInput[j-1]

  M = False

   bottom = j

#  e = e + 1

#  c = c + 1

  if M:

  break

 

  i = i + 1

#  print c

#  print e

return 

#Follow is the demo of Bubble up sort.

Array=[6, 16, 10, 9, 15, 5, 11, 1, 19, 4, 14, 17, 18, 0, 13, 3, 12, 2, 8, 7]

print Array

MrkBubSort(Array)

print Array

Coco:把註釋掉的計數程式碼拿出來執行後可以知道,對同樣的這個陣列,發生了178次比較,確是少了一些啊。

我:如果你試一試一些“極端”的資料,會觀察到一些有趣的現像。比如  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0],[19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],[19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]等等。

Coco:以下是輸出結果,每一組輸出結果中,第一組是原陣列,下一行的單個整數是比較次數,下一個是交換次數,最後一行的陣列是排序後的。

>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

19

0

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

>>>

>>> [19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

190

190

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

>>> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0]

190

19

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

>>>

>>> [19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

37

19

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

Coco:的確是有一些問題,比如,如果陣列的未尾存在逆序,即使前面的資料已經排好,也一樣需要190次交換。有沒有什麼辦法解決它呢?

我:提示一下,如果逆序在開頭呢?

Coco:嗯,只需要37次比較。看來比較次數和操作的方向有關。

我:所以,如果從兩端交替進行排序,就可以儘可能的避免無謂的比較操作。這種演算法我們稱為搖動。你試試實現它吧。

(很長時間後……)

def ShkBubSort(theInput):

  c = 0

  e = 0

  l = len(theInput)

 

  tmpt = 1

  top = 0

  tmpb = l

  bottom = tmpb

 

  while top < bottom:

 

  if top < tmpt:

  top = tmpt

  else :

  top = top + 1

  bottom = tmpb

  M = True

 

  for j in range(top, bottom):

  if theInput[j-1] > theInput[j]:

  theInput[j-1], theInput[j] = theInput[j], theInput[j-1]

  M = False

  tmpb = j

  e = e + 1

  c = c + 1

  if M:

  break

   

  for k in range(top + 1, bottom):

  cur = l - k

  if theInput[cur - 1] > theInput[cur]:

  theInput[cur-1], theInput[cur] = theInput[cur], theInput[cur-1]

  M = False

  tmpt = cur

   e = e + 1

  c = c + 1

  if M:

  break

#  print top, bottom

  print c

  print e

return

Coco:比我想像的麻煩的多啊。實際效果如何呢?我試試。

>>> [19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

54

19

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

>>> [6, 16, 10, 9, 15, 5, 11, 1, 19, 4, 14, 17, 18, 0, 13, 3, 12, 2, 8, 7]

169

108

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

>>>

>>> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0]

54

19

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

>>> [19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

190

190

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

Coco:總的來說,好像有些改進,不過並不是很明顯噢。

我:實際上,最關鍵的是,不論如何改進,都不會改變這一系列演算法交換操作過多的缺點。而在排序操作中,寫操作的代價要遠高於讀操作,所以無論怎樣減少比較次數,都不能真正有效的提高排序的。

Coco:唉,費這麼大勁,學了一個不甚實用的演算法,真是瞎折騰……

我:當然,學習這個演算法……

Coco:OK,OK,我知道你要說,主要是為了讓我練習,不過現在每個月只露一次面,無論多複雜的程式,也不能真正有效的提高我的熟練程度啊。你是不是也應該勤勞一些呀~

我:事實上,這個月我可沒有讓大家空等。我一直在寫《 Story》的第十一集,現在基本上已經解決了所有的問題,很快就會完成。

Coco:唉~,那裡又沒有機會讓我出場,失望啊,不知道哪天才能和大家再見面了,我會想你們的……


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-957938/,如需轉載,請註明出處,否則將追究法律責任。

相關文章