==================内核链表==================
内核网站:https://www.kernel.org/ //可以自己下载 想要的内核
内核链表路径:/home/gec/Download/linux-2.6.35.7-gec/include/linux/list.h
内核链表与 其他链表的区别?
其实样子差不多 ,而内核链表的存在就是为了,能够兼容多种结构体而做的链表。
我们先来看看两个链表的结构体
这是 内核链表:
typedef struct node
{
int data;
struct list_head list;
}listnode,*kernel_list;
内核链表是 在结构体里面 设置一个结构体来存储链表
//这是 双向链表 :
typedef struct node
{
int data;
struct node *prev;
struct node *next;
}listnode,*double_list;
双向链表是 在结构体里面 直接放置 头尾节点;
内核链表的特点:
内核结构元素不与特定类型结构相关,任何结构体都可通过内核的添加成为链表中的节点。
list_add(struct list_head *new, struct list_head *head)实现将节点插入到节点head的后面
list_add_tail(struct list_head *new, struct list_head *head)将节点new插入到节点head的前面
list_del(struct list_head *entry)节点删除
list_replace(struct list_head *old,struct list_head *new)使用新节点替代旧节点old
list_replace_init(struct list_head *old,struct list_head *new)使用新节点替代旧节点old,且将旧节点重新初始化
list_move(struct list_head *list, struct list_head *head)是将list移动到head的后面,小结构体指针
list_move_tail(struct list_head *list,struct list_head *head)是将list移动到head的前面,小结构体
list_empty(const struct list_head *head)//判断head节点是否为NULL
list_for_each(pos, head)迭代遍历链表,要调用list_entry()得到大结构的指针
list_for_each_entry(pos, head, member)迭代遍历链表,得到大结构的指针
内核链表:
节点设计:
typedef struct node //大结构体
{
int data;
struct list_head list; //小结构体
}listnode,*kernel_list;
//初始化空链表
kernel_list list_init(void)
{
kernel_list list = malloc(sizeof(listnode));
if(list != NULL)
{
INIT_LIST_HEAD(&list->list);
return list;
}
return NULL;
}
//创建节点
kernel_list new_node(int data)
{
kernel_list new = malloc(sizeof(listnode)); //大结构体
if(new != NULL)
{
new->data = data;
new->list.next = NULL;
new->list.prev = NULL;
}
return new;
}
//查找节点
kernel_list find_node(int data,kernel_list head)
{
if(list_empty(&head->list))
return NULL;
kernel_list pos;
list_for_each_entry(pos,&head->list, list)//pos指针的是每个大结构体指针,迭代遍历链表,得到大结构的指针
{
if(pos->data == data)
return pos;
}
return NULL;
}
//显示链表
void show(kernel_list kerlist)
{
kernel_list pos;
list_for_each_entry(pos,&kerlist->list,list)//pos指针的是每个大结构体指针,迭代遍历链表,得到大结构的指针
{
printf("%d\t",pos->data);
}
printf("\n");
}
练习:内核链表的移动操作,当输入一个正值时为插入操作;当输入一个负数时,删除对应的正数;输入两个数时,进行移动操作
移动操作步骤:
1、找到两个移动的节点的地址(大结构);
2、调用内核移动函数;
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
int g_i = 0;
int g_j = 0;
typedef struct node
{
int data;
struct list_head list;
}listnode,*kernel_list;
//初始化空链表
kernel_list list_init(void)
{
kernel_list list = malloc(sizeof(listnode));
if(list != NULL)
{
INIT_LIST_HEAD(&list->list);
return list;
}
return NULL;
}
//创建节点
kernel_list new_node(int data)
{
kernel_list new = malloc(sizeof(listnode)); //大结构体
if(new != NULL)
{
new->data = data;
new->list.next = NULL;
new->list.prev = NULL;
}
return new;
}
//遍历内核链表
void show(kernel_list kerlist)
{
kernel_list pos;
list_for_each_entry(pos,&kerlist->list,list)//pos指针的是每个大结构体指针,迭代遍历链表,得到大结构的指针
{
printf("%d\t",pos->data);
}
printf("\n");
}
//查找数据对应的 大节点
kernel_list find_node(int data,kernel_list head)
{
if(list_empty(&head->list))
return NULL;
kernel_list pos;
list_for_each_entry(pos,&head->list, list)//pos指针的是每个大结构体指针,迭代遍历链表,得到大结构的指针
{
if(pos->data == data)
return pos;
}
return NULL;
}
//获取输入端的数据
int get_number(char *buff)
{
int count = 0;
char *p;
p = strtok(buff," ");
count++;
g_i = atoi(p);
p = strtok(NULL," ");
if(p != NULL)
{
g_j = atoi(p);
count++;
}
return count;
}
int main(void)
{
kernel_list kerlist = list_init();
kernel_list new,tmp;
char arr[20];
int ret;
while(1)
{
fgets(arr,20,stdin);
ret = get_number(arr);
if(ret == 1)
{
//插入操作
if(g_i>0)
{
new = new_node(g_i);
list_add(&new->list, &kerlist->list);
show(kerlist);
}
//删除操作
if(g_i<0)
{
tmp = find_node(-g_i,kerlist);//得到大结构体的指针;
list_del(&tmp->list);//传入小结构指针;
free(tmp);
show(kerlist);
}
}
if(ret ==2)
{
new = find_node(g_i,kerlist);
tmp = find_node(g_j,kerlist);
list_move(&new->list,&tmp->list);
show(kerlist);
}
}
return 0;
}