首页 > 其他分享 >通用链表的封装

通用链表的封装

时间:2023-09-09 16:56:03浏览次数:34  
标签:node index 通用 List void list 链表 封装 ptr

通用链表

能够存储任意类型的数据到链表中,并提供对应的操作

万能指针 void*

C语言中任意类型的指针可以转换成void*类型

void*类型指针可以转换成任意类型指针

  • 节点:

void* ptr;  //  数据域

指针域;

  • 链表结构:

头指针

数量

  • 核心点:

1、void* 确保能存储任意类型数据

2、普通操作可参考双链表即可

2、通过回调模式来实现一些特殊操作,例如:遍历、按值操作、排序

  • list.h
#ifndef LIST_H
#define LIST_H

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

//    函数指针的类型重定义
typedef int (*CMP)(const void*,const void*);
typedef void (*SHOW)(const void*);
typedef void (*CHANGE)(void*,const void*);


//    通用链表
//    节点设计
typedef struct Node
{
    void* ptr;
    struct Node* prev;
    struct Node* next;
}Node;

//    设计通用链表结构
typedef struct List
{
    Node* head;
    size_t size;
}List;

//    创建链表
List* create_list(void);
//    头添加
void add_head_list(List* list,const void* ptr);
//    尾添加
void add_tail_list(List* list,const void* ptr);
//    插入
bool insert_list(List* list,size_t index,const void* ptr);
//    按位置删除
void* del_index_list(List* list,size_t index);
//    按值删除
void* del_value_list(List* list,const void* ptr,CMP cmp);
//    按位置修改
bool mod_index_list(List* list,size_t index,const void* data,CHANGE change);
//    按值修改
bool mod_value_list(List* list,const void* old,CMP cmp,const void* data,CHANGE change);
//    访问
void* access_list(List* list,size_t index);
//    查询
void* query_list(List* list,const void* data,CMP cmp);
//    数量
size_t size_list(List* list);
//    排序
void sort_list(List* list,CMP cmp);
//    清空
void clear_list(List* list);    //    节点、数据都删
//    销毁
void destroy_list(List* list);
//    遍历
void show_list(List* list,SHOW show);

#endif//LIST_H
  • list.c

#include "list.h"

//	创建节点
static Node* create_node(const void* ptr)
{
	Node* node = malloc(sizeof(Node));
	node->ptr = (void*)ptr;
	node->prev = node;
	node->next = node;
	return node;
}

//	两个节点之间添加一个新节点
static void _add_node(Node* p,Node* n,const void* ptr)
{
	Node* node = create_node(ptr);
	p->next = node;
	n->prev = node;
	node->prev = p;
	node->next = n;
}
//	删除节点
static void _del_node(Node* node)
{
	node->prev->next = node->next;
	node->next->prev = node->prev;
	free(node);
}
//	根据位置访问节点
static Node* _index_list(List* list,size_t index)
{
	if(index >= list->size) return NULL;
	if(index < list->size/2)
	{
		Node* n = list->head->next;
		while(index--) n = n->next;
		return n;
	}
	else
	{
		Node* n = list->head->prev;
		while(++index < list->size) n = n->prev;
		return n;
	}
}

//	创建链表
List* create_list(void)
{
	List* list = malloc(sizeof(List));
	list->head = create_node(NULL);	//	带头节点
	list->size = 0;
	return list;
}

//	头添加
void add_head_list(List* list,const void* ptr)
{
	_add_node(list->head,list->head->next,ptr);
	list->size++;
}

//	尾添加
void add_tail_list(List* list,const void* ptr)
{
	_add_node(list->head->prev,list->head,ptr);
	list->size++;
}

//	插入
bool insert_list(List* list,size_t index,const void* ptr)
{
	Node* node = _index_list(list,index);	
	if(NULL == node) return false;

	_add_node(node->prev,node,ptr);
	list->size++;
	return true;
}

//	按位置删除
void* del_index_list(List* list,size_t index)
{
	Node* node = _index_list(list,index);	
	if(NULL == node) return NULL;

	void* ptr = node->ptr;
	_del_node(node);
	list->size--;
	return ptr;
}


//	按值删除
void* del_value_list(List* list,const void* ptr,CMP cmp)
{
	for(Node* n=list->head->next; n!=list->head; n=n->next)
	{
		if(0 == cmp(n->ptr,ptr))
		{
			void* ptr = n->ptr;
			_del_node(n);
			list->size--;
			return ptr;
		}
	}
	return NULL;
}

//	遍历
void show_list(List* list,SHOW show)
{
	for(Node* n=list->head->next; n!=list->head; n=n->next)
	{
		show(n->ptr);
	}
}

//	按位置修改
bool mod_index_list(List* list,size_t index,const void* data,CHANGE change)
{
	Node* node = _index_list(list,index);		
	if(NULL == node) return false;
	change(node->ptr,data);
	return true;
}

//	按值修改
bool mod_value_list(List* list,const void* old,CMP cmp,const void* data,CHANGE change)
{
	for(Node* n=list->head->next; n!=list->head; n=n->next)
	{
		if(0 == cmp(n->ptr,old))
		{
			change(n->ptr,data);
			return true;
		}
	}
	return false;
}

//	访问
void* access_list(List* list,size_t index)
{
	Node* node = _index_list(list,index);	
	if(NULL == node) return NULL;
	return node->ptr;
}

//	查询
void* query_list(List* list,const void* data,CMP cmp)
{
	for(Node* n=list->head->next; n!=list->head; n=n->next)
	{
		if(0 == cmp(n->ptr,data)) return n->ptr;
	}
	return NULL;
}

//	数量
size_t size_list(List* list)
{
	return list->size;
}

//	排序
void sort_list(List* list,CMP cmp)
{
	for(Node* n=list->head->next; n->next!=list->head; n=n->next)
	{
		for(Node* m=n->next; m!=list->head; m=m->next)
		{
			if(1 <= cmp(n->ptr,m->ptr))
			{
				void* temp = n->ptr;
				n->ptr = m->ptr;
				m->ptr = temp;
			}
		}
	}
}

//	清空
void clear_list(List* list)
{
	while(list->size--)
	{
		void* ptr = del_index_list(list,0);	
		free(ptr);
	}
}

//	销毁
void destroy_list(List* list)
{
	clear_list(list);
	free(list->head);
	free(list);
}

标签:node,index,通用,List,void,list,链表,封装,ptr
From: https://www.cnblogs.com/ljf-0804/p/17689735.html

相关文章

  • 排序总结 链表
    排序总结时间复杂度空间复杂度是否能有稳定性选择O(N*N)O(1)×冒泡O(N*N)O(1)✔️插入O(N*N)O(1)✔️归并O(N*logN)O(N)✔️快排(一般指3.0)O(N*logN)O(N*logN)×堆O(N*logN)O(1)×基数排序作为不基于比较的排序,有稳定性基础类型的排序一般排序用快排,因为其时间复杂度常数项更小,需要保持......
  • 代码随想录算法训练营第三天| 203.移除链表元素 707.设计链表 206.反转链表
    203.移除链表元素链表定义structListNode{intval;ListNode*next;ListNode():val(0),next(NULL){};ListNode(intx):val(x),next(NULL){};ListNode(intx,ListNode*next):val(x),next(next){};}1.在原链表上移除链表元素classSolut......
  • 数据结构-封装队列
    list_queue.h#ifndefLIST_QUEUE_H#defineLIST_QUEUE_H#include<stdio.h>#include<stdlib.h>#include<stdbool.h>#defineTYPEint// 节点结构typedefstructNode{ TYPEdata; structNode*next;}Node;// 设计链式队列结构typedefstructList......
  • C# 封装 C++的dll
    C#的程序引用C++的dll时,首先要保证两者基于的平台一致,比如都是x64,或者都是x86的程序,否者两者之间不能直接调用,然后,要保证两者的数据类型可以相互识别,相互通用。在此重点介绍几个常用的数据转换。C++的char*和char[]数组,对应到C#的string类型C++的Handle类型,一般是一个很......
  • 算法通关村第一关——链表青铜挑战笔记
    算法通关村第一关——链表青铜挑战笔记链表是一种经典的数据结构,在很多软件里大量使用,例如操作系统、JVM等。在面试中链表题目数量少,类型也相对固定,考察频率却非常高,因此我们只要将常见题目都学完就万事大吉了,所以链表特别值得刷。单链表的概念链表的概念单向链表就像一个......
  • 数组模拟链表 模拟栈和队列 单调栈和队列(9/7 9/8)
    单链表数组模拟链表可以加快速度,更利于优化算法#include<iostream>usingnamespacestd;constintN=100010;inte[N],ne[N],head,idx;voidinit(){head=-1;idx=0;}voidadd_head(intx){e[idx]=x;ne[idx]=head;head=idx++;}void......
  • uniapp项目实践总结(十三)封装文件操作方法
    导语:在日常APP开发过程中,经常要进行文件的保存、读取列表以及查看和删除文件等操作,接下来就看一下具体的方法。目录原理分析方法实现实战演练案例展示原理分析主要是以下API。uni.saveFile:保存文件到本地缓存列表;uni.getSavedFileList:获取保存文件列表;uni.getSa......
  • 【设计模式】命令模式Command:在一次请求中封装多个参数
    (目录)命令模式使用频率不算太高。如果熟悉函数式编程的话,会发现命令模式完全没有使用的必要,甚至在业务开发的场景中也很少使用到。不过对于想要找到正确抽象的设计者来说,命令模式的设计思想却非常值得借鉴。命令和查询的区别:查询,获取一个不可变的结果;命令,改变状态,不一定获......
  • Java泛型对象在http请求和响应对象中的封装
    Java泛型对象在http请求和响应对象中的封装publicclassMySystemBaseResVo<T>{//注意:类的后面需要带上<T>,否则数据无法封装privateStringerr_no;privateStringerr_tips;privateTdata;publicStringgetErr_no(){returnerr_no;}......
  • React项目笔记-环境搭建、路由封装(跳转Navigate、懒加载lazy)、模块化样式引入、状态管
    环境准备nodev16.15.0npm8.5.5AntDesignofReact:https://ant.design/docs/react/introduce-cn一,创建项目npminitvite√Projectname:...vite-project-react√Selectaframework:»React√Selectavariant:»TypeScript然后使用vscode打开项目,由于......