zoukankan      html  css  js  c++  java
  • Linux内核中链表的学习


    一、自己学习链表

        数组的缺点:(1)数据类型一致;(2)数组的长度事先定好,不能灵活更改。

        从而引入了链表来解决数组的这些缺点:(1)结构体解决多数据类型(2)链表的组合使得链表的长度可以灵活设置。

             7b8dc810-d301-444c-aaf9-70c9a0465602

    基本概念:

    头结点:

        这个节点是为了便于管理链表的节点,这个节点并不保存数据;虽然和其他节点一样,但是这个头结点是指向首节点的节点。

    首节点:

        第一个保存有效数据的节。

    尾节点:

        最后一个保存有效数据的节点

    头指针:

        头指针是指向头节点的指针。


    单链表:

    链表节点的数据结构定义:

    typedef struct Node
    {
        int data;
        struct Node *PNEXT;
    }NODE,*PNODE;

    单链表的代码:

    
    
    typedef struct Node
    {
        int data;
        struct Node *PNEXT;
    }NODE,*PNODE;
    
    
    // 创建链表的节点
    PNODE create_node(int data)
    {
        // 创建结点
        PNODE p = (PNODE)malloc(sizeof(NODE));
        if (NULL == p)
        {
            printf("malloc error
    ");
            exit(-1);
        }
        memset(p, 0, sizeof(NODE));
    
        p->data = data;
        p->PNEXT = NULL;
    
        return p;
    }
    
    // 链表的初始化
    PNODE create_list()
    {
    
        int iLen_list = 0;
        int iData_list = 0;
    
        // 创建头结点
        PNODE pHead = NULL;
        pHead = (PNODE)malloc(sizeof(NODE));
        if (NULL == pHead)
        {
            printf("malloc pHead error
    ");
            exit(-1);
        }
        pHead->data = NULL;
        pHead->PNEXT = NULL;
    
        // 定义一个尾指针
        PNODE pTail = pHead;
    
        printf("输出链表的长度,n = 
    ");
        scanf("%d", &iLen_list);
    
        // 初始化创建节点的数据
        for (size_t i = 0; i < iLen_list; i++)
        {
            PNODE pNew = NULL;
            printf("输出链表第 %d 个的值", i + 1);
            scanf("%d", &iData_list);    
    
            // 创建节点
            pNew = create_node(iData_list);
    
            // 保证尾指针是一直指向最后一个节点
            pTail->PNEXT = pNew;
            pTail = pNew;
        }
    
        return pHead;
    }
    
    // 判断链表是否为空
    bool is_list_empty(PNODE pHead)
    {
        if (pHead->PNEXT == nullptr)
            return true;
        else
            return false;
    }
    
    // 链表的长度
    int len_list(PNODE pHead)
    {
        PNODE pNew = pHead;
        int i = 0;
    
        while ( pNew->PNEXT != nullptr )
        {
            i++;
            pNew = pNew->PNEXT;
        }
        return i;
    }
    
    //    遍历链表的所有节点
    void traver_all_list(PNODE pHead)
    {
    
        if (is_list_empty(pHead))
        {
            printf("空链表
    ");
            exit(-1);
        }
    
        PNODE pNew = pHead;
        while (pNew->PNEXT != nullptr )
        {        
            pNew = pNew->PNEXT;
            printf("%d
    ", pNew->data);
        }
    }
    
    // 链表的尾部添加数据
    bool list_append_tail(PNODE pHead,int data)
    {
    
        int i = NULL;
        if (is_list_empty(pHead))
        {
            printf("空链表
    ");
            return false;
        }
    
        PNODE pNew = pHead;
        while ((pNew->PNEXT != nullptr) )
        {  // pNew 最后指向最后一个节点
            pNew = pNew->PNEXT;
        }
    
        PNODE pNewOne = create_node(data);
        pNew->PNEXT = pNewOne;
    
        pNewOne->data = data;
        pNewOne->PNEXT = nullptr;
    
        return true;
    }
    
    // 链表的尾部插入数据
    bool list_insert_tail(PNODE pHead, int data)
    {
    
        int i = NULL;
        if (is_list_empty(pHead))
        {
            printf("空链表
    ");
            return false;
        }
    
        PNODE pNew = pHead;
        while ( (pNew->PNEXT != nullptr) && ( i<len_list(pHead) - 1) )
        {  // pNew 最后指向最后一个节点
            pNew = pNew->PNEXT;
            i++;
        }
    
        PNODE pNewOne = create_node(data);
        pNewOne->PNEXT = pNew->PNEXT;
        pNewOne->data = data;
    
        pNew->PNEXT = pNewOne;
    
        return true;
    }
    
    // 链表的头也就是添加一个新的链表的首节点
    bool list_insert_head(PNODE pHead, int data)
    {
        PNODE pNew = pHead;
        
        // 创建新的首节点,并使之节点指向旧的首节点
        PNODE pNewOne = create_node(data);
        pNewOne->data = data;
        pNewOne->PNEXT = pNew->PNEXT;
    
        // 头结点指向首节点
        pNew->PNEXT = pNewOne;
        return true;
    }
    
    // 插入链表 N 位置
    bool list_N_insert(PNODE pHead,int n, int data)
    {
        
        PNODE pNew = pHead;
        int i = 0;
    
        // 空的链表就不要插入了
        if (is_list_empty(pHead))
        {
            printf("空链表
    ");
            return false;
        }
    
        // 插入首节点
        if (n >len_list(pHead) + 1)
        {
            cout << "添加的位置大于链表的长度" << endl;
            return false;
        }
        else if ( 1 == n )
        {
            return list_insert_head(pHead,data);
        }
        else if (n == len_list(pHead))
        {
            // 插入尾节点
            return list_insert_tail(pHead,data);
        }
        else
        {
            while ( (pNew->PNEXT != nullptr) && (i<n-1))
            {
                // 在 N 的位置插入,则必须使得 pNew 指向 n-1 的位置
                pNew = pNew->PNEXT;
                i++;
            }
    
            PNODE pNewOne = create_node(data);
            pNewOne->data = data;
            pNewOne->PNEXT = pNew->PNEXT;
            pNew->PNEXT = pNewOne;
    
            return true;
        }
    
    }
    
    // 删除链表的首节点
    bool delete_list_heap(PNODE pHead)
    {
        if (is_list_empty(pHead))
        { // 空的链表的话,就没有什么好删除的
            printf("空链表,不需要删除
    ");
            return false;
        }
    
        // 指向首节点
        PNODE pNew = pHead->PNEXT;
        // 头结点指向第二个节点
        pHead->PNEXT = pNew->PNEXT;
        cout << "删除节点的数值是:" << pNew->data << endl;
    
        free (pNew);
        pNew = nullptr;
    
        return true;
    }
    
    // 删除链表的尾节点
    bool delete_list_tail(PNODE pHead)
    {
        int i = NULL;
    
        if (is_list_empty(pHead))
        {
            printf("空链表
    ");
            return false;
        }
    
        PNODE pNew = pHead;
        while ((pNew->PNEXT != nullptr) && (i < len_list(pHead))-1)
        { // 使得 pNew 指向尾节点的倒数一个节点
            pNew = pNew->PNEXT;
            i++;
        }
    
        PNODE pDelOne = pNew->PNEXT;
        cout << "删除节点的数值是:" << pDelOne->data << endl;
    
        pNew->PNEXT = nullptr;
        free(pDelOne);
        pDelOne = nullptr;
    
        return true;
    }
    
    
    // 删除链表 N 位置
    bool delete_N_list(PNODE pHead, int n)
    {
        PNODE pNew = pHead;
        int i = 0;
    
        // 空的链表就不要插入了
        if (is_list_empty(pHead))
        {
            printf("空链表
    ");
            return false;
        }
    
        if (n > len_list(pHead))
        {
            cout << "删除的位置大于链表的长度" << endl;
            return false;
        }
        else if ( 1 == n )
        {// 删除首节点
            return delete_list_heap(pHead);
        }
        else if (n == len_list(pHead))
        { // 删除尾节点
            return delete_list_tail(pHead);
        }
        else
        { // 删除除了首节点尾节点以外的节点,pNew 指向删除节点前面的那个节点
            while ((pNew->PNEXT != nullptr) && (i<n-1) )
            {
                pNew = pNew->PNEXT;
                i++;
            }
    
            PNODE pDelOne = pNew->PNEXT;
            pNew->PNEXT = pDelOne->PNEXT;
            cout << "删除节点的数值是:" << pDelOne->data << endl;
            free(pDelOne);
            pDelOne = nullptr;
    
            return true;
        }
    }
    
    // 链表的排序
    bool sort_list(PNODE pHead)
    {
        if (is_list_empty(pHead))
        {
            printf("空链表
    ");
            return false;
        }
    
        int n = len_list(pHead);
    
        PNODE pp = nullptr;
        PNODE qq = nullptr;
        int i, j;
        int Temp;
    
        for (pp = pHead->PNEXT, i = 0; i < n-1; i++, pp = pp->PNEXT)
        {
            for (qq = pp->PNEXT, j = i+1; j < n; j++,qq = qq->PNEXT)
            {
                if (  pp->data > qq->data )
                {
                    Temp = pp->data;
                    pp->data = qq->data;
                    qq->data = Temp;
                }
            }
        }
    
        return true;
    }
    
    
    int main(int argc, char *argv[])
    {
        
        PNODE pHead = NULL;
        int iLen_lis = NULL;                                                              
    
        // 创建链表已经初始化
        pHead = create_list();
    
        // 链表的遍历
        traver_all_list(pHead);
    
        // 计算链表长度
        iLen_lis = len_list(pHead);
        cout << "链表的长度是:" << iLen_lis << endl;
        
        // 链表尾部添加数据
        if (list_append_tail(pHead, 4))
        {
            cout << "链表的尾部添加数据成功" << endl;
    
            iLen_lis = len_list(pHead);
            cout << "链表的长度是:" << iLen_lis << endl;
            traver_all_list(pHead);
        }    
    
        // 链表头部添加数据
        cout << endl;
        if (list_insert_head(pHead, 5))
        {
            cout << "链表的首节点添加数据成功" << endl;
    
            iLen_lis = len_list(pHead);
            cout << "链表的长度是:" << iLen_lis << endl;
            traver_all_list(pHead);
        }
    
        // 指定位置插入数据
        cout << endl;
        if (list_N_insert(pHead,4,99))
        {
            cout << "插入成功" << endl;
            iLen_lis = len_list(pHead);
            cout << "链表的长度是:" << iLen_lis << endl;
            traver_all_list(pHead);
        }
    
        // 指定位置删除数据
        cout << endl;
        if (delete_N_list(pHead, 5))
        {
            cout << "删除成功" << endl;
            iLen_lis = len_list(pHead);
            cout << "链表的长度是:" << iLen_lis << endl;
            traver_all_list(pHead);
        }
    
        // 链表的排序
        cout << endl;
        if ( sort_list(pHead) )
        {
            cout << "排序成功" << endl;
            traver_all_list(pHead);
        }
    
        while (1);
    }

       经过自己的实测是正确的:

    输出链表的长度,n =
    3
    输出链表第 1 个的值1
    输出链表第 2 个的值2
    输出链表第 3 个的值3
    1
    2
    3
    链表的长度是:3
    链表的尾部添加数据成功
    链表的长度是:4
    1
    2
    3
    4
    
    链表的首节点添加数据成功
    链表的长度是:5
    5
    1
    2
    3
    4
    
    插入成功
    链表的长度是:6
    5
    1
    2
    99
    3
    4
    
    删除节点的数值是:3
    删除成功
    链表的长度是:5
    5
    1
    2
    99
    4
    
    排序成功
    1
    2
    4
    5
    99

    补充:单链表的逆序

    bool reverse_list(PNODE pHead)
    {
        if (is_list_empty(pHead))
        {
            printf("空链表
    ");
            return false;
        }
        
        PNODE Temp0 = pHead;
        PNODE Temp1 = pHead;
        PNODE Temp3 = pHead->PNEXT;
        PNODE Temp2 = nullptr;
        int i = 1;
        while (Temp3->PNEXT != nullptr)
        {
            Temp2 = Temp3;
            Temp3 = Temp3->PNEXT;
            if ( 1 == i)
            {
                Temp2->PNEXT = nullptr;
            }
            else
            {
                Temp2->PNEXT = Temp1;
            }
            i++;    
            Temp1 = Temp2;
        }
        Temp3->PNEXT = Temp2;
        Temp0->PNEXT = Temp3;
        return true;
    }

        传入了头结点的指针,99f11dab-1add-407c-8990-974e3b01ae06

        首先 T2 接替 T3,T2指向了下一个节点,而 T1 接替 T2,就这样一部一部,使之 T2 永远指向 T1,当 T3 结束的时候,T3 是没有指向 T2 的,所以退出循环就执行Temp3->PNEXT = Temp2;,而头结点 T0->PNEXT

    = T3.

    双链表:

    因为单链表的操作的不便(一旦指针指向一个节点,就无法返回来,必须重新进行循环),所以就引入了双向链表。

    双向链表的数据定义:

    typedef struct Node
    {
        int data;
        struct Node * PPREV;
        struct Node * PNEXT;
    }NODE, *PNODE;

        因为是双向链表,所以就定义了两个指向节点的指针,prev 往前指,next 指向后面的节点。

        特殊的是:头结点的 prev 是指向尾节点(最后一个节点),而尾节点的 next 是指向头结点的。

    cd3a79ee-e101-40af-82e4-32d7c86ddd1a

    代码:

    #define DEBUG
    #ifdef DEBUG
    #define DBG(fmt, args,...)     printf(fmt, ##args)
    #else
    #define DBG(fmt, args...)     do {} while (0)
    #endif
    typedef struct Node
    {
        int data;
        struct Node * PPREV;
        struct Node * PNEXT;
    }NODE, *PNODE;
    // 创建单个节点
    PNODE create_node(int data)
    {
        PNODE pNew = nullptr;
        pNew = (PNODE)malloc(sizeof(NODE));
        if ( nullptr == pNew)
        {
            cout << " malloc error" << endl;
            exit(-1);
        }
        pNew->PNEXT = nullptr;
        pNew->PPREV = nullptr;
        pNew->data = data;
        return pNew;
    }
    // 链表的初始化
    PNODE create_list()
    {
        int i = 0;
        int iLenList = NULL;
        int iDataList = NULL;
        PNODE pHead = nullptr;
        PNODE pTail = nullptr;
        pHead = (PNODE)malloc(sizeof(NODE));
        if ( nullptr == pHead )
        {
            cout << " malloc error" << endl;
            exit(-1);
        }
        pHead->data = NULL;
        pHead->PNEXT = pHead->PPREV = nullptr;
        pTail = pHead;
        
        printf("输入链表的长度 n = ");
        scanf("%d", &iLenList);
        for ( i = 0; i < iLenList; i++)
        {
            printf("输入创建 第 %d 节点的数据
    ", i + 1);
            scanf("%d", &iDataList);
            PNODE pNew = create_node( iDataList );
            pTail->PNEXT = pNew;
            pHead->PPREV = pNew;
            pNew->PPREV = pTail;
            pNew->PNEXT = pHead;
            pTail = pNew;
        }
        return pHead;
    }
    bool list_is_empty(PNODE pHead)
    {
        PNODE pNew = pHead;
        if ( pNew->PNEXT == nullptr )
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    // 双向链表的遍历
    bool traver_list(PNODE pHead)
    {
        if ( list_is_empty(pHead))
        {
            cout << "空链表" << endl;
            return false;
        }
        PNODE pNew = pHead, pHeadNew = pHead;
        while (pNew->PNEXT != pHeadNew)
        {
            pNew = pNew->PNEXT;
            cout << pNew->data << endl;
        }
        return true;
    }
    // 计算链表的长度
    int len_list(PNODE pHead)
    {
        PNODE pHeadNew = pHead;
        int i = NULL;
        PNODE pNew = pHead;
        while ( pNew->PNEXT != pHeadNew )
        {
            pNew = pNew->PNEXT;
            i++;
        }
        return i;
    }
    // 链表的尾部添加数据
    bool list_tail_append_data(PNODE pHead, int data)
    {
        PNODE  pHeadNew = pHead;
        PNODE pTail = pHead;
        DBG("%d 
    ", __LINE__);
        int n = len_list(pHead);
        int i = 0;
        //  抱枕 pTail 指向最后一个节点
        while ( i < (n) )  // 从头结点到尾节点需要移动 n(链表长度)次数
        {
            pTail = pTail->PNEXT;
            i++;
        }
        // 创建新的节点
        PNODE pNewOne = (PNODE)malloc(sizeof(NODE));
        if ( nullptr == pNewOne )
        {
            cout << "malloc error" << endl;
            return false;
        }
        pNewOne->data = data;
        DBG("%d 
    ", __LINE__);
        pTail->PNEXT = pNewOne;
        pNewOne->PPREV = pTail;
        pNewOne->PNEXT = pHeadNew;
        pHeadNew->PPREV = pNewOne;
        DBG("%d 
    ", __LINE__);
        return true;
    }
    // 链表的头部添加数据
    bool list_heap_insert_data(PNODE pHead, int data)
    {
        if ( list_is_empty(pHead))
        {
            printf("空链表 
    ");
            return false;
        }
        PNODE pHeadNew = pHead;
        PNODE pNewOne = (PNODE)malloc(sizeof(NODE));
        pNewOne->data = data;
        pNewOne->PNEXT = pHeadNew->PNEXT;
        pHeadNew->PNEXT->PPREV = pNewOne;
        pHeadNew->PNEXT = pNewOne;
        return true;
    }
    bool list_tail_insert(PNODE pHead,int data)
    {
        PNODE pHeadNew = pHead;
        PNODE pNew = pHead;
        int i = 0;
        int n = len_list(pHeadNew);
        while (i<(n-1))
        { // pNew 指向尾节点的前面一个节点,
            i++;
            pNew = pNew->PNEXT;
        }
        PNODE pNewOne = (PNODE)malloc(sizeof(NODE));
        pNewOne->data = data;
        pNewOne->PNEXT = pNew->PNEXT;
        pNew->PNEXT->PPREV = pNewOne;
        pNewOne->PNEXT = pNew;
        pNew->PNEXT = pNewOne;
        return true;
    }
    // 指定位置插入数据
    bool list_N_insert(PNODE pHead, int iPos, int data)
    {
        PNODE pHeadNew = pHead;
        PNODE pNew = pHead;
        if (list_is_empty(pHead))
        {
            printf("空链表 
    ");
            return false;
        }
        int  i = NULL;
        int  n = len_list(pHeadNew);
        if ( iPos > n)
        {
            printf("出入位置大于链表的长度,不能执行插入
    ");
            return false;
        }
        else if ( n == 1)
        {// 在首结点插入数据
            return list_heap_insert_data(pHeadNew, data);
        }
        else if ( n == iPos)
        {// 在尾节点插入数据
            return list_tail_insert(pHeadNew,data); 
        }
        else
        {
            // 在除了尾节点首节点插入数据
            while (i < (iPos - 1))
            {// 使得  pNew  指向删除节点的前面一个节点
                pNew = pNew->PNEXT;
                i++;
            }
            PNODE pNewOne = create_node(data);
            pNewOne->PNEXT = pNew->PNEXT;
            pNew->PNEXT->PPREV = pNewOne;
            pNew->PNEXT = pNewOne;
            pNewOne->PPREV = pNew;
            return true;
        }
    }
    // 删除链表首节点
    bool delete_heap_list(PNODE pHead)
    {
        PNODE pHeadNew = pHead;
        PNODE pNew;
        int n = len_list(pHead);
        if ( n == 1)
        {
            pNew = pHeadNew->PNEXT;
            pHeadNew->PNEXT = pHeadNew;
            pHeadNew->PNEXT = pHeadNew;
            printf("删除数据是%d
    ", pNew->data);
            free(pNew);
            pNew = nullptr;
            return true;
        }
        else
        {
            pNew = pHeadNew->PNEXT;
            pHeadNew->PNEXT = pHeadNew->PNEXT->PNEXT;
            pHeadNew->PNEXT->PPREV = pHeadNew;
            printf("删除数据是%d
    ", pNew->data);
            free(pNew);
            pNew = nullptr;
            return true;
        }
    }
    // 删除链表的尾节点
    bool delete_tail_list(PNODE pHead)
    {
        PNODE pHeadNew = pHead;
        PNODE pNew = pHead;
        PNODE pNewOne = nullptr;
        int n = len_list(pHead);
        int i = NULL;
        while (i < (n - 1))
        {// pNew 指向删除节点的前面一个节点
            pNew = pNew->PNEXT;
            i++;
        }
        pNewOne = pNew->PNEXT;
        printf("删除数据是%d
    ", pNewOne->data);
        pNew->PNEXT = pHeadNew;
        pHeadNew->PPREV = pNew;
        free(pNewOne);
        pNewOne = nullptr;
        
        return true;
    }
    // 删除链表的任意的位置
    bool delete_N_list(PNODE pHead,int iPos)
    {
        if (list_is_empty(pHead))
        {
            printf("空链表 
    ");
            return false;
        }
        PNODE pNew = pHead;
        PNODE pNewOne = pHead;
        int i = NULL;
        int n = len_list(pHead);
        if (iPos > n)
        {
            printf("删除位置大于链表的长度,不能执行删除
    ");
            return false;
        }
        else if ( iPos == 1)
        {
            return delete_heap_list(pHead);
        }
        else if (iPos == n)
        {
            return delete_tail_list(pHead);
        }
        else
        {
            while (i<(iPos - 1))
            {
                pNew = pNew->PNEXT;
                i++;
            }
            pNewOne = pNew->PNEXT;
            pNew->PNEXT = pNewOne->PNEXT;
            pNewOne->PNEXT->PPREV = pNew;
            printf("删除数据是%d
    ", pNewOne->data);
            free(pNewOne);
            pNewOne = nullptr;
            return true;
        }
    }
    // 对链表进行排序
    bool list_sort(PNODE pHead)
    {
        if (list_is_empty(pHead))
        {
            printf("空链表,排序失败
    ");
            return false;
        }
        int n = len_list(pHead);
        PNODE ppNew = nullptr;
        PNODE qqNew = nullptr;
        int i = 0, j = 0;
        int TempDat = NULL;
        for (ppNew = pHead->PNEXT, i = 0; i < (n - 1);i++,ppNew = ppNew->PNEXT)
        {
            for (qqNew = ppNew->PNEXT, j = i+1; j < n;j++,qqNew=qqNew->PNEXT)
            {
                if ( ppNew->data > qqNew->data)
                {
                    TempDat = ppNew->data;
                    ppNew->data = qqNew->data;
                    qqNew->data = TempDat;
                }
            }
        }
        return true;
    }
    int main(int argc, char **argv)
    {
        int iLenList = NULL;
        PNODE pHead = nullptr;
        // 双向链表的初始化
        pHead = create_list();
        if (traver_list(pHead))
        {
            cout << "遍历成功" << endl;
        }
        iLenList = len_list(pHead);
        printf("链表长度等于 %d
    ", iLenList);
        // 链表的尾部添加数据
        if (list_tail_append_data(pHead, 4))
        {
            list_tail_append_data(pHead, 5);
            printf("尾部添加数据成功
    ");
            traver_list(pHead);
        }
        if (list_heap_insert_data(pHead, 10))
        {
            list_heap_insert_data(pHead, 11);
            printf("头部添加数据成功
    ");
            traver_list(pHead);
        }
        // 链表的任意位置添加数据
        if (list_N_insert(pHead,3,99))
        {
            printf("位置3添加数据成功
    ");
            traver_list(pHead);
        }
        // 任意位置删除数据
        if (delete_N_list(pHead, 8))
        {
            printf("位置8删除数据成功
    ");
            traver_list(pHead);
        }
        // 排序
        if ( list_sort(pHead) )
        {
            printf("排序成功
    ");
            traver_list(pHead);
        }
        while (1);
    }

      双链表和单链表的操作其实很多的类似,参考者编写代码,还是比较简单的。参照了单链表,也是设置了头结点用于帮助设计双向链表,然后还有首尾节点,这些才是正真保存数据的开始的节点和结束的节点。

    二、内核链表的学习

        对于链表的操作自己编写的话过于麻烦,而Linux内核提供了对应的API,可以直接调用方便使用:D:source insightlinux2.6.35.7android-kernel-samsung-devincludelinux 的 list.h。

    0、链表节点的指针

    struct list_head 
    {
        struct list_head *next, *prev;
    };

        链表结构体的指针有两个:next 指向下一个节点,prev 指向上一个节点。也就是说内核链表具备了双向链表的功能,而且链表只是纯链表,并不具备数据类型,所以具备非常大的通用性,这样可以自己根据自己的实际的需求去设计。

    1、链表头结点的初始化

    (1)定义且初始化

    #define LIST_HEAD_INIT(name) { &(name), &(name) }
    #define LIST_HEAD(name) 
        struct list_head name = LIST_HEAD_INIT(name)

        链表头结点定义的时候且完成初始化,将上面的宏进行进行展开:

    #define LIST_HEAD(name) 
        struct list_head name = { &(name), &(name) }

        是将链表的头结点的两个指针分别都指向了自己,从而完成链表头结点的初始化。

    (2)先定义后完成初始化

    static inline void INIT_LIST_HEAD(struct list_head *list)
    {
        list->next = list;
        list->prev = list;
    }

        对于一个已经完成链表头节点初始化,那么对这个链表头则是调用这个函数来完成初始化。这里函数实现链表头节点的初始化与上面宏完成初始化是一样的,差别无非是定义且初始化,一个是先定义头结点后完成初始化。

    2、链表节点的添加

    static inline void __list_add(struct list_head *new,
                      struct list_head *prev,
                      struct list_head *next)
    {
        next->prev = new;
        new->next = next;
        new->prev = prev;
        prev->next = new;
    }

        对于链表节点的添加,这里需要知道,默认的都是进行尾添加,也就是在节点的后面进行添加。

    注意:

        学习发现,内核的双向链表是其实也是借助了头结点了。

    2.1、链表的头结点进行添加

    static inline void list_add(struct list_head *new, struct list_head *head)
    {
        __list_add(new, head, head->next);
    }

        new 指向全新的节点,而 head 是指向头节点,而head->next 是指头首节点的下一个节点,也就是第二个节点。所以插入的节点 new 是在第一个和第二个节点直接之间完成节点的插入。

    2.2、链表尾部节点的添加

    static inline void list_add_tail(struct list_head *new, struct list_head *head)
    {
        __list_add(new, head->prev, head);
    }

        new 指向新的节点,而 head->prev 指向链表的尾节点,head 指向链表的首节点。所以 new 是被插入在首节点和尾节点之间。

    3、链表删除一个节点

    static inline void __list_del(struct list_head * prev, struct list_head * next)
    {
        next->prev = prev;
        prev->next = next;
    }

     

    static inline void list_del(struct list_head *entry)
    {
        __list_del(entry->prev, entry->next);
        entry->next = LIST_POISON1;
        entry->prev = LIST_POISON2;
    }

        entry 是指向删除节点的指针。 entry->prev 是指向删除节点的前面一个节点,而 entrt->next 指向删除节点的下一个节点。而将删除节点的 prev 和 next 分别设置为 position,对它的定义为:

    /*
     * These are non-NULL pointers that will result in page faults
     * under normal circumstances, used to verify that nobody uses
     * non-initialized list entries.
     */
    #define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
    #define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)

        理解内核的注释, position 不是一个空指针,但是会引起页的错误。

    4、节点的替换

    static inline void list_replace(struct list_head *old,
                    struct list_head *new)
    {
        new->next = old->next;
        new->next->prev = new;
        new->prev = old->prev;
        new->prev->next = new;
    }

        代码还是比较的简单,完成新老节点替换,使得新的节点的指针指向老节点的指向。

    static inline void list_replace_init(struct list_head *old,
                        struct list_head *new)
    {
        list_replace(old, new);
        INIT_LIST_HEAD(old);
    }

        完成新老节点的替换,然后将老节点进行初始化。

    5、节点的移动

    /**
     * list_move - delete from one list and add as another's head
     * @list: the entry to move
     * @head: the head that will precede our entry
     */
    static inline void list_move(struct list_head *list, struct list_head *head)
    {
        __list_del(list->prev, list->next);
        list_add(list, head);
    }

    将 list 指向的节点从 head 为开始的头结点的链表删除之后,又移动到这个链表的首节点。也就是在头结点的后面。

    /**
     * list_move_tail - delete from one list and add as another's tail
     * @list: the entry to move
     * @head: the head that will follow our entry
     */
    static inline void list_move_tail(struct list_head *list,
                      struct list_head *head)
    {
        __list_del(list->prev, list->next);
        list_add_tail(list, head);
    }

        将节点 list 从链表 中删除,并将节点 list 添加到链表(以 head 为头结点)的尾部。

    6、链表的判断

    /**
     * list_is_last - tests whether @list is the last entry in list @head
     * @list: the entry to test
     * @head: the head of the list
     */
    static inline int list_is_last(const struct list_head *list,
                    const struct list_head *head)
    {
        return list->next == head;
    }

    判断节点 list 是不是链表的最后一个节点。

    list 是判断的链表的节点。

    head:是双向量表的头结点。

        代码和简单,就是判断 list 节点的下一个节点是不是 head(头结点)。

    /**
     * list_empty - tests whether a list is empty
     * @head: the list to test.
     */
    static inline int list_empty(const struct list_head *head)
    {
        return head->next == head;
    }

    判断链表是否为空:

        其实就是判断自己的下一个节点是不是指向了自己,因为只有空的链表,也就是只有一个头结点的话,才会自己指向自己。

     

    /**
     * list_empty_careful - tests whether a list is empty and not being modified
     * @head: the list to test
     *
     * Description:
     * tests whether a list is empty _and_ checks that no other CPU might be
     * in the process of modifying either member (next or prev)
     *
     * NOTE: using list_empty_careful() without synchronization
     * can only be safe if the only activity that can happen
     * to the list entry is list_del_init(). Eg. it cannot be used
     * if another CPU could re-list_add() it.
     */
    static inline int list_empty_careful(const struct list_head *head)
    {
        struct list_head *next = head->next;
        return (next == head) && (next == head->prev);
    }

    判断链表是否为空,这次的判断是通过头结点的前驱和后驱是不是指向同一个节点。按照字面上面的解释,是怕在判断的时候被CPU 的其他的线程修改了数据,因此这种判断的方法是比较的正确的。

    7、链表的首节点放到尾节

    /**
     * list_rotate_left - rotate the list to the left
     * @head: the head of the list
     */
    static inline void list_rotate_left(struct list_head *head)
    {
        struct list_head *first;
        if (!list_empty(head)) {
            first = head->next;
            list_move_tail(first, head);
        }
    }

        显示判断链表不为空的时候,让链表的首节点放到尾节点。

    8、判断链表是否只有一个的节点(首节点)

    /**
     * list_is_singular - tests whether a list has just one entry.
     * @head: the list to test.
     */
    static inline int list_is_singular(const struct list_head *head)
    {
        return !list_empty(head) && (head->next == head->prev);
    }

        当链表只有一个节点的时候,也就是存在一个头结点和首节点,所以这个时候头结点的头指针和尾指针都是指向首节点的。

    9、链表的遍历

    #define list_entry(ptr, type, member) 
        container_of(ptr, type, member)

    type :结构体的类型

    member:结构体的成员变量

    ptr:返回结构体的起始的地址,我估计这个点应该是链表的头结点的地址


    #define list_first_entry(ptr, type, member) 
        list_entry((ptr)->next, type, member)

        返回结构体的初始地址的下一个节点的初始地址(我估计应该是链表的首节点的地址)。

        上面的介绍,已经可以基本对内核有了基本的认识。

    三、内核链表的使用

        内核链表提供的都是纯链表,而对于链表的数据类型是通过自己灵活指定的,是将链表的结构整个内嵌到链表的结构体里面。

    struct
    {
        int goal;
        int id;
        struct list_head head;
    }

        goal和 id 是数据,而 head 在是链表的指针的结构;而自己可以灵活去设置自己的数据区域。

    因为单链表的操作的不便(一旦指针指向一个节点,就无法返回来,必须重新进行循环),所以就引入了双向链表。

        对于链表的操作自己编写的话过于麻烦,而Linux内核提供了对应的API,可以直接调用方便使用:D:source insightlinux2.6.35.7android-kernel-samsung-devincludelinux 的 list.h。

    0、链表节点的指针

    struct list_head

    {

    struct list_head *next, *prev;

    };

        链表结构体的指针有两个:next 指向下一个节点,prev 指向上一个节点。

    1、链表头结点的初始化

    (1)定义且初始化

    #define LIST_HEAD_INIT(name) { &(name), &(name) }

     

    #define LIST_HEAD(name)

    struct list_head name = LIST_HEAD_INIT(name)

        链表头结点定义的时候且完成初始化,将上面的宏进行进行展开:

    #define LIST_HEAD(name)

    struct list_head name = { &(name), &(name) }

        是将链表的头结点的两个指针分别都指向了自己,从而完成链表头结点的初始化。

    (2)先定义后完成初始化

    static inline void INIT_LIST_HEAD(struct list_head *list)

    {

    list->next = list;

    list->prev = list;

    }

        对于一个已经完成链表头节点初始化,那么对这个链表头则是调用这个函数来完成初始化。这里函数实现链表头节点的初始化与上面宏完成初始化是一样的,差别无非是定义且初始化,一个是先定义头结点后完成初始化。

  • 相关阅读:
    使用分析函数进行行列转换
    SQL模糊查询
    Web服務器的配置方法
    oracle基礎知識2
    oracle基礎知識9
    在客户端脚本中获取Session的方法
    推荐litianping的几篇文章,包括owc统计图,rss技术,项目常用类,petshop架构分析
    Asp.net生成工作流、审批流的解决方案(asp.net workflow svg)
    DiscuzNT 1.0正式版推出了
    web.config中的特殊字符串xml中的非法字符串
  • 原文地址:https://www.cnblogs.com/qxj511/p/5001842.html
Copyright © 2011-2022 走看看