1. 程式人生 > >c語言之單鏈表

c語言之單鏈表

       連結串列是一種資料結構,它不僅非常有用,而且許多操作連結串列的技巧也適用於其他資料結構。

        連結串列就是一些包含資料的獨立資料結構(通常稱為節點)的集合。連結串列中的每一個節點都是通過鏈或者指標連線在一起,程式通過指標訪問連結串列中的節點,通常節點是動態分配的,但有時你也能看到節點陣列構建的連結串列,即使在這種情況下,程式也是通過指標來遍歷連結串列的。

先建立一個結構:

typedef struct NODE {
             strcut NODE *link;
             int                   value;
}Node;

下面來構建一個插入節點函式:

sll_insert(register Node **linkp,int new_value){
      register Node *current;
      register Node *new;
      while((current=*linkp)!=NULL && current->value<new_value)
                 linkp=&current->link;
      new=(Node *)malloc(sizeof(Node));
      if(new==NULL)
          return 0;
      new->value=new_value;
      new->link=current;
      *linkp=new;
      return 1;
 }


下面我們來幾個關於單鏈表的程式設計練習:

1.編寫一個函式,用於計數一個單鏈表的節點的個數。它的唯一引數就是一個指向連結串列第一個節點的指標。編寫這個函式時,你必須知道哪些資訊?這個函式還能用於執行其他任務嗎?

解析:這個函式很簡單,雖然它只能用於它宣告的那種型別的節點---你必須知道節點內部的結構。

int sll_count_nodes( Node *first){
         int count=0;
         for(;first!=NULL;first=first->link)
                 count++;
        return count;
 }

如果這個函式被呼叫時傳遞給它的是一個指向連結串列中間是位置某個節點的的指標,那麼它將對連結串列中這個節點以後的節點進行計數。 

2.編寫一個函式,在一個無序的單鏈表中尋找一個特定的值,並返回一個指向該節點的指標。如果想讓這個函式適用於有序的單鏈表,需不需要進行修改?

Node * sll_find_nodes(Node *first ,int value){
         while(first!=NULL){
               if(first->value==value)
                     return first;          
         first=first->link;         
         }
         return NULL;
         
 }

如果想讓它適用於有序單鏈表,不需要修改!

3.編寫一個函式,反序排列一個單鏈表的所有節點。函式的原型是Node *sll_reverse(Node *first),函式的引數指向連結串列的第一個節點,當連結串列被重新排列後,函式返回一個指向連結串列新頭節點的指標。連結串列的最後一個節點link欄位的值應該是NULL,在空連結串列上執行這個函式將返回NULL。

方案1:

Node *sll_reverse(Node *first ){
        if(first==NULL)
               return NULL;
        Node *preview;
        Node *next;
        preview=first;
        first=first->link;
        if(first==NULL)
               return preview;
        next=first->link;
        preview->link=NULL;
        first->link=preview;
        while(next!=NULL){
               preview=first;
               first=next;
               next=next->link;
               first->link=preview;

        }
       return first;
 }

方案2:

Node *sll_reverse(Node *first){
         if(first==NULL)
           return NULL;
          Node *node_array[100];
          int n;
          for(n=0;first!=NULL;first=first->link){
                   node_array[n]=first;
                   if(n==0)
                        node_array[n]->link=NULL;
                   else 
                     node_array[n]->link=node_array[n-1];
                   n++;
          }
          return node_array[n-1];
 }

假如傳遞的是頭指標*head。那麼函式該怎麼寫呢?

Node *sll_resverse(Node *head){
          if(head->link==NULL)
                     return NULL;
           Node *current,*temp;
          current=head->link;
          current->link=NULL;
         while(current!=NULL){
                 temp=current;
                 current=current->link;
                 temp->link=head->link;
                 head->link=temp; 
         }
         return current;
 }

4.編寫一個函式,從單鏈表中移除一個節點,函式原型為int sll_remove(Node **rootp,Node *node)。函式中的第一個引數是一個指向連結串列頭指標的指標,第二個引數是一個想要移除的節點的指標。

解析:可以分為三種情況:

1.要刪除的節點為第一個;

2.要刪除的節點在中間;

3.要刪除的節點位於最後一個;

這是我想的一個思路。

但你要仔細想想,事實上都是一樣的。

我的方案:

Node *sll_remove(Node **rootp,Node *node){
                Node *current;
               while((current=(*rootp)->link)!=NULL){
                              if(current==node){
                                    (*rootp)->link=current->link;
                                    return 1;
                                    
                               }
               (*rootp)->link=current;
               
               }
              return 0;
 }

參考書方案:

int sll_remove(Node *linkp,Node *delete){
     register Node *current;
     assert(delete!=NULL);
    while((currnet=*linkp)!=NULL && current != delete)
                 linkp=&current->link;
   if(current==delete){
      *linkp=current->link;
       free(current);
      return 1;
   }
   else
     return 0;
 }