通用的双向循环链表

当构建通用的双向循环链表时,不能保证输入的数据是什么类型,这时可以使用柔性数组帮助我们构建。

柔性数组

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);
	}
}

如果有错误欢迎指正!谢谢观看!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值