Linux 鏈表學習

來源:互聯網
上載者:User

對於鏈表,我想每一個程式員都很瞭解。結構就像一根鏈條一樣,一節接一節,而對它的訪問有點像冰糖葫蘆,如果你要吃第二個,你必須先吃掉第一個。這就是單向鏈表。當然它也有更進階的,比如,迴圈鏈表,雙向鏈表,雙向迴圈鏈表。Linux核心的標準鏈表就是環形雙向迴圈鏈表。
       Linux中的鏈表有點特殊,它沒有前端節點,它的尾節點就直接指向首節點。於是構成了一個很大的環,所以每一個節點都是前端節點,你可以從任意節點出發,沿任意的方向逐一查看鏈表或者是它的一部分。
       Linux核心中的鏈表是很優秀的設計,核心中所欲用到鏈表的地方都使用了它,所以在你的代碼中也最好用這些已有的鏈表介面,別螳臂擋車,阻擋潮流了。
      下面我們來看看Linux核心中的鏈表給我們提供了什麼樣的功能。
      首先,鏈表結構體定義在標頭檔<linux/list.h>中,形式很簡單:
      struct list_head {
                struct list_head *next, prev;
      };
     一個list_head結構體本身沒有什麼意義,,通常需要把它嵌入到你自己的結構體中:
     struct my_struct {
              struct list_head list;
              unsigned long dog;
              void *cat;
     };
     鏈表在使用前必須初始化,由於多數元素都是動態建立(也許這就是你需要使用鏈表的原因),所以最常見的情況是在運行時初始化鏈表。
     struct my_struct *p;
     p->dog = 0;
     p->cat = NULL;
     INIT_LIST_HEAD(&p->list);
    
     直接聲明和初始化一個靜態鏈表:
     static LIST_HEAD(fox);
     上述語句聲明並初始化名為fox的靜態鏈表。
     不需要與任何鏈表的內部成員打交到,你僅僅將鏈表結構插入到你自己的資料中就可以了。
操作鏈結表    核心提供了一組函數來操作鏈結表,這些函數都要使用一個或多個list_head結構體指標做參數。因為函數都是用C語言以內嵌函式形式實現的,所以它們的原型都在標頭檔<linuxlist.h>中。
     有趣的是,所有這些函數的複雜度都是O(1),也就是說,無論這些函數操作的鏈表大小如何,無論它們得到額參數如何,它們都在恒定的時間裡完成。
1,給鏈表增加一個節點:在給定節點之後
     list_add(struct list_head *new, struct list_head *head)
2,給鏈表增加一個節點:在給定節點之前
    list_add_tail(struct list_head *new, struct list_head *head)
3,從鏈表刪除一個節點:
    lsit_del(struct list_head *entry)
需要自己手動釋放entry結構體
4,從鏈表中刪除一個節點,並對其進行重新初始化
    lsit_del_init(struct list_head *entry)
5,把節點從一個鏈表移到另一個鏈表:
    list_move(struct list_head *list, struct list_head *head)
    list_move_tail(struct list_head *list, struct list_head *head)
6,檢查鏈表是否為空白:
    lsit_empty(struct list_head *head)
    如果指定的鏈表為空白,該函數返回非0值,否則返回0
7,合并兩個鏈表
    list_splice(struct list_head *list, struct list_head *head)
    list_splice_init(struct list_head *list, struct list_head *head)
如果你已經得到了next和prev指標,那你可以使用內部操作函數,從而省下提領指標的時間,內建函式與外部函數重名,只是在前面加了兩條底線。
遍曆鏈表:
核心給我們提供了一組非常好用的介面來遍曆鏈表,不過它們的複雜度為O(n),n為鏈表中的元素數目。list_for_each()宏就是用來遍曆鏈表,它有兩個參數,第一個用來指向當前項,第二個是需要遍曆的鏈表,但是它得到的只是lsit_head的指標,而我麼您需要的是插入了list_head的結構體。list_entry()宏可以協助我們它有三個參數,一個是指向給定的鏈表元素的指標,一個是其中嵌入了鏈表的結構體類型的引用,另一個是結構體中鏈表成員的名稱:如下是用法:
       struct list_head *p;
       struct my_struct * my;
       list_for_each(p, &mine->list) {
             my = list_entry(p, struct my_struct, list);
       }
還有一些宏:list_for_each_prev()      list_for_each_safe()  可以選擇使用
最後一個宏只能用來防止鏈表刪除操作,為了防止並發訪問實際的鏈表資料,應該使用其他的鎖

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.