一、常规链表的缺陷:
第一:每一种节点都是特殊的,导致每一条链表都是特殊的,因此 每一种链表的增删查改也都是特殊的。注意:特殊的不具备有通用性
第二:当每一种节点处于变化的数据结构网络中时,节点指针无法指向稳定不变的节点。
比如:有一千多个节点,那么用常规的链表来插入就需要一千种插入函数。
二、常规链表和内核链表的区别:
1.一个包含数据域(常规链表),一个不包含数据域(内核链表)。
三、内核链表
内核链表的原理:
1.将链表结构抽象出来:去除节点中的具体数字,只保留表示逻辑的双向指针。形成一条只包含逻辑的“纯粹的链表”。
2.将此链表“寄宿”于具体数据的节点之中,使之贯穿于这些节点。
3.统一内核链表的操作接口
①初始化链表:INIT_LIST_HEAD()/LIST_HEAD_INIT()
②插入节点:list_add()/list_add_tail()
③删除节点:list_del()/list_del_init()
④移动节点:list_move()/list_move_tail()
⑤合并链表:list_splice()
⑥后向遍历:list_for_each()/list__for_each_safe()/list__for_each_entry()
⑦前向遍历:list_for_each_prev()/list__for_each_entry_prev()
⑧判断是否为空:list_empty()
⑨取得宿主节点指针:list_entry()
4.图形加深认识
5.下面通过内核链表的源码做一项练习:奇偶分离。
项目:
#include <stdio.h>
#include <stdlib.h>
#include "commonheader.h"
#include "list.h"
//一个具体的“大结构体”
struct node
{
int data;
//只包含链表逻辑的“小结构体”
struct list_head root;
};
//初始化
struct node *init_list(void)
{
struct node *head = malloc(sizeof(struct node)); //头节点
if(head != NULL)
{
INIT_LIST_HEAD(&head->root); //引用"list.h" 让 list 指向自己
}
//这里就是头指针指向一个空链表
}
//创建新的节点
struct node *new_node(int data)
{
struct node *new = calloc(1, sizeof(struct node));
if(new != NULL)
{
new->data = data;
}
return new;
}
//显示
void show(struct node *head)
{
struct list_head *pos; //小结构体的指针
struct node *p;
list_for_each(pos, &head->root) //这个在内核链表宏定义是一个for循环
{
p = list_entry(pos, struct node, root); //这个是从小结构体获得大结构体的指针
printf("%d\t", p->data);
}
printf("\n");
}
//奇偶排列
void rearrange(struct node *head)
{
struct list_head *pos, *tmp;
struct node *p;
int flag = 0;
list_for_each_prev(pos, &head->root) //不断的往前找
{
p = list_entry(pos, struct node, root);
if(p->data % 2 == 0 && flag != 0) // flag != 0 避免一开始就是偶数
{
list_move_tail(pos, &head->root); //将 p 指向的节点移动到头节点之前
pos = tmp; //如果是偶数 保存这个位置
}
else
{
tmp = pos; //如果是奇数 保存这个位置 防止出现死循环
}
flag = 1;
}
}
int main(int argc, char **argv)
{
struct node *head;
head = init_list();
//获得用户输入的数据
int n;
scanf("%d", &n);
int i;
for(i = 0; i <= n; i++)
{
struct node *new = new_node(i);
//注意:
//1. new 和 head 是指向大结构体的
//2.我们操作的是小结构体(也就是内核链表)
//3.所以要加上取地址符号 &
list_add_tail(&new->root, &head->root);
}
show(head);
rearrange(head);
show(head);
return 0;
}
运行结果: