Linux 内核开发之单链表的增删查改详解

什么是链表

  • 物理存储单元上非连续、非顺序的线性数据结构

用图形流程来理解(单链表)


链表的类型

链表差异

那我们为了方便起见,此次的文章就以单链表来学习和理解

为什么要学习链表?

  1. 内核开发离不开链表
  2. 驱动开发中的实际应用
  3. 字符和网络 设备管理离不开链表

单链表创建与应用(最后附源码)

重要参数

  1. 定义单链表节点

  2. 创建一个节点

  3. 创建一个包含多个节点的链表

    函数调用:

    创建结果:

  4. 在链表头部插入节点

    函数调用:

  5. 在链表尾部插入节点

    函数调用:

  6. 删除链表头部节点

    函数调用:

  7. 删除链表尾部节点

    函数调用:

  8. 删除指定值(结构体中data的值)的节点(第一个匹配的)

    函数调用:

  9. 删除指定位置的节点,value 代表删除节点的位置顺序个数

    函数调用:

  10. 按data值查找节点,返回位置

    函数调用:

  11. 按位置查找节点,返回值

    函数调用

  12. 修改指定位置的节点数据

    函数调用:

  13. 修改第一个匹配值的节点数据

    函数调用:

  14. 链表信息打印

源码

c 复制代码
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//定义单链表节点
struct node{
	int data;
	struct node *next;
};

//创建一个节点
struct node* create_node(int value) {
    // 1. 分配内存
    struct node *new_node = (struct node*)malloc(sizeof(struct node));
    
    // 2. 检查内存是否分配成功
    if (new_node == NULL) {
        printf("内存分配失败!\n");
        return NULL;
    }
    
    // 3. 设置节点数据
    new_node->data = value;
    new_node->next = NULL;  // 重要:新节点默认不连接任何节点
    
    printf("创建节点成功,数据 = %d,地址 = %p\n", new_node->data, new_node);
    return new_node;
}

// 创建一个包含多个节点的链表
//value:节点值
//size:节点大小
//return:返回创建的链表
struct node* create_list_node(int *value,int size){
	// 头指针:指向链表的第一个节点
    // 初始化为NULL,表示空链表
    struct node *head = NULL;//头结点
    struct node *tail = NULL;//传值的中间节点

	
	for(int i = 0 ; i < size ; i++)//创建节点并连接
		{
		struct node *new_node = create_node(value[i]);
			if( i == 0)//当为第一个节点时,赋值给头指针
				{
					head = new_node ;//给头指针赋值
					tail = head ;//指向当前链表最后一个,并且当前为第一个节点的地址
				}
			else
				{
					tail->next = new_node ;//将新的节点挂载到链表的最后一个节点的指向next域
					tail = tail->next ;//继续指向当前链表最后一个,并且当前为下一个节点的地址
				}
			
		}
	return head ;//返回所创建的链表头指针

}


//删除整个包含多个节点的链表
 void delete_list_node(struct node *head){
	struct node *current_head = head;

	while(current_head != NULL)
		{
			struct node *tmp_value = current_head;//定义变量保存当前指针值,以便后续释放
			current_head = current_head->next ;
			printf("释放地址:%p\n",tmp_value);
			free(tmp_value);
		}
	printf("删除当前链表结束\n");


}

 // 增操作:添加节点 
 // 1. 在链表头部插入节点
 //head:要插入的链表
 //value:插入的data值
 //return:返回创建的链表
struct node *insert_node_by_head(struct node *head , int value ){

	struct node *new_node = (struct node *)malloc(sizeof(struct node));//创建新的node节点

	if(new_node == NULL)
		return NULL;

	new_node->data = value ;//新节点赋值
	new_node->next = NULL ;
	
	struct node * tmp_head = head ;//将头指针保存
	head = new_node ;//将新的节点赋值给头指针
	new_node->next = tmp_head ;//将旧头指针指向新节点的next域

	return head ;

}
// 2. 在链表尾部插入节点
//head:要插入的链表
//value:插入的data值
//return:返回创建的链表
struct node *insert_node_by_tail(struct node *head , int value ){

	struct node *new_node = (struct node *)malloc(sizeof(struct node));//创建新的node节点
	struct node *tmp_node = head ;

	new_node->data = value ;//新节点赋值
	new_node->next = NULL ;

	//从头结点轮训到末尾节点
	while(tmp_node->next != NULL)
		{
			tmp_node = tmp_node->next ; 
		}
	tmp_node->next  = new_node; //把新节点给到最后一个节点的空next域
	return head ;

}

// ============ 删操作:删除节点 ============

// 1. 删除链表头部节点
//head:插入的链表
//return:返回删除后的链表
struct node *delete_node_by_head(struct node *head){

	struct node *tmp_node = head ;//保存头节点,以便方便释放

	if(tmp_node == NULL)
		return NULL;


	head = head->next ; 
	free(tmp_node);

	return head ;

}

// 2. 删除链表尾部节点
//head:插入的链表
//return:返回删除后的链表
struct node *delete_node_by_tail(struct node *head){

	struct node *current_node = head ;//保存头节点,以便方便释放
	struct node *tmp_node = NULL ;

	if(current_node == NULL)
		return NULL;

	while(current_node->next->next != NULL)//循环到倒数第二个节点
		{
			current_node = current_node->next ;
		}
	printf("当前链表节点为:%d",current_node->data);

	tmp_node = current_node ;
	
	current_node = current_node->next;
	free(current_node);
	tmp_node->next = NULL ;
	

	return head ;

}

//删除指定值(结构体中data的值)的节点(第一个匹配的)
//head:要插入的链表
//value:插入的data值
//return:返回删除后的链表
struct node *delete_node_by_data(struct node *head,int value){

	struct node * current_node = head ;
	struct node * tmp_node = NULL ;

	if(head->data == value)//第一个节点是否为删除节点
		{
			head= head->next ;
			free(current_node);
			return head ; 
		}

	while(current_node->next->data != value)
		{
			current_node = current_node->next ; 
		}
	printf("当前节点为:%d\n",current_node->data);
	//找到了data相吻合数据
	tmp_node = current_node->next;
	current_node->next = current_node->next->next ;
	free(tmp_node);

	return head ;
}

//删除指定位置的节点,value 代表删除节点的位置顺序个数
//head:要插入的链表
//value:插入的data值
//return:返回删除后的链表
struct node *delete_node_by_local(struct node *head,int value){

	struct node * current_node = head ;
	struct node * tmp_node = NULL ;
	int tmp_value = value ;

	if(tmp_value == 1)//第一个节点是否为删除节点
		{
			head= head->next ;
			free(current_node);
			return head ; 
		}

	tmp_value -= 2;//当位置个数大于1时候,比如2:删除第二个数据,只需要执行一次指针跳跃,所以进行减一,并且需要在到删除节点的前一个节点
	printf("tmp_value为:%d\n",tmp_value);
	while(tmp_value--)
		{
			current_node = current_node->next ; 
		}
	printf("当前节点为:%d\n",current_node->data);
	//找到了data相吻合数据
	tmp_node = current_node->next;
	current_node->next = current_node->next->next ;
	free(tmp_node);

	return head ;
}


// ============ 查操作:查找节点 ============

// 1. 按值查找节点,返回位置
//head:要插入的链表
//value:插入的data值
//return:返回查找的位置
int find_node_by_data(struct node *head,int value){

	struct node * current = head ;
	int return_value = 1  ;//因为最小值为:1

	while(current->data != value)
		{
			current = current->next ;
			return_value++;
		}
	printf("找到了节点,在第:%d个\n",return_value);
	return return_value ;
}
// 2. 按位置查找节点,返回值
//head:要插入的链表
//local:插入的data值
//return:返回查找的位置
int find_data_by_local(struct node *head,int local){

	struct node * current = head ;
	int tmp_value = local  ;

	tmp_value -= 1 ;//需要减一处理
	while(tmp_value--)
		{
			current = current->next ;
		}
	printf("current->data:%d\n",current->data);
	return current->data ;
}

// ============ 改操作:修改节点数据 ============
// 1. 修改指定位置的节点数据
//head:要插入的链表
//local:需要修改的位置值
//value:修改的的data值
void node_list_change_by_local(struct node * head , int local , int value){

	struct node * current = head ;

	local-- ; 

	while(local--)
		{
			current = current->next;
		}
	printf("当前需要修改的节点值为:%d\n",current->data);
	current->data = value ; 
	printf("修改后的节点值为:%d\n",current->data);


}

// 2. 修改第一个匹配值的节点数据
//head:要插入的链表
//data:需要修改的位置值
//value:修改的的data值
void node_list_change_by_data(struct node * head , int data , int value){

	struct node * current = head ;


	while(current->data != data)
		{
			current = current->next;
		}
	printf("当前需要修改的节点值为:%d\n",current->data);
	current->data = value ; 
	printf("修改后的节点值为:%d\n",current->data);


}


//链表信息打印
void print_node_list(struct node *head) {
    printf("当前链表:");
    struct node *current = head;
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}


int main() {	

	int value[] = {1,2,3,4,5,6,7,8,9,10};//链表所要存的值与顺序
	printf("链表的大小为:%d,%d 值为:%d、%d、%d、%d、%d、%d\n",sizeof(value),sizeof(int),value[0],value[1],value[2],value[3],value[4],value[5]);
	struct node *head = NULL;//定义头结点指针
	int find_value = 0;
	
	head = create_list_node(value,sizeof(value)/sizeof(int));

	print_node_list(head);

//	head  =  insert_node_by_head(head,88);//链表前段插入节点
//
//	head  =  insert_node_by_head(head,77);//链表前段插入节点
//
//	head = insert_node_by_tail(head,99);//链表后段插入节点
//
//	head = insert_node_by_tail(head,100);//链表后段插入节点


//	head = delete_node_by_head(head);//链表前段删除节点

//	head = delete_node_by_tail(head);//链表后段删除节点
//	print_node_list(head);
                  
//	head = delete_node_by_data(head,9);
//	head = delete_node_by_local(head,5);

//	find_value = find_node_by_data(head,7);

//	find_value = find_data_by_local(head,8);

//	node_list_change_by_local(head,7,333);
//	node_list_change_by_data(head,10,333);

//	print_node_list(head);
    
//    delete_list_node(head);
    
    return 0;
}
复制代码
相关推荐
ValhallaCoder6 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
wdfk_prog7 小时前
[Linux]学习笔记系列 -- [drivers][input]input
linux·笔记·学习
盟接之桥7 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
忆~遂愿7 小时前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
湘-枫叶情缘7 小时前
1990:种下那棵不落叶的树-第6集 圆明园的对话
linux·系统架构
月挽清风8 小时前
代码随想录第十五天
数据结构·算法·leetcode
NEXT068 小时前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法
Fcy6488 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满8 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠9 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法