//!
//! C++工具:C语言链表实现C++STL接口--支持泛型宏
//!
//! == 工具简介 ==
//! 本文是上篇文章的加强版
//! 上篇文章: C++工具:仿C++STL接口的C风格链表--支持函数泛型
//!
//! 上篇文章实现了C语言链表的泛型与C++STL接口,但使用的是函数风格,
//! 不同类型需要用不同函数操作,略显麻烦,且不支持深拷贝数据结构,
//! 指针类型需要手动分配和循环链表释放内存
//!
//! 本章带来的加强版链表采用面向对象的思想,使用与接口与C++STL类似,
//! 提供自定义内存分配器,支持自定义类型的深拷贝操作,
//! 默认自动生成八大基本类型和字符串类型链表,
//! 提供默认浅拷贝分配器和字符串分配器
//!
//! 加强版链表利用结构体封装回调指针实现接口的统一,
//! 利用宏泛型生成对应数据结构类型
//! == 工具简介 ==
//!
//!
//! == 使用说明 ==
//! 以字符串类型作为例子:
//!
//! == 代码段 ==
//! // Tlist_make宏的等价声明: Tlist_Tcharp *ls = Topen_Tcharp(Tmalloc_Tcharp,Tfree_Tcharp);
//! Tlist_Tcharp *ls = Tlist_make(Tcharp);
//! Tfor_each(ls,it,Tcharp)
//! {
//! printf("%s\n",it->value);
//! }
//! Tclose_Tcharp(ls);
//! == 代码段 ==
//!
//! 1.Tlist_Tcharp为链表类型,类似list<char*>
//! 2.Topen_Tcharp函数类似构造函数,链表需要构造函数初始化才能使用
//! 3.Tmalloc_Tcharp是内存分配函数,Tfree_Tcharp是内存释放函数
//! 4.内存分配器可以自定义分配结构体的内存分配问题,和深拷贝问题
//! 5.Tfor_each是遍历宏,参数(1:链表对象,2:返回的迭代器,3:数据接口类型)
//! 6.Tclose_Tcharp函数类似析构函数,释放链表的元素内存与链表本身的内存
//! 7.自定义分配器时注意内存泄露问题,内存分配与释放函数需完全对应
//! 8.Tlist_make宏是快速声明宏,方便使用,如果是自定义分配器,必须符合函数签名格式
//! == 使用说明 ==
//!
//!
//! == 展示顺序 ==
//! 1.main测试代码
//! 2.Tlist_Tapi.h文件
//! 3.测试参考头文件
//! == 展示顺序 ==
//!
//!
//! 结束语:
//! 该链表的使用符合C++程序员在C语言的使用习惯,
//! 也解决了C语言下C++程序员无容器可用的烦恼,
//! 与C语言内核链表相比泛型容器可以降低学习成本
//! 本文提供的容器可能还有很多不足的地方,如果有发现问题请在评论区反馈,
//! 如果本文给你提供了C语言下其他C++泛型容器的设计思想,你已经实现并希望分享给大家,
//! 请在评论区留言并将代码提交到GIthub上
//! GIthub网址:https://github.com/HellowAmy/cpp_base.git
//!
//!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Tlist_Tapi.h"
//== 自定义类型:自定义内存分配:注意生成顺序 (类型定义 -> 宏代码生成 -> 自定义分配器) ==
typedef struct meg meg;
struct meg
{
int len;
char *type;
char data[100];
};
//注意:
// 当链表调用push_back等需要分配内存的函数元素的函数时,调用Tmalloc
// 调用pop_back等移除元素时需要释放内存的函数时,调用Tfree
//对象
Tlist_Tbuild(Tmeg,meg)
static void Tmalloc_Tmeg(Tls_Tmeg *head,meg value)
{
head->value.len = value.len;
head->value.type = (char*)malloc(strlen(value.type) +1);
strcpy(head->value.type,value.type);
strcpy(head->value.data,value.data);
}
static void Tfree_Tmeg(Tls_Tmeg *head)
{
free(head->value.type);
}
//指针
Tlist_Tbuild(Tmegp,meg *)
static void Tmalloc_Tmegp(Tls_Tmegp *head,const meg *value)
{
//给链表存储的指针分配内存
head->value = (meg *)malloc(sizeof(meg));
//给结构体内的成员分配内存
head->value->type = (char*)malloc(strlen(value->type) +1);
head->value->type[strlen(value->type)] = '\0';
head->value->len = value->len;
strcpy(head->value->type,value->type);
strcpy(head->value->data,value->data);
}
static void Tfree_Tmegp(Tls_Tmegp *head)
{
//Tmalloc函数分配了多少Tfee就释放多少
free(head->value->type);
free(head->value);
}
//== 自定义类型:自定义内存分配:注意生成顺序 (类型定义 -> 宏代码生成 -> 自定义分配器) ==
//== 自定义类型:(使用默认分配器需要外部malloc分配内存,否则会浅拷贝问题) ==
typedef struct dire dire;
struct dire
{
int x;
int y;
int z;
char *data;
};
Tls_Tbase(Tdirep,dire *)
//== 自定义类型:(使用默认分配器需要外部malloc分配内存,否则会浅拷贝问题) ==
//各类型加入测试
void test_1()
{
//== 基础类型测试 ==
printf("== 基础类型测试 ==\n");
{
Tlist_Tchar *ls = Tlist_make(Tchar); //等价下方声明
// Tlist_Tchar *ls = Topen_Tchar(Tmalloc_Tchar,Tfree_Tchar);
const char t1 = 'a';
char t2 = 'b';
ls->push_back(ls,t1);
ls->push_back(ls,t2);
ls->push_back(ls,'c');
Tfor_each(ls,it,Tchar)
{
printf("%c\n",it->value);
}
Tclose_Tchar(ls);
}
{
Tlist_Tint *ls = Topen_Tint(Tmalloc_Tint,Tfree_Tint);
const int t1 = 100;
int t2 = 200;
ls->push_back(ls,t1);
ls->push_back(ls,t2);
ls->push_back(ls,300);
Tfor_each(ls,it,Tint)
{
printf("%d\n",it->value);
}
Tclose_Tint(ls);
}
//== 基础类型测试 ==
//== 字符串测试 ==
printf("== 字符串测试 ==\n");
{
Tlist_Tcharp *ls = Topen_Tcharp(Tmalloc_Tcharp,Tfree_Tcharp);
const char* t1 = "a1";
char* t2 = "a2";
ls->push_back(ls,t1);
ls->push_back(ls,t2);
ls->push_back(ls,"a3");
Tfor_each(ls,it,Tcharp)
{
printf("%s\n",it->value);
}
Tclose_Tcharp(ls);
}
{
Tlist_Tcharp *ls = Tlist_make(Tcharp);
const char* t1 = "a1";
char* t2 = "a2";
ls->push_back(ls,t1);
ls->push_back(ls,t2);
ls->push_back(ls,"a3");
Tfor_each(ls,it,Tcharp)
{
printf("%s\n",it->value);
}
Tclose_Tcharp(ls);
}
//== 字符串测试 ==
//== 自定义测试 ==
printf("== 自定义测试 ==\n");
{
Tlist_Tmeg *ls = Topen_Tmeg(Tmalloc_Tmeg,Tfree_Tmeg);
{
const meg t1 = {0,"00","000"};
meg t2;
t2.len = 1;
t2.type = (char *)malloc(100);
strcpy(t2.type,"11");
strcpy(t2.data,"111");
ls->push_back(ls,t1);
ls->push_back(ls,t2);
}
Tfor_each(ls,it,Tmeg)
{
printf("p1:[%d : %s : %s]\n",it->value.len,it->value.data,it->value.type);
}
Tclose_Tmeg(ls);
}
{
Tlist_Tmegp *ls = Topen_Tmegp(Tmalloc_Tmegp,Tfree_Tmegp);
{
meg* t2 = (meg*)malloc(sizeof(meg));
t2->len = 1;
t2->type = (char *)malloc(100);
strcpy(t2->type,"11");
strcpy(t2->data,"111");
ls->push_back(ls,t2);
//使用完了需要释放
free(t2->type);
}
Tfor_each(ls,it,Tmegp)
{
printf("p2:[%d : %s : %s]\n",it->value->len,it->value->data,it->value->type);
}
Tclose_Tmegp(ls);
}
{
Tlist_Tdirep *ls = Tlist_make(Tdirep);//等价下方声明
// Tlist_Tdirep *ls = Topen_Tdirep(Tmalloc_Tdirep,Tfree_Tdirep);
{
//使用默认分配器时,刚分配加入链表的变量不要释放
dire *t1 = (dire *)malloc(sizeof(dire));
t1->x = 1;
t1->y = 2;
t1->z = 3;
t1->data = (char *)malloc(100);
strcpy(t1->data,"4");
ls->push_back(ls,t1);
dire *t2 = (dire *)malloc(sizeof(dire));
t2->x = 11;
t2->y = 22;
t2->z = 33;
t2->data = (char *)malloc(100);
strcpy(t2->data,"44");
ls->push_back(ls,t2);
}
//使用默认分配器时,关闭链表时需要手动释放元素的内存
//for
Tfor_each(ls,it,Tdirep)
{
printf("p3:[%d : %d : %d : %s]\n",it->value->x,it->value->y,it->value->z,it->value->data);
}
Tclose_Tdirep(ls);
}
//== 自定义测试 ==
printf("== 测试结束 ==\n");
}
//== 接口测试 ==
void test_2()
{
printf("\n== 接口测试 ==\n");
printf("== 操作ls1 ==\n");
//使用链表时,需要开启和关闭链表
Tlist_Tcharp *ls1 = Topen_Tcharp(Tmalloc_Tcharp,Tfree_Tcharp);
ls1->push_back(ls1,"s[1]");
ls1->push_back(ls1,"s[2]");
ls1->push_front(ls1,"s[-1]");
ls1->push_front(ls1,"s[-2]");
ls1->insert(ls1,2,"s[0.1]");
ls1->insert(ls1,3,"s[0.2]");
Tfor_each(ls1,it,Tcharp)
{
printf("%s\n",it->value);
}
printf("链表个数: %ld\n",ls1->size);
Tlist_Tcharp *ls2 = Tclone_Tcharp(ls1);
printf("克隆链表ls2: 链表个数: %ld\n",ls2->size);
printf("\n== 移除元素 ==\n");
ls1->pop_back(ls1);
ls1->pop_front(ls1);
ls1->erase(ls1,1);
Tfor_each(ls1,it,Tcharp)
{
printf("%s\n",it->value);
}
printf("链表个数: %ld\n",ls1->size);
ls1->clear(ls1); //清空链表
printf("清空链表:链表个数: %ld\n",ls1->size);
Tclose_Tcharp(ls1); //关闭链表
//操作ls2
printf("== 操作ls2 ==\n");
Tfor_each(ls2,it,Tcharp)
{
printf("%s\n",it->value);
}
Tclose_Tcharp(ls2); //关闭链表
printf("== 测试结束 ==\n");
}
int main()
{
printf("== begin ==\n");
test_1();
test_2();
printf("== end ==\n");
return 0;
}
/*
* 测试结果
*
== begin ==
== 基础类型测试 ==
a
b
c
100
200
300
== 字符串测试 ==
a1
a2
a3
== 自定义测试 ==
p1:[0 : 000 : 00]
p1:[1 : 111 : 11]
p2:[1 : 111 : 11]
p3:[1 : 2 : 3 : 4]
p3:[11 : 22 : 33 : 44]
== 测试结束 ==
== 接口测试 ==
== 操作ls1 ==
s[-2]
s[-1]
s[0.1]
s[0.2]
s[1]
s[2]
链表个数: 6
克隆链表ls2: 链表个数: 6
== 移除元素 ==
s[-1]
s[0.2]
s[1]
链表个数: 3
清空链表:链表个数: 0
== 操作ls2 ==
s[-2]
s[-1]
s[0.1]
s[0.2]
s[1]
s[2]
== 测试结束 ==
== end ==
*/
//!
//! Tlist_Tapi.h
//!
#ifndef TLIST_TAPI_H
#define TLIST_TAPI_H
#include <stdlib.h>
#include <string.h>
//未使用变量警告去除
#define Tun(x) (void)(x)
//链表遍历宏
#define Tfor_each(ls,it,Tapi) \
for(Tls_##Tapi *it = ls->head->next;it!=NULL;it=it->next)
//定义函数代码生成宏
#define Tlist_Tbuild(Tapi,Tvalue) \
typedef struct Tls_##Tapi Tls_##Tapi; \
struct Tls_##Tapi \
{ \
Tvalue value; \
Tls_##Tapi *prev; \
Tls_##Tapi *next; \
}; \
\
typedef struct Tlist_##Tapi Tlist_##Tapi; \
struct Tlist_##Tapi \
{ \
void (*alloc) (Tls_##Tapi *head,const Tvalue value); \
void (*free) (Tls_##Tapi *head); \
void (*init) (Tls_##Tapi *head); \
void (*push_back) (Tlist_##Tapi *head,const Tvalue value); \
void (*push_front) (Tlist_##Tapi *head,const Tvalue value); \
int (*insert) (Tlist_##Tapi *head,size_t pos,const Tvalue value); \
void (*pop_back) (Tlist_##Tapi *head); \
void (*pop_front) (Tlist_##Tapi *head); \
int (*erase) (Tlist_##Tapi *head,size_t pos); \
void (*clear) (Tlist_##Tapi *head); \
size_t size; \
Tls_##Tapi *head; \
}; \
\
__attribute__((unused)) \
static void list_init_##Tapi(Tls_##Tapi *head) \
{ \
if(head == NULL) return; \
head->prev = NULL; \
head->next = NULL; \
} \
\
__attribute__((unused)) \
static void list_push_back_##Tapi(Tlist_##Tapi *ls,const Tvalue value) \
{ \
if(ls->head == NULL) return; \
Tls_##Tapi *new_value = (Tls_##Tapi *)malloc(sizeof(Tls_##Tapi)); \
list_init_##Tapi(new_value); \
\
if(ls->size == 0) \
{ \
ls->head->prev = new_value; \
ls->head->next = new_value; \
new_value->prev = ls->head; \
} \
else \
{ \
new_value->prev = ls->head->prev; \
ls->head->prev->next = new_value; \
ls->head->prev = new_value; \
} \
ls->size += 1; \
ls->alloc(new_value,value); \
} \
\
__attribute__((unused)) \
static void list_push_front_##Tapi(Tlist_##Tapi *ls,const Tvalue value) \
{ \
if(ls->head == NULL) return; \
Tls_##Tapi *new_value = (Tls_##Tapi *)malloc(sizeof(Tls_##Tapi)); \
list_init_##Tapi(new_value); \
\
if(ls->size == 0) \
{ \
ls->head->prev = new_value; \
ls->head->next = new_value; \
new_value->prev = ls->head; \
} \
else \
{ \
ls->head->next->prev = new_value; \
new_value->next = ls->head->next; \
new_value->prev = ls->head; \
ls->head->next = new_value; \
} \
ls->size += 1; \
ls->alloc(new_value,value); \
} \
\
__attribute__((unused)) \
static int list_insert_##Tapi(Tlist_##Tapi *ls,size_t pos,const Tvalue value) \
{ \
if(ls->head == NULL || pos >= ls->size) return 0; \
Tls_##Tapi *new_value = (Tls_##Tapi *)malloc(sizeof(Tls_##Tapi)); \
list_init_##Tapi(new_value); \
\
size_t count = 0; \
Tls_##Tapi *it = ls->head->next; \
for(;it != NULL;it = it->next) \
{ \
if(count == pos) break; \
count++; \
} \
\
new_value->next = it; \
new_value->prev = it->prev; \
it->prev->next = new_value; \
it->prev = new_value; \
\
ls->size += 1; \
ls->alloc(new_value,value); \
return 1; \
} \
\
__attribute__((unused)) \
static void list_pop_back_##Tapi(Tlist_##Tapi *ls) \
{ \
if(ls->head == NULL || ls->size == 0) return ; \
ls->size -= 1; \
\
Tls_##Tapi *end = ls->head->prev; \
ls->head->prev = end->prev; \
end->prev->next = NULL; \
ls->free(end); \
free(end); \
} \
\
__attribute__((unused)) \
static void list_pop_front_##Tapi(Tlist_##Tapi *ls) \
{ \
if(ls->head == NULL || ls->size == 0) return ; \
ls->size -= 1; \
\
Tls_##Tapi *begin = NULL; \
if(ls->size == 0) \
{ \
begin = ls->head->next; \
ls->head->next = NULL; \
} \
else \
{ \
begin = ls->head->next; \
ls->head->next = begin->next; \
begin->next->prev = ls->head; \
} \
ls->free(begin); \
free(begin); \
} \
\
__attribute__((unused)) \
static int list_erase_##Tapi(Tlist_##Tapi *ls,size_t pos) \
{ \
if(ls->head == NULL || ls->size == 0 || pos >= ls->size) return 0; \
ls->size -= 1; \
\
size_t count = 0; \
Tls_##Tapi *it = ls->head->next; \
for(;it != NULL;it = it->next) \
{ \
if(count == pos) break; \
count++; \
} \
\
Tls_##Tapi *now = NULL; \
if(pos == ls->size || ls->size == 0) \
{ \
now = it; \
it->prev->next = NULL; \
ls->head->prev = it->prev; \
} \
else \
{ \
now = it; \
it->prev->next = it->next; \
it->next->prev = it->prev; \
\
} \
ls->free(now); \
free(now); \
return 1; \
} \
\
__attribute__((unused)) \
static void list_clear_##Tapi(Tlist_##Tapi *ls) \
{ \
if(ls->head == NULL) return; \
while(1) \
{ \
Tls_##Tapi *begin = ls->head->next; \
if(begin == NULL) break; \
ls->head->next = ls->head->next->next; \
ls->free(begin); \
free(begin); \
} \
ls->size = 0; \
} \
\
__attribute__((unused)) \
static Tlist_##Tapi* Topen_##Tapi \
(void (*alloc)(Tls_##Tapi *head,const Tvalue value), \
void (*free)(Tls_##Tapi *head)) \
{ \
Tlist_##Tapi *ls = (Tlist_##Tapi *)malloc(sizeof(Tlist_##Tapi)); \
ls->head = (Tls_##Tapi*)malloc(sizeof(Tls_##Tapi)); \
\
ls->alloc = alloc; \
ls->free = free; \
ls->init = list_init_##Tapi; \
ls->push_back = list_push_back_##Tapi; \
ls->push_front = list_push_front_##Tapi; \
ls->insert = list_insert_##Tapi; \
ls->pop_back = list_pop_back_##Tapi; \
ls->pop_front = list_pop_front_##Tapi; \
ls->erase = list_erase_##Tapi; \
ls->clear = list_clear_##Tapi; \
\
ls->size = 0; \
ls->init(ls->head); \
return ls; \
} \
\
__attribute__((unused)) \
static void Tclose_##Tapi(Tlist_##Tapi *ls) \
{ \
ls->clear(ls); \
free(ls->head); \
free(ls); \
} \
\
__attribute__((unused)) \
static Tlist_##Tapi* Tclone_##Tapi(Tlist_##Tapi *ls) \
{ \
if(ls == NULL) return NULL; \
Tlist_##Tapi *ls_new = Topen_##Tapi(ls->alloc,ls->free); \
\
for(Tls_##Tapi *it = ls->head->next;it!=NULL;it=it->next) \
{ \
ls_new->push_back(ls_new,it->value); \
} \
return ls_new; \
} \
//定义生成浅拷贝分配器
#define Tac_Tdefault(Tapi,Tvalue) \
__attribute__((unused)) \
static void Tmalloc_##Tapi(Tls_##Tapi *head,const Tvalue value) \
{ head->value = (Tvalue)value; } \
__attribute__((unused)) \
static void Tfree_##Tapi(Tls_##Tapi *head) \
{ Tun(head); } \
//定义生成字符串分配器
#define Tac_Tcharp(Tapi) \
__attribute__((unused)) \
static void Tmalloc_Tcharp(Tls_##Tapi *head,const char* value) \
{ \
head->value = (char*)malloc(strlen(value) +1); \
strncpy(head->value,value,strlen(value)); \
head->value[strlen(value)] = '\0'; \
} \
__attribute__((unused)) \
static void Tfree_Tcharp(Tls_##Tapi *head) \
{ free(head->value); } \
//== 定义生成对应类型代码 + 浅拷贝分配器 ==
#define Tls_Tbase(Tapi,Tvalue) \
Tlist_Tbuild(Tapi,Tvalue) \
Tac_Tdefault(Tapi,Tvalue) \
//== 定义生成对应类型代码 + 字符串分配器 ==
#define Tls_Tcharp() \
Tlist_Tbuild(Tcharp,char *) \
Tac_Tcharp(Tcharp) \
//===== 最终代码生成 =====
//基础类型(浅拷贝存储)
Tls_Tbase(Tchar,char)
Tls_Tbase(Tshort,short)
Tls_Tbase(Tint,int)
Tls_Tbase(Tlong,long)
Tls_Tbase(Tlonglong,long long)
Tls_Tbase(Tfloat,float)
Tls_Tbase(Tdouble,double)
//字符串(深拷贝特例)
Tls_Tcharp()
//===== 最终代码生成 =====
//== 快速构造的工厂宏 ==
#define Tlist_make(Tapi) Topen_##Tapi(Tmalloc_##Tapi,Tfree_##Tapi)
#endif // TLIST_TAPI_H
//!
//! 测试参考代码
//!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Tlist_for(it,head) for(Tlist_c *it = head.next;it != NULL;it = it->next)
#define Tlist_for_p(it,head) for(Tlist_c *it = head->next;it != NULL;it = it->next)
//类型宏
#define Tvalue char *
//#define Tvalue int
//#define Tvalue msg
//存放数据的链表
typedef struct Tlist_c Tlist_c;
struct Tlist_c
{
Tvalue value;
// size_t size;
Tlist_c *prev;
Tlist_c *next;
};
//操作结构体--集合操作链表回调函数的数据结构
typedef struct Tlist_ac Tlist_ac;
struct Tlist_ac
{
void (*alloc) (Tlist_c *head,const Tvalue value);
void (*free) (Tlist_c *head);
void (*init) (Tlist_c *head);
void (*push_back) (Tlist_ac *head,const Tvalue value);
void (*push_front) (Tlist_ac *head,const Tvalue value);
int (*insert) (Tlist_ac *head,size_t pos,const Tvalue value);
void (*pop_back) (Tlist_ac *head);
void (*pop_front) (Tlist_ac *head);
int (*erase) (Tlist_ac *head,size_t pos);
void (*clear) (Tlist_ac *head);
// Tlist_ac (*clone) (Tlist_ac *head);
// size_t (*size) (Tlist_ac *head);
size_t size;
Tlist_c *head; //链表
};
//链表的初始化函数,使用链表前必须初始化
static void list_init(Tlist_c *head)
{
if(head == NULL) return;
// head->size = 0;
head->prev = NULL;
head->next = NULL;
}
static void list_push_back(Tlist_ac *ls,const Tvalue value)
{
//分配空间
if(ls->head == NULL) return;
Tlist_c *new_value = (Tlist_c *)malloc(sizeof(Tlist_c));
list_init(new_value);
//连接到头节点
if(ls->size == 0)
{
//1.头节点的前后指针,指到新节点
//2.新节点前指针,指到头节点
ls->head->prev = new_value;
ls->head->next = new_value;
new_value->prev = ls->head;
}
else
{
//1.新节点前节点,指向头节点前指针(头节点前指针等于尾节点)
//2.尾节点的后指针,指到新节点
//3.头节点前指针,指到新节点(等于将新节点当做尾节点)
new_value->prev = ls->head->prev;
ls->head->prev->next = new_value;
ls->head->prev = new_value;
}
ls->size += 1; //计数
ls->alloc(new_value,value); //赋值
}
static void list_push_front(Tlist_ac *ls,const Tvalue value)
{
//分配空间
if(ls->head == NULL) return;
Tlist_c *new_value = (Tlist_c *)malloc(sizeof(Tlist_c));
list_init(new_value);
//连接到头节点
if(ls->size == 0)
{
//参考: list_push_back
ls->head->prev = new_value;
ls->head->next = new_value;
new_value->prev = ls->head;
}
else
{
//1.第一个带数据节点的前指针,指向新节点
//2.新节点的后指针,指向第一个带数据节点
//3.新节点的前指针,指向头节点
//4.头节点的后指针,指向新节点
ls->head->next->prev = new_value;
new_value->next = ls->head->next;
new_value->prev = ls->head;
ls->head->next = new_value;
}
ls->size += 1; //计数
ls->alloc(new_value,value); //赋值
}
static int list_insert(Tlist_ac *ls,size_t pos,const Tvalue value)
{
//分配空间
if(ls->head == NULL || pos >= ls->size) return 0;
Tlist_c *new_value = (Tlist_c *)malloc(sizeof(Tlist_c));
list_init(new_value);
//获取指定的当前节点
size_t count = 0;
Tlist_c *it = ls->head->next;
for(;it != NULL;it = it->next)
{
if(count == pos) break;
count++;
}
//1.新节点后指针,指向当前节点
//2.新节点前指针,指向当前节点的前指针(等于当前节点的前节点)
//3.当前节点的前节点的后指针,指向新节点
//4.当前节点前指针,指向新节点
new_value->next = it;
new_value->prev = it->prev;
it->prev->next = new_value;
it->prev = new_value;
ls->size += 1; //计数
ls->alloc(new_value,value); //赋值
return 1;
}
static void list_pop_back(Tlist_ac *ls)
{
if(ls->head == NULL || ls->size == 0) return ;
ls->size -= 1; //计数移除
//1.保留尾节点
//2.头节点的前指针,指向尾节点的前一个
//3.尾节点的前一个的后指针,指向空(新的尾节点指向空)
//4.释放尾节点
Tlist_c *end = ls->head->prev;
ls->head->prev = end->prev;
end->prev->next = NULL;
ls->free(end);
free(end);
}
static void list_pop_front(Tlist_ac *ls)
{
if(ls->head == NULL || ls->size == 0) return ;
ls->size -= 1; //计数移除
//最后一个节点
Tlist_c *begin = NULL;
if(ls->size == 0)
{
begin = ls->head->next;
ls->head->next = NULL;
}
else
{
//1.保留第一个带数据节点
//2.头节点的后指针,指向第一个带数据的后指针(等于第二个带数据节点)
//3.第二个带数据的前指针,指向头节点
//4.释放第一个带数据节点
begin = ls->head->next;
ls->head->next = begin->next;
begin->next->prev = ls->head;
}
ls->free(begin);
free(begin);
}
static int list_erase(Tlist_ac *ls,size_t pos)
{
if(ls->head == NULL || ls->size == 0 || pos >= ls->size) return 0;
ls->size -= 1; //计数移除
//获取指定的当前节点
size_t count = 0;
Tlist_c *it = ls->head->next;
for(;it != NULL;it = it->next)
{
if(count == pos) break;
count++;
}
//删除末尾节点和最后一个元素时,需要特殊处理,避免操作空指针
Tlist_c *now = NULL;
if(pos == ls->size || ls->size == 0)
{
//1.保留当前节点
//2.前一个节点的后指针,指向空(新尾节点)
//3.头节点前指针,指向新尾节点
//4.释放当前指针
now = it;
it->prev->next = NULL;
ls->head->prev = it->prev;
}
else
{
//1.保留当前节点
//2.前一个节点的后指针,指向后节点
//3.后节点的前指针,指向前节点
//4.释放当前指针
now = it;
it->prev->next = it->next;
it->next->prev = it->prev;
}
ls->free(now);
free(now);
return 1;
}
static void list_clear(Tlist_ac *ls)
{
if(ls->head == NULL) return;
while(1)
{
//1.保存第一个节点,获取下一个,然后依次释放
Tlist_c *begin = ls->head->next;
if(begin == NULL) break;
ls->head->next = ls->head->next->next;
ls->free(begin);
free(begin);
}
ls->size = 0; //清空计数
}
//启动链表
static Tlist_ac* Tlist_open(void (*alloc)(Tlist_c *head,const Tvalue value),void (*free)(Tlist_c *head))
{
//分配自身内存和链表的头节点链表
Tlist_ac *ls = (Tlist_ac *)malloc(sizeof(Tlist_ac));
ls->head = (Tlist_c*)malloc(sizeof(Tlist_c));
//注册操作链表的回调函数
// alloc和free回调需要用使用者自定义
// 自定义复杂结构内存的分配和释放
ls->alloc = alloc;
ls->free = free;
ls->init = list_init;
ls->push_back = list_push_back;
ls->push_front = list_push_front;
ls->insert = list_insert;
ls->pop_back = list_pop_back;
ls->pop_front = list_pop_front;
ls->erase = list_erase;
ls->clear = list_clear;
ls->clear = list_clear;
//初始化链表
ls->size = 0;
ls->init(ls->head);
return ls;
}
//关闭链表
static void Tlist_close(Tlist_ac *ls)
{
ls->clear(ls); //清空带数据节点
free(ls->head); //清空头节点
free(ls); //清空操作结构体
}
//克隆链表
static Tlist_ac* Tlist_clone(Tlist_ac *ls)
{
if(ls == NULL) return NULL;
Tlist_ac *ls_new = Tlist_open(ls->alloc,ls->free);
for(Tlist_c *it = ls->head->next;it!=NULL;it=it->next)
{
ls_new->push_back(ls_new,it->value);
}
return ls_new;
}
//== 默认分配器 ==
//字符串
static void list_malloc_Tcharp(Tlist_c *head,const char* value)
{
head->value = (char*)malloc(strlen(value) +1);
strncpy(head->value,value,strlen(value));
head->value[strlen(value)] = '\0';
}
static void list_free_Tcharp(Tlist_c *head)
{ free(head->value); }
基本类型
//static void list_malloc_Tbase(Tlist_c *head,Tvalue value)
//{ head->value = value; }
//static void list_free_Tbase(Tlist_c *head)
//{ }
//== 默认分配器 ==