封装的通用链表(list.c/list.h/test_list.c)

#ifndef LIST_H
#define LIST_H#include <stdio.h>
#include <stdbool.h>//	通用链表节点
typedef struct ListNode
{void* ptr;struct ListNode* prev;struct ListNode* next;
}ListNode;//	通用链表结构
typedef struct List
{ListNode* head;size_t size;
}List;//	创建链表
List* create_list(void);//	追加
void add_list(List* list,void* ptr);//	插入
bool insert_list(List* list,int index,void* ptr);//	按位置删除
bool delete_index_list(List* list,int index);typedef int (*fp)(const void*,const void*);//	按值删除 ?
bool delete_value_list(List* list,void* ptr,fp cmp);//	查询	?
void* query_list(List* list,void* ptr,fp cmp);//	访问
void* access_list(List* list,int index);//	排序	?
void sort_list(List* list,fp cmp);//	清空
void clear_list(List* list);//	销毁
void destroy_list(List* list);//	遍历
void show_list(List* list,void (*show)(void*));#endif//LIST_H
#include <stdlib.h>
#include "list.h"//	创建节点
static ListNode* create_node(void* ptr)
{ListNode* node = malloc(sizeof(ListNode));node->ptr = ptr;node->next = node;node->prev = node;return node;
}//	在两个节点之间插入新节点
static void _add_list(ListNode* p,ListNode* n,void* ptr)
{ListNode* node = create_node(ptr);p->next = node;n->prev = node;node->prev = p;node->next = n;
}//	删除节点
static void _del_list(ListNode* node)
{node->prev->next = node->next;node->next->prev = node->prev;free(node->ptr);//void* ptr = node->ptr;free(node);
//	return ptr;
}//	根据位置访问节点
static ListNode* _index_list(List* list,int index)
{if(0 > index || index >= list->size) return NULL;if(index < list->size/2){ListNode* node = list->head->next;while(index--) node = node->next;return node;}else{ListNode* node = list->head->prev;while(++index < list->size) node = node->prev;return node;}
}//	创建链表
List* create_list(void)
{List* list = malloc(sizeof(List));list->head = create_node(NULL);list->size = 0;return list;
}//	在末尾追加
void add_list(List* list,void* ptr)
{_add_list(list->head->prev,list->head,ptr);list->size++;
}//	插入
bool insert_list(List* list,int index,void* ptr)
{ListNode* node = _index_list(list,index);if(NULL == node) return false;_add_list(node->prev,node,ptr);list->size++;return true;
}//	按位置删除
bool delete_index_list(List* list,int index)
{ListNode* node = _index_list(list,index);if(NULL == node) return false;_del_list(node);list->size--;return true;}//	按值删除 ?
bool delete_value_list(List* list,void* ptr,fp cmp)
{for(ListNode* n=list->head->next; list->head!=n; n=n->next){//	if(n->ptr == ptr) 无法进行直接比较 //	需要通过回调函数让调用者提供值比较的方法if(0 == cmp(n->ptr,ptr)){_del_list(n);list->size--;return true;}}return false;
}//	查询
void* query_list(List* list,void* ptr,fp cmp)
{for(ListNode* n=list->head->next; list->head!=n; n=n->next){if(0 == cmp(ptr,n->ptr)){return n->ptr;}}return NULL;
}//	访问
void* access_list(List* list,int index)
{ListNode* node = _index_list(list,index);if(NULL == node) return NULL;return node->ptr;
}//	排序
void sort_list(List* list,fp cmp)
{for(ListNode* i=list->head->next; list->head->prev!=i; i=i->next){ListNode* min = i;for(ListNode* j=i->next; list->head!=j; j=j->next){if(0 > cmp(j->ptr,min->ptr))min = j;}if(min != i){//	不需要交换内存,只需交换指针指向即可void* tmp = i->ptr;i->ptr = min->ptr;min->ptr = tmp;	}}
}//	清空
void clear_list(List* list)
{while(list->size) delete_index_list(list,0);
}//	销毁
void destroy_list(List* list)
{clear_list(list);free(list->head);free(list);
}//	遍历
void show_list(List* list,void (*show)(void*))
{for(ListNode* n=list->head->next; list->head!=n; n=n->next){show(n->ptr);}
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"//	以下都是用户写的代码
typedef struct Student
{char name[20];char sex;int id;
}Student;void show_stu(void* ptr)
{Student* stu = ptr;printf("%s %c %d\n",stu->name,stu->sex,stu->id);
}//	比较的回调函数
int cmp_name(const void* p1,const void* p2)
{const Student *s1 = p1,*s2 = p2; return strcmp(s1->name,s2->name);
}int cmp_id(const void* p1,const void* p2)
{const Student *s1 = p1,*s2 = p2; return s1->id - s2->id;
}int main(int argc,const char* argv[])
{//	创建链表List* list = create_list();Student* stu = NULL;for(int i=0; i<10; i++){stu = malloc(sizeof(Student));sprintf(stu->name,"hehe%d",i);stu->sex = i%2 ? 'w':'m';stu->id = rand()%1000;add_list(list,stu);}stu = malloc(sizeof(Student));sprintf(stu->name,"xixi");stu->sex ='w';stu->id = 2001;insert_list(list,2,stu);delete_index_list(list,7);Student stu1 = {"hehe4",'w',1010};delete_value_list(list,&stu1,cmp_name);delete_value_list(list,&stu1,cmp_id);sort_list(list,cmp_id);show_list(list,show_stu);destroy_list(list);
}

Linux内核链表虽然设计很巧妙,但是不利于初学者使用,另一种通用的设计思路是借助void*的兼容性,来设计一种链表,称为通用链表,这种链表还需要借助回调函数。

//  定义了一个函数指针变量
返回值 (*函数指针变量名)(参数列表);void (*funcp)(int num1,int num2);
//  该函数指针的类型是
返回值 (*)(参数列表);  void (*)(int,int);
//  函数指针类型重定义
typedef 返回值 (*重定义后的类型名)(参数列表);typedef void (*fp)(int,int);fp 就是 void (*)(int,int)这个函数指针类型 可以用来定义该类型的函数指针变量fp p;   //  p就是函数指针变量
​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/47677.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web开发:ASP.NET CORE前后端交互之AJAX(含基础Demo)

目录 一、后端 二、前端 三、代码位置 四、实现效果 五、关键的点 1.后端传输给前端&#xff1a; 2.前端传输给后端 一、后端 using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.Rendering; using WebAppl…

【Android】Intent基础用法及作用

文章目录 使用Intent在活动中穿梭组成显式Intent隐式Intent显式与隐式区别作用 活动间传递数据向下一个活动传递数据返回数据给上一个活动 使用Intent在活动中穿梭 Intent&#xff08;意图&#xff09;是一种重要的消息传递对象&#xff0c;用于在不同组件&#xff08;如活动&…

数据挖掘新技能:Python爬虫编程指南

Python爬虫的优势 Python之所以成为数据爬取的首选语言&#xff0c;主要得益于其丰富的库和框架支持。以下是一些常用的库&#xff1a; Requests&#xff1a;用于发送HTTP请求&#xff0c;简单易用&#xff0c;是Python爬虫的基础库。BeautifulSoup&#xff1a;用于解析HTML文…

StarRocks on AWS Graviton3,实现 50% 以上性价比提升

在数据时代&#xff0c;企业拥有前所未有的大量数据资产&#xff0c;但如何从海量数据中发掘价值成为挑战。数据分析凭借强大的分析能力&#xff0c;可从不同维度挖掘数据中蕴含的见解和规律&#xff0c;为企业战略决策提供依据。数据分析在营销、风险管控、产品优化等领域发挥…

使用 spring MVC 简单的案例 (1)计算器

一、计算器 1.1前端代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> …

签名优化:请求数据类型不是`application/json`,将只对随机数进行签名计算,例如文件上传接口。

文章目录 I 签名进行请求数据类型类型判断1.1 常见的ContentType1.2 签名切面处理1.3 文件上传案例1.4 处理接口信息背景: 文件上传接口的请求数据类型通常为multipart/form-data,方便携带文本域和使用接口文档进行调试。 如果携带JSON数据,不方便调试接口。 前端数据也要特…

Github 2024-07-18 开源项目日报Top10

根据Github Trendings的统计,今日(2024-07-18统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量TypeScript项目3非开发语言项目3Jupyter Notebook项目2Python项目2JavaScript项目1C#项目1Rust项目1MDX项目1C++项目1项目化学习 创建周期:253…

Python数据获取(网页视频、音频版)

爬取数据&#xff0c;上一章有介绍&#xff0c;不懂流言私信或者评论交流即可&#xff0c; 在Python中编写爬虫通常涉及以下几个步骤&#xff1a; 发送HTTP请求&#xff1a;使用requests库向目标网站发送请求。解析网页内容&#xff1a;使用BeautifulSoup从HTML中解析出需要的…

JAVA中的File类,文件流,字节流和字符流超级详解(1.8万字干货 )

1.File类 在Java中&#xff0c;File 类是 java.io 包中的一个重要类&#xff0c;它提供了与文件或目录路径名相关的一系列操作。File 类可以用来创建、删除、重命名文件和目录&#xff0c;也可以用来获取文件或目录的属性&#xff0c;比如大小、最后修改时间等。 File类的常用方…

10 - FFmpeg - 重采样 - SoftwareResampleExample

一. 音频帧概率详解&#xff1a; 1. 概念 1&#xff09;采样率&#xff08;Sample Rate&#xff09;&#xff1a;每秒从连续信号中提取并组成离散信号的采样个数&#xff0c;它用赫兹&#xff08;Hz&#xff09;来表示。 一般音乐CD的采样率是 44100Hz&#xff0c;所以视频…

Mac Electron 应用如何进行签名(signature)和公证(notarization)?

最近很多客户反映&#xff0c;从官网下载的Mac Electron应用打不开&#xff0c;直接报病毒&#xff0c;类似于这种&#xff1a; 这是因为在MacOS 10.14.5之后&#xff0c;如果应用没有在苹果官方平台进行公证notarization(我们可以理解为安装包需要审核&#xff0c;来判断是否存…

spring 同类方法调用事务失效解决办法

可以使用AopContext.currentProxy()获取到当前类的代理对象&#xff0c;然后再用代理对象进行调用本类中的方法 如下 f1 和f2 属于同一个类 public voidf1() {((本类名)AopContext.currentProxy()).f2();}Transactionalpublic f2() {} AopContext.currentProxy()方法的使用场景…

Python(字典)

字典根据一个信息查找另外一个信息&#xff0c;也是可变数据类型&#xff0c;底层元素是无序的&#xff0c;第一个添加的元素&#xff0c;地址不一定在第一位&#xff0c;键只能有一个不能重复&#xff0c;但是值可以重复&#xff0c;字典当中的键要求是不可以变的数据类型&…

第6章 单片机的定时器/计数器

6.1 定时/计数器的结构与工作原理 6.2 定时器的控制 6.3 定时/计数器的工作方式 6.4 定时/计数器的编程和应用 6.1 定时/计数器的结构与工作原理 6.1.1 定时/计数器的基本原理 纯软件定时/计数方法&#xff1a; 定时——空循环预定周次&#xff0c;等待预定时间 计数—…

【Qt】之【Bug】error:C1083 无法打开包括文件

背景 a.cpp引用b.h正常&#xff0c;但是a.h引用b.h就报 “无法打开包括文件”的错误 分析 查看“编译输出”&#xff0c;显示不是a.h引起的错误&#xff0c;而是C插件&#xff0c; 查看后发现&#xff0c;C插件引用了a所在插件pro&#xff0c;但是没有引用a依赖的b所在的插件…

Axure中继器进阶指南:打造专业级交互

中继器进阶篇 前言 经过了基础篇的学习,我们已经掌握了中继器的基本操作,接下来来解锁中继器的进阶操作。 1. 修改删除指定行 首先拖入中继器,加上【修改】 【删除】的按钮,然后给修改按钮添加单击事件选择【更新行】。 这里可以看到我们在中继器内部添加的事件,在编…

IDEA关联数据库

《IDEA破解、配置、使用技巧与实战教程》系列文章目录 第一章 IDEA破解与HelloWorld的实战编写 第二章 IDEA的详细设置 第三章 IDEA的工程与模块管理 第四章 IDEA的常见代码模板的使用 第五章 IDEA中常用的快捷键 第六章 IDEA的断点调试&#xff08;Debug&#xff09; 第七章 …

2024-07-16 Unity插件 Odin Inspector7 —— Number Attributes

文章目录 1 说明2 Number 特性2.1 MaxValue / MinValue2.2 MinMaxSlider2.3 ProgressBar2.4 PropertyRange2.5 Unit2.6 Wrap 1 说明 ​ 本文介绍 Odin Inspector 插件中有关 Number 特性的使用方法。 2 Number 特性 2.1 MaxValue / MinValue 在 Inspector 窗口中对象能够被设…

LLM 构建Data Multi-Agents 赋能数据分析平台的实践之④:数据分析之三(数据展示)

概述 在先前探讨的文章中&#xff0c;我们构建了一个全面的数据测试体系&#xff0c;该体系遵循“数据获取—数据治理—数据分析”的流程。如何高效地构建数据可视化看板&#xff0c;以直观展现分析结果&#xff0c;正逐渐成为利用新兴技术提升效能的关键领域。伴随业务拓展、数…

java json 实体互转 null现象

结论 相对于json字符串转为实体&#xff0c;再转回为json字符串&#xff0c;更接近高保真的是 “com.google.gson.Gson {}”, new GsonBuilder().create().toJson(bo1)); 和 “com.alibaba.fastjson.JSON {}”, JSON.toJSONString(bo1)); 代码 BusinessInsertBO bo Business…