Coco學程式設計(二)--直接選擇排序 (轉)

worldblog發表於2007-12-14
Coco學程式設計(二)--直接選擇排序 (轉)[@more@]

Coco:這麼長時間不來,我還真想大家,實在是某人太懶了,總也不來上課。

我:這個……還真是對不起啊。主要是因為最近找了份新工作,正在趕一個專案,比較忙一些。經常會有天黑才回來的事情,所以有很長一段時間沒有出現。

Coco:據我所知~某人天黑才會回家,是因為在廣州總迷路,每次坐在車上的時間還沒有找路的時間長,而且,還因為一些很菜的問題被卡住了……

我:為什麼總要揭我的短呀……-_-#

Coco:hoho,上課上課~

我:好吧,上次講了直接插入排序,我們從改進它開始。這幾天,你對這個演算法有什麼想法沒有?

Coco:在書上讀到,在容器中反覆的插入和刪除節點是一種很低效的做法,不但速度慢,還會造成的碎片化,是這樣子的吧。

我:很正確,所以通常來說,我們應該想辦法減少插入和刪除的次數。這樣可以有效避免記憶體的碎片化。

Coco:不過對於選擇插入法來說,我們只移動出現逆序的節點了,還有什麼辦法能更進一步減少這插入和刪除的操作嗎?

我:有一個辦法,就是不用del和Insert進行顯示的刪除和插入操作,充分利用容器現有的空間,以節點來移動它。

Coco:不太理解。

我:由些產生的最簡單的方法,用簡單的數學描述來講,是這樣子的,假設集合有{a1, a2, a3,…, an},我們先從整個區間中找出最小的一個元素am,如果它不等於a1,就把它和a1交換;然後查詢[a2, a3,…, an]區間,在其中找出最小的元素,如果它不等於a2,就把它和a2交換;重複這一過程,就可以對整個陣列排序了。

Coco:看起來很簡單呀,我去試試,測試程式碼段就還用上次的嘍~

#以下是Coco的程式碼:

#Direct choice sort. It is a sample method.

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

def DrtChcSort(theArray):

  #Move the begin of search area.

  for i in range(len(Array)):

  curMrk = i

  #Find the min node.

  for j in range(i, len(theArray)):

  if theArray[j] < theArray[curMrk]:

  curMrk = j

  #Move it to front.

  if not(curMrk == i):

  theArray[curMrk], theArray[i] = theArray[i], theArray[curMrk]

 

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

print Array

DrtChcSort(Array)

print Array

Coco:這辦法比上次那個簡單多了嘛,為什麼當初不教我這個?

我:要你寫這些演算法又不是真要你實用,主要是練習一下。要不然,對的陣列排序最簡單的辦法應該是:Array.sort()

Coco:倒~好吧,算你說的有道理,不過這樣直接交換連結串列中的元素:“theArray[curMrk], theArray[i] = theArray[i], theArray[curMrk]”真的可以保證記憶體不會碎片化,還能減少插入和刪除嗎?

我:老實說,我不知道,因為python對這個線性容器的操作被封裝了起來,從我們這個使用層上,是看不到的。不過,我們至少避免了顯示的增刪操作。如果說這樣是“可能會有壞結果”,那顯示的增刪操作則是“幾乎一定會有壞結果”,如果在C語言這類直接操作記憶體的語言中,兩者的效果就是很明確的了。

Coco:為什麼說“幾乎”?

我:因為python有它的記憶體管理機制,它可以進行垃圾回收,所以記憶體的碎片化和丟失,還是會受到控制,特別是jython,由於使用平臺,基本上不存在記憶體方面的困擾。不過,過於依賴它也不是好主意,至少會給虛擬機器帶來不必要的負擔。

Coco:聽起來有道理的樣子,我還有一個疑問,在這個排序中,我們把當前已排序間後面的那個元素直接與未排序區間中的最小元素交換了,這會不會造成後面的未排序區間越來越亂,給我們帶來額外的麻煩呢?

我:這種交換的確有增加混亂――形像的說,就像熱學中的“熵”――的可能,不過如果這個演算法只考慮某一個連結串列,也就基本上沒有什麼用途了。而從統計角度講,未排序區間的“熵”

不會因此而增加。

Coco:明白了,不過這個演算法太簡單了,再多講點東西吧。

我:上次有個朋友問遞迴的含義,你知道嗎?

Coco:遞推多項式,一種,每一項由前一項使用的公式來決定。

我:怎麼看著這麼眼熟啊,從哪裡貼來的?

Coco:這麼快就讓你看出來了啊,《金山詞霸》嘍~

我:倒……真會偷懶,簡單的說,遞迴的就是指一個方法中會使用它自身。

Coco:聽起來怪怪的,給個程式讓我們看看吧。

我:歐幾里德演算法,輾轉相除求最大公因子,如何?你來寫這個程式吧,也不是多難

Coco:真會偷懶~

def Gba(a, b):

  r = a%b

  if r == 0:

  return b

  else:

  return (b, r)

Coco:這個就可以得到a和b的最大公因子了。這種透過呼叫自身來進入下一步的函式就是一種遞迴函式吧。

我:是的,與之相對應的運算方法是迭代,也就是說透過某種方法重新記錄當前狀態,然後迴圈生成這一狀態的演算法,這樣不用重複呼叫函式,在上比遞迴要好,不過可讀性通常會差一些。比如以上這個Gba(a, b)的遞迴形式應該是這樣子:

def Gba(a, b):

  r = a%b

  while r!=0:

  a, b = b, r

  r = a%b

  return b

Coco:好像明白點兒了。接下來呢?

我:上次去cn99新聞組上問你說的那個很菜的問題時,有位叫Chadzer的朋友寫了一個不錯的回應,雖然我的問題很菜(Coco:這個笨蛋會不知道在python裡怎麼交換元素,也敢出來教別人,我真是遇人不淑呀~),但這位朋友寫的回信比我的問題更有價值,如果明天有空,我把它譯出來給大家分享一下。不過今天先這樣吧,這兩天感冒,不太舒服,明天還要上班。

Coco:感冒了不早說,別傳染給我,閃~


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

相關文章