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

來源:互聯網
上載者:User

前文連結:http://www.cnblogs.com/pmer/archive/2012/11/21/2781703.html

【重構】

  首先,什麼是鏈表?無論《C程式設計》還是《C程式設計伴侶》都沒有給出清晰準確的定義。
  不知道什麼叫鏈表,當然不可能正確地寫出關於鏈表的代碼,《C程式設計伴侶》中出現為鏈表安裝了一條不倫不類的“義尾”(tail)的怪現象也就不足為怪了。
  在這裡我給出我對鏈表的定義:鏈表就是一個指標,這個指標,要麼值為NULL,要麼指向其中含有另一個鏈表的資料。
  當然,鏈表有很多種,這裡的定義只是最簡單的一種——單向鏈表。
  這個定義明顯模仿了n!的定義方法,是一種遞迴式的定義。這種遞迴式定義的東西用遞迴的方法很容易實現。
  其次,鏈表結點的描述。

typedef    struct   {      char name[20];      float score;   }data_t;typedef    struct node   {      data_t item ;      struct node *next ;   }node_t;

 

  這樣就建立了一個抽象的結點類型。這樣處理的好處是成功地把資料從結點中在形式上剝離開了,這對代碼的結構及可維護性都非常很重要。因為我們知道,在一個糟糕的資料結構上是絕對無法建立良好的代碼結構的,而代碼的結構糟糕則一定會導致可維護性的下降。
  選擇了鏈表就是選擇了鏈表的優點而不是選擇了鏈表的劣勢,這就和你買輛汽車是用來開的而不是用來推的道理一樣。和同樣屬於線性結構的數組相比,鏈表的優勢是很容易在前面加入結點結點,但在尾部加入結點則要麻煩得多。數組則相反,即使在有足夠的預留空間的情況下,不經過一番折騰也很難在數組的開始加入一個資料,但是很容易在數組的尾部加入一個資料(只要事先預留了位置)。
  既然鏈表很容易在頭部加入結點,通常情況下建立鏈表也應該選擇這種方式——不斷地向其中添加資料就行了。代碼如下:

1. #include <stdlib.h>2. #include <stdio.h>3. 4. //----------通用函數---------------------//5. void *my_malloc( size_t );6. //--------------------------------------//7. 8. 9. //----------“資料”類型----------------//10. typedef 11.    struct12.    {13.       char name[20];14.       float score;15.    }16. data_t;17. //-----------關於“資料”的函數-----------//18. int  input  ( data_t * ) ; 19. void output ( data_t * ) ; 20. //---------------------------------------//21. 22. 23. //---------“結點”類型------------------//24. typedef 25.    struct node26.    {27.       data_t item ;28.       struct node *next ;29.    }30. node_t;31. //--------“鏈表”操作函數---------------//32. void create( node_t ** );33. void insert( node_t ** ,  node_t * );34. void print ( node_t * );35. //--------------------------------------//36. 37. 38. int main( void )39. {40.    node_t *head = NULL ; //空鏈表41.    42.    puts("建立鏈表");43.    create( &head ); 44.    //測試 45.    puts("輸出鏈表");46.    print( head );47. 48.    return 0;49. }50. 51. //-------通用函數定義-------------------//52. void *my_malloc( size_t size )53. {54.    void *p = malloc( size );55.    if( p == NULL )56.    {57.       puts("記憶體不足");58.       exit(1); 59.    }   60.    return p;61. }62. //--------------------------------------//63. 64. //---------“資料”操作函數定義---------//65. int input ( data_t *p_data )66. {67.    puts("請輸入姓名、成績:");68.    if( scanf( "%20s%f" , p_data->name , &p_data->score ) != 2 ) //20很重要 69.    {70.       while( (getchar()) != '\n' ) //清空輸入緩衝 71.          ;72.       return 0 ;   73.    }74.    return !0 ;75. }76. 77. void output ( data_t *p_data )78. {79.    printf ("姓名:%s 成績:%.2f\n" , p_data->name , p_data->score  ) ;80. }81. //--------------------------------------//82. 83. 84. //----------“鏈表”操作函數定義--------//85. 86. void print( node_t *p_node )87. {88.    if( p_node != NULL )89.    {90.       output ( &p_node->item ); 91.       print( p_node->next );92.    }93. }94. 95. void insert( node_t ** p_next ,  node_t * p_node)96. {97.    p_node -> next = * p_next ;98.    * p_next = p_node ;99. }100. 101. void create( node_t **p_next )102. {103.    data_t data;104. 105.    if( input ( & data ) != 0 )106.    {107.       node_t *p_node = my_malloc( sizeof (*p_node) );108.       p_node->item = data ;109.       insert( p_next , p_node );//插入結點110.       create( p_next );//繼續 111.    }112. }113. //--------------------------------------//

 

  這種寫法,由於把“資料”視為結點的一個抽象成員,成功地把“資料”部分的操作與關於鏈表的操作像油和水一樣地分離開來。在開發過程中可以把它們作為兩個相對獨立的模組開發(即所謂“高內聚低耦合”)。而且即使以後對“資料”部分有所修改,只要介面沒有發生改變,鏈表部分完全不受任何影響。

  或許有人仍然希望新加入的結點都接到鏈表的尾部,由於這裡的create()函數是一次性從零開始建立鏈表,所以實現這點也並不困難甚至可以說是非常簡單,只需要把create()函數定義中的  

create( p_next );//繼續

改成

create( &(*p_next)->next );   //create( p_next );//繼續

 

就可以了。
  也就是說,對於一次性建立的鏈表,壓根不需要有tail這種東東。

  但在實際開發中,並不是總能碰到問題要求一次性建立鏈表這種“好事”,如果問題要求動態地(非一次性地)從鏈表尾部加入結點、並且要求從前面刪除結點呢?這時才需要在head的基礎上再加一個記錄尾部結點的tail。但即使這樣也不要“首尾兩端”,而應該“首尾共濟”,大大方方地

typedef  struct  {    node_t *head;    node_t *tail; } queue_t  ;

 

好了。
只不過這種東東並不叫鏈表(Linked list),而叫Queue(隊列)。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.