欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 艺术 > 封装的通用链表(list.c/list.h/test_list.c)

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

2024/10/24 2:00:42 来源:https://blog.csdn.net/weixin_65029285/article/details/140531517  浏览:    关键词:封装的通用链表(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就是函数指针变量
​

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com