簡單的Linked List實現

 

Abstraction

Introduction
學習資料結構,第一個要學的就是linked list,本文示範最簡單的linked list實現,包含建立與顯示,可把它當成linked list的標準範本,畢竟步驟都差不多。

一個基本的問題:為什麼需要linked list?若要將大量資料存到記憶體,你會想到什麼?第一個想到的就是array,但C語言是個靜態語言,array必須事先宣告大小,這樣compiler才能進行最佳化,若到時候沒用這麼多記憶體,就白白浪費記憶體了。或許你會說array可以配合malloc()變成動態array,但前提是你必須告訴malloc()要建立多大的array,若連要建立多大的陣列也不確定,而是在run-time看有多少資料就建立多大,這時連malloc()的動態array也不能用了,此時就得靠linked list。

linked list是資料結構的基礎,基本上就是靠struct如火車車廂那樣連在一起,run-time有需要時,在動態掛一個struct上去。

C語言

1  /*  
2  (C) OOMusou 2008 http://oomusou.cnblogs.com
3 
4  Filename    : DS_linked_list_simple.c
5  Compiler    : Visual C++ 8.0
6  Description : Demo how to use malloc for linked list
7  Release     : 03/22/2008 1.0
8    */
9  #include < stdio.h >
10  #include < stdlib.h >
11  #include < string .h >
12 
13  #define SLEN 255
14 
15  struct list {
16    int   no;
17    char name[SLEN];
18    struct list * next;
19  };
20 
21  int main() {
22    int no;
23    char s[ 255 ];
24   
25    struct list * head    = NULL;
26    struct list * current = NULL;
27    struct list * prev    = NULL;
28   
29    while ( 1 ) {
30      printf( " No. = " );
31      scanf( " %d " , & no);
32     
33      if (no ==   0 )
34        break ;
35   
36      printf( " Name = " );
37      scanf( " %s " , s);
38     
39      current = ( struct list * )malloc( sizeof ( struct list));
40      if (current == NULL)
41        exit(EXIT_FAILURE);
42       
43      current -> next = NULL;
44     
45      current -> no = no;
46      strncpy(current -> name, s, SLEN - 1 );
47      current -> name[SLEN - 1 ] =   ' \0 ' ;
48     
49      if (head == NULL)
50        head = current;
51      else
52        prev -> next = current;
53       
54      prev = current;
55    }
56   
57    // display linked list
58    current = head;
59    while (current != NULL) {
60      printf( " No. = %d, Name = %s\n " , current -> no, current -> name);
61      current = current -> next;
62    }
63   
64    // free linked list
65    current = head;
66    while (current != NULL) {
67      prev = current;
68      current = current -> next;
69      free(prev);
70    }
71  }


執行結果

No. =   1
Name
= clare
No.
=   2
Name
= jessie
No.
=   0
No.
=   1 , Name = clare
No.
=   2 , Name = jessie


15行

struct list {
 
int   no;
 
char name[SLEN];
 
struct list * next;
};


linked list的基礎就是struct,所以先建立一個自訂的struct型別,因為linked list是靠struct串聯起來,所以最後要多一個struct pointer指向下一個struct。

25行

struct list * head    = NULL;
struct list * current = NULL;
struct list * prev    = NULL;


建立linked list最基本需要三個指標,head指向linked list的第一個struct,current指向目前剛建立的struct,prev則指向前一個struct,目的在指向下一個struct,對於未使用的pointer,一律指定為NULL,這是一個好的coding style,可以藉由判斷是否為NULL判斷此pointer是否被使用。

39行

current = ( struct list * )malloc( sizeof ( struct list));
if (current == NULL)
  exit(EXIT_FAILURE);
     
current
-> next = NULL;


每當有新資料,需要建立一個新的struct時,就用malloc()要一塊記憶體,由於malloc()傳回的是void *,所以要手動轉型成struct list *。但malloc()並不是一定會成功,若記憶體不足時,仍然會失敗,所以必須判斷是否傳回NULL。

由於一個新的node,一定是linked list最後一個node,所以將current->next接null。

45行

current -> no = no;
strncpy(current
-> name, s, SLEN - 1 );
current
-> name[SLEN - 1 ] =   ' \0 ' ;


正式將輸入的資料填進struct,至於為什麼要用strncpy()而不用strcpy()呢?雖然strcpy()也可以,但strncpy()比較安全,若輸入的字串大小超過struct所定義的字串大小,則會只接受struct所接受的字串大小,而不會因為找不到'\0'而造成程式錯誤。

49行

if (head == NULL)
  head
= current;
else
  prev
-> next = current;
     
prev
= current;


判斷若是第一個node,則將目前的node當成head,若不是第一個node,則將前一個node指向目前的node,完成linked list的連接。最後將目前的node當成前一個node,以備指向下一個node。

58行

// display linked list
current = head;
while (current != NULL) {
  printf(
" No. = %d, Name = %s\n " , current -> no, current -> name);
  current
= current -> next;
}


要重新顯示linked list,所以將指標再度指向第一個node,每當顯示一個node後,就指向下一個node,直到指到NULL為止。

64行

// free linked list
current = head;
while (current != NULL) {
  prev
= current;
  current
= current -> next;
  free(prev);
}


由於malloc()是將記憶體放在heap,而不是放在stack,所以並不會隨著function的結束而釋放,必須要手動使用free()釋放記憶體,否則會造成memory leak。

再來看C++,由於STL已內建一些容器,所以不需再重新實作linked list,有兩個選擇:std::vector或者std::list。std::vector的優點是non-sequential access超快,新增資料於後端超快,但insert和erase任意資料則超慢;std::list則剛好相反,insert和erase速度超快,但non-sequential access超慢,由於本例只有新增與non-sequential access,所以適合std::vector。不過由於STL使用泛型技術,若將來需求改變,想改用std::list也沒關係,只要將容器改掉即可,剩下的都不用改,因為STL的演算法並不挑容器,這正是泛型偉大之處。

C++

1  /*  
2  (C) OOMusou 2008 http://oomusou.cnblogs.com
3 
4  Filename    : DS_linked_list_simple_vector_class.cpp
5  Compiler    : Visual C++ 8.0
6  Description : Demo how to use vector instead of linked list
7  Release     : 03/22/2008 1.0
8  */
9  #include < iostream >
10  #include < string >
11  #include < vector >
12 
13  using   namespace std;
14 
15  class List {
16  public :
17    int no;
18    string name;
19  };
20 
21  int main() {
22    vector < List > vec;
23   
24    while ( 1 ) {
25      List list;
26      cout <<   " No. = " ;
27      cin >> list.no;
28     
29      if (list.no ==   0 )
30        break ;
31   
32      cout <<   " Name = " ;
33      cin >> list.name;
34     
35      vec.push_back(list);
36    }
37   
38    vector < List > ::iterator iter = vec.begin();
39    for (; iter != vec.end(); ++ iter)
40      cout <<   " No. = "   << iter -> no <<   " , Name = "   << iter -> name << endl;
41  }

 

執行結果

No. =   1
Name
= clare
No.
=   2
Name
= jessie
No.
=   0
No.
=   1 , Name = clare
No.
=   2 , Name = jessie


15行由struct改用了class,不過若繼續使用struct亦可,至於其他的程式都很直觀,就不再多做解釋。

Conclusion
本文主要是討論使用C語言透過malloc()實現資料結構的linked list,以彌補靜態語言的不足,同時亦討論C++使用STL的替代方案與便利性,C與C++各擅勝場,你可自行決定使用C或C++。


使用C語言簡單的實現linked list,並用C++的std::vector實作出相同的功能作比較。

你可能感兴趣的:(list)