垃圾代碼評析——關於《C程序設計伴侶》9.4——鏈表(四)


【樣本】

    ——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p241~242

【評析】

  這段代碼的基本能算及格。在鏈表中查找,無非是從頭到尾一個一個的比較。

  代碼中的node是一個多余的變量。寫鏈表操作代碼時很多人都有這種惡習。實際上對於鏈表的操作者來說,由於鏈表是一種遞歸結構,所以只要是單調的從前到后的操作,任何一個結點的next成員都可以視為一個head。除非在操作過程中需要“回頭”,沒有任何必要保留初始的head值。

  此外,代碼中的break語句不如改成return node;。最后一句的return node;不如寫成return NULL;。這樣代碼的意義更加明確。 

student* find(student* node,char* key)
{
   
   while( node != NULL )
   {
      if(strcmp( node->name , key )==0)
      {
         return node ;
      }
      node = node->nex t;
   }
   return NULL ;
}

 

 【樣本】

     ——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p242

【評析】

  這段議論實在能把人雷得外焦里嫩。順序查找效率確實不算高,但對於鏈表來說實在是無奈之舉,因為這是鏈表本身的結構特性所決定的,除此之外別無他法也是無可奈何的事情。二分查找效率確實不錯,但是那是有前提條件的,第一數據要有序,第二通常只能用於數組,因為數組的中間元素可以直接訪問。但是對於鏈表來說,由於只能順序訪問各個結點而且根本無法回頭,所以尋找鏈表的終點幾乎是一件和順序查找同樣費勁的事情,這還沒算上為鏈表排序的巨大成本。所以用二分法對鏈表查找就好像是說,剃須刀刮胡子有些慢,買把鋒利的王麻子菜刀刮胡子會更有效。
下面就欣賞一下如何用菜刀刮胡子。

【樣本】

 

    ——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p244

【評析】

  首先這里的head=sort(head.cmpname);的成本比順序查找還要高,因為冒泡排序需要比較的次數是N平方量級的,而順序查找需要比較的次數是N的一次方量級的。
  其次這里的tail=gettail(head);找到鏈表的結尾同樣需要比較N次。鏈表的尾巴一向是深藏不露的,為揪出鏈表的尾巴而專門寫了一個函數,歷史上這還是首次。

  再看一下midfind()函數:

【樣本】

    ——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p243
【評析】

  這里明顯有個漏洞,就是當head、tail都為NULL時,亦即鏈表為空時,代碼是錯誤的,程序很可能因此而崩潰。

  二分法的關鍵在於確定中間結點,這里的student* mid =getmid(head,tail);又是如何得到的呢?再來看一下getmid()函數:

【樣本】

   ——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p242~243

 【評析】

  天哪!先從頭走到尾,數出鏈表一共有多少個結點,然后再從頭走到中間,一共需要移動3/2N次。問題在於這樣的過程不是一回而是多次。
  通俗地講一下。假如有一隊人,你要從中找一個人,你本可以從前走到隊尾挨個問一下。但是這里的樣本代碼卻嫌這種方法太慢。他“采用了一種更加有效的查找算法”:首先,用兩兩交換的辦法讓隊伍排好隊(注意這本身就比從前走到尾費事、費時);然后從開頭走到隊尾數一共有多少人;然后再按照人數從開頭走到隊伍中間,了解一下要找的人在前面還是在后面;如果在前面就再從前走到中間數人數然后再從前面走到隊伍前部的中間……
  試問,天下還有比這更愚蠢的“更加有效的查找算法”嗎?

【重構】

  這次還是免了吧。用二分法對鏈表查找,俺實在丟不起那人。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM