1、前言
最近寫代碼需用到連結清單結構,正好公共庫有關于連結清單的。第一眼看時,覺得有點新鮮,和我之前見到的連結清單結構不一樣,隻有前驅和後繼指針,而沒有資料域。後來看代碼注釋發現該代碼來自linux核心,在linux源代碼下include/lish.h下。這個連結清單具備通用性,使用非常友善。隻需要在結構定義一個連結清單結構就可以使用。
2、連結清單介紹
連結清單是非常基本的資料結構,根據鍊個數分為單連結清單、雙連結清單,根據是否循環分為單向連結清單和循環連結清單。通常定義定義連結清單結構如下:
連結清單中包含資料域和指針域。連結清單通常包含一個頭結點,不存放資料,友善連結清單操作。單向循環連結清單結構如下圖所示:
雙向循環連結清單結構如下圖所示:
這樣帶資料域的連結清單降低了連結清單的通用性,不容易擴充。linux核心定義的連結清單結構不帶資料域,隻需要兩個指針完成連結清單的操作。将連結清單節點加入資料結構,具備非常高的擴充性,通用性。連結清單結構定義如下所示:
連結清單結構如下所示:
需要用連結清單結構時,隻需要在結構體中定義一個連結清單類型的資料即可。例如定義一個app_info連結清單,
3、linux核心連結清單實作
核心實作的是雙向循環連結清單,提供了連結清單操作的基本功能。
(1)初始化連結清單頭結點
list_head宏建立一個連結清單頭結點,并用list_head_init宏對頭結點進行指派,使得頭結點的前驅和後繼指向自己。
init_list_head函數對連結清單進行初始化,使得前驅和後繼指針指針指向頭結點。
(2)插入節點
插入節點分為從連結清單頭部插入list_add和連結清單尾部插入list_add_tail,通過調用__list_add函數進行實作,head->next指向之一個節點,head->prev指向尾部節點。
(3)删除節點
從連結清單中删除一個節點,需要改變該節點前驅節點的後繼結點和後繼結點的前驅節點。最後設定該節點的前驅節點和後繼結點指向list_position1和list_position2兩個特殊值,這樣設定是為了保證不在連結清單中的節點項不可通路,對list_position1和list_position2的通路都将引起頁故障
(4)移動節點
move将一個節點移動到頭部或者尾部。
(5)判斷連結清單
list_is_last函數判斷節點是否為末尾節點,list_empty判斷連結清單是否為空。
(6)周遊連結清單
宏list_entity擷取連結清單的結構,包括資料域。list_first_entry擷取連結清單第一個節點,包括資料源。list_for_each宏對連結清單節點進行周遊。
4、測試例子
編寫一個簡單使用連結清單的程式,進而掌握連結清單的使用。
自定義個類似的list結構如下所示:mylist.h
mylist.c如下所示:
測試結果如下所示: