一、基本知识
内核链表:可以给里面的每一个数据都可以存储不同的数据的类型,结构体成员里面(将结点放在数据中)
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;
}
标签:klink,基本知识,结点,链表,pnode,phead,内核,NULL
From: https://blog.csdn.net/weixin_63722559/article/details/141927994