当构建通用的双向循环链表时,不能保证输入的数据是什么类型,这时可以使用柔性数组帮助我们构建。
柔性数组
struct DNode{
struct DNode *prev;
struct DNode *next;
char elem[];
};
柔性数组的[]中可以不写数字或者是[0],柔性数组必须为结构体的最后一个元素。当需要malloc分配内存时,再根据传入的值来决定数据类型。
双向循环链表中的一些实用函数
清空销毁链表
//清空
void clear_dlinkedlist(DLinkedList list){
assert(list!=NULL);
struct DNode *node,*next; //next用于存储node->next 当node被释放时 再将next赋值给node
for(node=list->next;node!=list;node=next){ //当node==list说明进入循环
next = node->next;
free(node);
}
list->next = list->prev = list; //结点前驱和后继都指向list 此时为头结点
}
//销毁
void destroy_dlinkedlist(DLinkedList list){
assert(list!=NULL);
clear_dlinkedlist(list);
free(list);
}
根据前驱、后继、元素、元素大小创建结点
static struct DNode *create_dnode(struct DNode *prev,struct DNode *next,
const void *pElem,size_t elemSize){
struct DNode *node = (struct DNode *)malloc(DNODESIZE + elemSize); //分配内存
if(node!=NULL){//不为空 分配内存成功
node->prev = prev;
node->next = next;
memcpy(node->elem,pElem,elemSize);//因为不知道数据类型,使用内存拷贝
}
return node;
}
在前插入和在后插入
static int insert_after(struct DNode *node,const void *pElem,size_t elemSize){
struct DNode *insNode = create_dnode(node,node->next,pElem,elemSize);//使用create函数
if(insNode == NULL){ //创建失败
return FAILURE;
}
node->next->prev = insNode;//后插入 需要先将原来的node->next的prev指向insnode
node->next = insNode;
return SUCCESS;
}
static int insert_before(struct DNode *node,const void *pElem,size_t elemSize){
struct DNode *insNode = create_dnode(node->prev,node,pElem,elemSize);
if(insNode == NULL){
return FAILURE;
}
node->prev->next = insNode;
node->prev = insNode;
return SUCCESS;
}
在头部和末尾插入
//头部插入
int push_front_dlinkedlist(DLinkedList list,const void *pElem,size_t elemSize){
assert(list!=NULL && pElem!=NULL && elemSize!=0);
return insert_after(list,pElem,elemSize);
//return insert_before(list->next,pElem,elemSize); 两种方法均可
}
//末尾插入
int push_back_dlinkedlist(DLinkedList list,const void *pElem,size_t elemSize){
assert(list!=NULL && pElem!=NULL && elemSize!=0);
return insert_before(list,pElem,elemSize);
//return insert_after(list->prev,pElem,elemSize); 两种方法均可
根据位置找到结点
static struct DNode *get_dnode(DLinkedList list,size_t pos){
struct DNode *node;
size_t i;
for(node=list->next,i=1;i<pos && node!=list;node=node->next,++i);
if(i<pos){
return NULL;
}
return node;
}
在指定位置前插入
int insert_dlinkedlist(DLinkedList list,size_t pos,const void *pElem,size_t elemSize){
assert(list!=NULL && pElem!=NULL && elemSize!=0);
if(pos == 0){
return FAILURE;
}
struct DNode *node = get_dnode(list,pos);
if(node == NULL){
return FAILURE;
}
return insert_before(node,pElem,elemSize);
}
删除 头部删除以及尾部删除
//删除函数 直接让node前一个结点next指向node下一个结点,node下一个结点的prev指向node前一个结点 释放
static int delete_dnode(struct DNode *node){
node->prev->next = node->next;
node->next->prev = node->prev;
free(node);
return SUCCESS;
}
int pop_front_dlinkedlist(DLinkedList list){
assert(list!=NULL);
if(list->next == list){
return FAILURE;
}
return delete_dnode(list->next); //插入在头部,即list->next
}
int pop_back_dlinkedlist(DLinkedList list){
assert(list!=NULL);
if(list->prev == list){
return FAILURE;
}
return delete_dnode(list->prev);//插入尾部 ,即list->prev
}
指定位置删除
int remove_dlinkedlist(DLinkedList list,size_t pos){
assert(list!=NULL);
if(pos == 0){
return FAILURE;
}
struct DNode *node = get_dnode(list,pos);
if(node == NULL || node == list){
return FAILURE;
}
return delete_dnode(node);
}
根据位置找到elem
void *elem_of_dlinkedlist(DLinkedList list,size_t pos){
assert(list!=NULL);
if(pos == 0){
return NULL;
}
struct DNode *node = get_dnode(list,pos);
if(node == NULL || node == list){
return NULL;
}
return (void *)(node->elem);
}
根据条件删除
int delete_condition_dlinkedlist(DLinkedList list,bool (*condition)(const void *),size_t n){
assert(list!=NULL && condition!=NULL);
int cnt = 0;
struct DNode *node,*next;
for(node=list->next;node!=list;node=next){
next = node->next;
if(condition(node->elem)){
if(n == 0){//n=0时,删除所有满足condition的元素
delete_dnode(node);
++cnt;
}else{
if(--n==0){
delete_dnode(node);
return 1;
}
}
}
}
return cnt;
}
更改elem值
int update_dlinkedlist(DLinkedList list,size_t pos,void *pNewElem,size_t elemSize){
assert(list!=NULL && pNewElem!=NULL && elemSize!=0);
if(pos == 0){
return FAILURE;
}
struct DNode *node = get_dnode(list,pos);
if(node == NULL || node == list){
return FAILURE;
}
memcpy(node->elem,pNewElem,elemSize); //切记使用memcpy内存拷贝
return SUCCESS;
}
逆序输出
双向链表的逆序输出与单向链表的逆序输出差别很大
void reverse_foreach_dlinkedlist(DLinkedList list,void (*foreach)(void *)){
assert(list!=NULL && foreach!=NULL);
struct DNode *node;
for(node=list->prev;node!=list;node=node->prev){
foreach(node->elem);
}
}
如果有错误欢迎指正!谢谢观看!