内核链表基本知识

一、基本知识

内核链表:可以给里面的每一个数据都可以存储不同的数据的类型,结构体成员里面(将结点放在数据中)

1、实质

内核链表:有头的、双向循环链表

2、注意

  • 结构体第一个成员即为结构体的首地址
  • 该链表里面的数据主要由两部分构成 前驱结点,后继结点,该节点作为数据放在数据中

3、怎么通过链表找到对应的数据结点

  • 内存链表提供了,offsetof (获得的是结构体成员到结构体开头的偏移量)contianer_of(两个宏)(通过偏移量获取结构体首地址)
  • 结构体指针-偏移量就获得了位置

4、循环链表

第一个指针的前驱结点指向最后一个结点,最后一个结点的尾指针指向第一个结点

二、内联链表的特点

1、可扩展性

内核代码都没有写成死代码,对于后续的要求可以进行灵活改变、方便修改和追加

2、封装性

函数的接口的封装性比较好,属于程序与程序之间的高内聚低耦合的特点。

3、数据类型多变

在这里是将结点作为数据插入,故可以灵活的拓展数据的数据结构,也就是说常用的带数据域的链表降低了链表的通用性,不容易扩展。linux内核定义的链表结构不带数据域,只需要两个指针完成链表的操作。将链表节点加入数据结构,具备非常高的扩展性,通用性。

4、遍历效率高

因为一个结点都包含着前一个结点,也就是说从任一一个结点都可以进行遍历,遍历的效率比较高。

三、链表的操作

3.1、创建结点

Klink_t *create_link()
{
    Klink_t *pklink = malloc(sizeof(Klink_t));
    if(NULL == pklink)
    {
        perror("fail malloc");
        return NULL;
    }
    pklink->phead = NULL;
    pklink->clen = 0;
    pthread_mutex_init(&(pklink->mutex),NULL);
    return pklink;
}

3.2、头插

int push_klink_head(Klink_t *klink,void *p)
{
    KNode_t *knode = (KNode_t *)p;
    knode->ppre = NULL;
    knode->pnext = NULL;
    knode->pnext = klink->phead;
    if(klink->phead != NULL)
    {//可能没有前驱结点
        klink->phead->ppre = knode;
    }
    klink->phead = knode;
    klink->clen++;
    return 0;
}

3.3、尾插

int push_klink_tail(Klink_t *klink,void *p)
{
    KNode_t *knode = (KNode_t *)p;
    knode->ppre = NULL;
    knode->pnext = NULL;
    KNode_t *q = klink->phead;
    if(klink->phead == NULL)
    {
        push_klink_head(klink,knode);
    }
    while(q->pnext != NULL)
    {
        q = q->pnext;
    }
    q->pnext = knode;
    knode->ppre = q;  
    klink->clen++;
   

3.4、遍历

void klink_for_each(Klink_t *klink,void (*func)(void *))
{
    KNode_t *pnode = klink->phead;
    while(pnode != NULL)
    {
        func(pnode);
        pnode = pnode->pnext;
    }
    printf("\n");
}

3.5、查找

KNode_t *find_link(Klink_t *klink,void *t,CMP_t func)
{
    KNode_t *pnode = klink->phead;
    while(pnode != NULL)
    {
        if(func(t,pnode))
        {
            return pnode;
        }
        pnode = pnode->pnext;
    }
    return NULL;
}

3.6、头删

int pop_klink_head(Klink_t *klink)
{ 
    if(klink->phead == NULL)
    {
        return 0;
    }
    KNode_t *pnode = klink->phead;
    klink->phead = pnode->pnext;
    if(klink->phead != NULL)
    {
        klink->phead->ppre = NULL;
    }
    free(pnode);
    klink->clen--;
    return 1;
}

3.7、销毁

int pop_klink_head(Klink_t *klink)
{ 
    if(klink->phead == NULL)
    {
        return 0;
    }
    KNode_t *pnode = klink->phead;
    klink->phead = pnode->pnext;
    if(klink->phead != NULL)
    {
        klink->phead->ppre = NULL;
    }
    free(pnode);
    klink->clen--;
    return 1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值