1. 程式人生 > >linux 雙向迴圈連結串列(下)

linux 雙向迴圈連結串列(下)

1 雙向連結串列在Linux核心中的實現過程

    Linux核心對雙向迴圈連結串列的設計非常巧妙,連結串列的所有運算都基於只有兩個指標域的list_head結構體來進行。 

  1. /* linux-2.6.38.8/include/linux/types.h */
  2. struct list_head {  
  3.     struct list_head *next, *prev;  
  4. };  

    連結串列的運算(原始碼都在linux-2.6.38.8/include/linux/list.h檔案中定義,並且假定CONFIG_DEBUG_LIST未定義):

    (1)、連結串列頭結點的建立

    1.1 靜態建立 

  1. #define LIST_HEAD_INIT(name) { &(name), &(name) }
  2. #define LIST_HEAD(name) \
  3.     struct list_head name = LIST_HEAD_INIT(name)  

    通過LIST_HEAD巨集建立一個list_head結構體變數name,並把name的所有成員(next和prev)都初始化為name的首地址。 

    1.2 動態建立 

  1. staticinlinevoid INIT_LIST_HEAD(
    struct list_head *list)  
  2. {  
  3.     list->next = list;  
  4.     list->prev = list;  
  5. }  

    把list_head結構體變數的首地址傳遞給INIT_LIST_HEAD函式來對其成員進行初始化。

    (2)、結點的新增

    list_add函式是把新結點new新增到head結點的後面,而list_add_tail函式是把新結點new插入到結點head的前面。

    函式原始碼如下: 

  1. staticinlinevoid __list_add(
    struct list_head *new,  
  2.                   struct list_head *prev,  
  3.                   struct list_head *next)  
  4. {  
  5.     next->prev = new;  
  6.     new->next = next;  
  7.     new->prev = prev;  
  8.     prev->next = new;  
  9. }  
  10. staticinlinevoid list_add(struct list_head *newstruct list_head *head)  //
  11. {  
  12.     __list_add(new, head, head->next);  
  13. }  
  14. staticinlinevoid list_add_tail(struct list_head *newstruct list_head *head)  
  15. {  
  16.     __list_add(new, head->prev, head);  
  17. }  
  1.    (3)、結點的刪除

list_del函式的作用是將結點*entry從連結串列中移走,並把此結點的兩個成員分別初始化為LIST_POISON1和LIST_POISON2。注意,這裡的*entry結點所佔用的記憶體並沒有被釋放。

    list_del_init函式的作用也是將結點*entry從連結串列中移走,但它把此結點的兩個成員初始化為entry。 

  1. staticinlinevoid __list_del(struct list_head * prev, struct list_head * next)  
  2. {  
  3.     next->prev = prev;  
  4.     prev->next = next;  
  5. }  
  6. staticinlinevoid __list_del_entry(struct list_head *entry)  
  7. {  
  8.     __list_del(entry->prev, entry->next);  
  9. }  
  10. staticinlinevoid list_del(struct list_head *entry)  
  11. {  
  12.     __list_del(entry->prev, entry->next);  
  13.     entry->next = LIST_POISON1;  
  14.     entry->prev = LIST_POISON2;  
  15. }  
  16. staticinlinevoid list_del_init(struct list_head *entry)  
  17. {  
  18.     __list_del_entry(entry);  
  19.     INIT_LIST_HEAD(entry);  
  20. }  

    LIST_POISON1和LIST_POISON2的值定義在linux-2.6.38.8/include/linux/poison.h檔案中: 

  1. #define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
  2. #define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)

    其中POISON_POINTER_DELTA的值在CONFIG_ILLEGAL_POINTER_VALUE未配置時為0。

    (4)、結點的替換

   list_replace函式的作用是用結點*new替換掉結點*old,list_replace_init函式的作用與list_replace相同,除了它還會把*old結點的兩個成員初始化為old外。 

  1. staticinlinevoid list_replace(struct list_head *old,  
  2.                 struct list_head *new)  
  3. {  
  4.     new->next = old->next;  
  5.     new->next->prev = new;  
  6.     new->prev = old->prev;  
  7.     new->prev->next = new;  
  8. }  
  9. staticinlinevoid list_replace_init(struct list_head *old,  
  10.                     struct list_head *new)  
  11. {  
  12.     list_replace(old, new);  
  13.     INIT_LIST_HEAD(old);  
  14. }  

     (5)、結點的移動

    list_move函式的作用是把*list結點從它所在的連結串列中移除,然後把它新增到*head結點的後面。list_move_tail函式的作用與list_move相同,但它把*list插入到*head結點的前面。 

  1. staticinlinevoid list_move(struct list_head *list, struct list_head *head)  
  2. {  
  3.     __list_del_entry(list);  
  4.     list_add(list, head);  
  5. }  
  6. staticinlinevoid list_move_tail(struct list_head *list,  
  7.                   struct list_head *head)  
  8. {  
  9.     __list_del_entry(list);  
  10.     list_add_tail(list, head);  
  11. }  

    (6)、判斷*list是否是連結串列head的最後一個結點,是則返回1,否則返回0 

  1. staticinlineint list_is_last(conststruct list_head *list,  
  2.                 conststruct list_head *head)  
  3. {  
  4.     return list->next == head;  
  5. }  

    (7)、判斷head是否為空表,是則返回1,否則返回0 

  1. staticinlineint list_empty(conststruct list_head *head)  
  2. {  
  3.     return head->next == head;  
  4. }  
  5. staticinlineint list_empty_careful(conststruct list_head *head)  
  6. {  
  7.     struct list_head *next = head->next;  
  8.     return (next == head) && (next == head->prev);  
  9. }  

    (8)、翻轉連結串列 

  1. 相關推薦

    linux 雙向迴圈連結串列

    1 雙向連結串列在Linux核心中的實現過程     Linux核心對雙向迴圈連結串列的設計非常巧妙,連結串列的所有運算都基於只有兩個指標域的list_head結構體來進行。  /* linux-2.6.38.8/include/linux/t

    雙向迴圈連結串列帶頭結點

    //定義結構體 typedef struct data {       int  data;       struct data *pro;   //前驅       struct data *next; //後繼 }DATA; //建立雙向迴圈連結串列 DATA *cr

    C++ 雙向迴圈連結串列簡稱:雙鏈表

    一、概念     1.在雙鏈表中的每個結點應有兩個連結指標:               lLink -> 指向前驅結點&nb

    C++——實現雙向迴圈連結串列帶頭結點

    雙向連結串列也叫雙鏈表,是連結串列的一種,它的每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅。所以,從雙向連結串列中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。一般我們都構造雙向迴圈連結串列。 簡單的畫一個雙向迴圈簡易圖: 下面就用C++實現一下基本操

    C++資料結構與STL--雙向迴圈連結串列實現自定義iterator類

    class dLinkList {private:node<T> *head;  //頭節點size_t length; //連結串列長度void dInsert(node<T> *curr,T val)  //插入的輔助函式,把新節點插入curr前 {node<T>* t

    雙向迴圈連結串列建立·插入·刪除·遍歷

    author:chen ming dong #include<stdio.h> #include<stdlib.h> typedef struct list { int a; struct list *next;

    連結串列:如何輕鬆寫出正確的連結串列程式碼?

    本文是學習演算法的筆記,《資料結構與演算法之美》,極客時間的課程 寫好連結串列程式碼 技巧一、理解指標或引用的含義 不管是C語言中指標的含義,還是JAVA語言中引用的概念,它們的意思是一樣的,都是儲存所指物件的記憶體地址。 編寫連結串列程式碼的時候,這樣的程式碼: p -&g

    07-連結串列:如何輕鬆寫出正確的連結串列程式碼

    上一節我講了連結串列相關的基礎知識。學完之後,我看到有人留言說,基礎知識我都掌握了,但是寫連結串列程式碼還是很費勁。哈哈,的確是這樣的! 想要寫好連結串列程式碼並不是容易的事兒,尤其是那些複雜的連結串列操作,比如連結串列反轉、有序連結串列合併等,寫的時候非常容易

    雙向迴圈連結串列c++)

    #include<iostream> using namespace std; struct ListNode { ListNode() :_data(0) ,_prev(0) , _next(0) {} ListNode( c

    Linux 核心建立雙向迴圈連結串列

    #define LIST_HEAD_INIT(name) { &(name), &(name) }    #define LIST_HEAD(name) \ struct list_h

    Linux 核心雙向迴圈連結串列list_head

    什麼是雙向迴圈連結串列就不說了,學習linux的應該都有C家族的基礎。 struct list_head {   struct list_head *next, *prev; }; list_head

    資料結構與演算法-線性表之雙向連結串列雙向迴圈連結串列

    前言:前面介紹了迴圈連結串列,雖然迴圈連結串列可以解決單鏈表每次遍歷只能從頭結點開始,但是對於查詢某一節點的上一節點,還是頗為複雜繁瑣,所以可以在結點中加入前一個節點的引用,即雙向連結串列 一、簡介   雙向連結串列:在連結串列中,每一個節點都有對上一個節點和下一個節點的引用或指標,即從一個節點出發可以有

    UVa11925 生成排列Generating Permutations---雙向迴圈連結串列

    題目描述:給你一個特定序列,要求你經過一定的變換規則將升序列變為給的特定序列。 https://vjudge.net/problem/UVA-11925 變換規則為:1.第一個元素和第二個元素交換. 2、首元素到尾部。 題目分析:逆著處理,最後輸出的時候倒著輸出就行了。若第一個元素大於第

    資料結構學習筆記——C++實現雙向迴圈連結串列模板類超詳解

    定義了兩個標頭檔案分別放置結點類模板(Node.h)和雙鏈表模板(DoubleLinkList.h), 然後在原始檔的main函式中測試。 Node.h #pragma once # include <iostream> template <class

    C語言實現雙向迴圈連結串列帶頭結點尾結點的基本操作

           我在之前一篇部落格中《C語言實現雙向非迴圈連結串列(不帶頭結點)的基本操作》中詳細實現了不帶頭尾節點的雙向非迴圈連結串列的很多操作。其實同單鏈表一樣,不帶頭結點的連結串列很多操作都是比較麻

    C語言學習歷程雙向迴圈連結串列

    首先通過定義結構體。 接著是完整的函式: #include <stdio.h> #include <stdlib.h> #define T 1 #define F 0 typedef int Elementype; typedef int

    C語言版連結串列——實現雙向迴圈連結串列建立、插入、刪除、釋放記憶體等簡單操作

    雙向迴圈連結串列是基於雙向連結串列的基礎上實現的,和雙向連結串列的操作差不多,唯一的區別就是它是個迴圈的連結串列,通過每個節點的兩個指標把它們扣在一起組成一個環狀。所以呢,每個節點都有前驅節點和後繼節點(包括頭節點和尾節點)這是和雙向連結串列不同的地方。我們看下雙向迴圈連結

    雙向迴圈連結串列C++實現完整版

    #include<iostream> using namespace std; /* *節點類 */ struct DCNode { int data; DCNode * prior; DCNode * next; }; /* *連結串列類 */

    資料結構雙向迴圈連結串列C語言

     C語言實現雙向迴圈連結串列的基本功能與除錯: //DoubleCircleLinkLst.h #ifndef _LINKLIST_H #define _LINKLIST_H #include <stdio.h> #include <stdlib.h&g

    《劍指offer》系列 二叉搜尋樹與雙向連結串列Java

    連結 牛客: 二叉搜尋樹與雙向連結串列 題目描述 輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。 思路 這個程式碼是借鑑網上的,整體結構和中序遍歷非常類似,只不過將原本輸出那部分的操作換成了改變結