C语言实现双向循环链表

前言

首先呢,我个人是不推荐写链表的,不过作为初学者来说,学会怎么写这个链表确实很重要。那么我们知道,一般的链表都是单链表,就是他是只有next(我们这边叫只有子没有父),如果你要定位到此节点的前一个节点的话,在单链表中就只能循环遍历一遍来找了。

但是在学会了双向循环链表之后,你就不用再担心这个问题了。那么双向循环链表呢,顾名思义,他是一个既有left(parents)父节点指向指针,又有right(son)子节点指向指针的链表结构。

同样的,作者直接把源代码放文章末尾了,有需要的直接拿走不谢!当然作者很希望各位看官能给本人点个小赞,谢谢!

准备工作

首先呢,头文件是经典的stdio和stdlib(这个是用来malloc分配动态堆空间内存的),然后作者多加了一个assert.h,这个是经典防止参数传空值的。

结构体DuLNode就是节点类型,结构体DuLinkList就是链式结构标准写法。

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#define OK 0
#define ERROR -1
typedef int Status;
typedef int ElemType;
typedef struct DuLNode
{
	struct DuLNode* prev;
	struct DuLNode* next;
	ElemType data;
}DuLNode, * PDuLNode;  //12byte 
typedef struct
{
	DuLNode* head;
	int cursize;//个数
}DuLinkList;

 建立节点

在传参时默认父子节点不传值就都为空指针。sizeof就是获取类型内存长度。

//建立节点
DuLNode* Buynode(ElemType val, DuLNode* parg = nullptr, DuLNode* narg = nullptr)
{
	//DuLNode * s = (DuLNode*)malloc(sizeof(*s));
	DuLNode* s = (DuLNode*)malloc(sizeof(DuLNode));   //12
	if (nullptr == s)  // if(s = nullptr)
	{
		exit(EXIT_FAILURE);
	}
	s->prev = (parg == nullptr) ? s : parg;
	s->next = (narg == nullptr) ? s : narg;
	s->data = val;
	return s;
}

 释放节点

由于创建的时候是用malloc创建的,所以在释放时就要用free来回收内存。

//释放节点
void Freenode(DuLNode* q)
{
	free(q);
}

初始化节点

直接利用建立节点的函数Buynode对头结点进行创建。

void InitList(DuLinkList* plist) {
	assert(plist != nullptr);
	plist->cursize = 0;
	plist->head = Buynode(0);
}

 获取长度

//获得长度
int GetSize(DuLinkList* plist)
{
	assert(plist != nullptr);
	return plist->cursize;
}

判断是否为空

//是否为空
bool IsEmpty(DuLinkList* plist)
{
	assert(plist != nullptr);
	return GetSize(plist) == 0;
}

插入链表

在ptr前先建立一个节点s,并使其成为ptr的父指向,然后将s节点所指向的父节点即原本ptr的父节点的子指向从指向ptr改变为指向s。

void InsertPrev(DuLinkList* plist, DuLNode* ptr, ElemType val)
{
	assert(plist != nullptr && ptr != nullptr);
	ptr->prev = Buynode(val, ptr->prev, ptr);
	DuLNode* s = ptr->prev;
	s->prev->next = s;
	plist->cursize++;
}

尾插

这里有人会问,你尾插不应该循环到尾部然后再调用插入函数吗?那作者想告诉你,这是双向循环链表,你忽视了他循环的属性。所谓循环,就是尾部不在指向null,而是直接指向头结点。

这么一来,你从头节点往头结点前面插入不就等同于尾插?没有问题吧?

//尾插
void Push_Back(DuLinkList* plist, ElemType val) {
	assert(plist != nullptr);
	InsertPrev(plist, plist->head, val);
}

头插

放到头结点后面插入不就是头插?没问题吧?

//头插
void Push_Front(DuLinkList* plist, ElemType val) {
	assert(plist != nullptr);
	InsertPrev(plist, plist->head->next, val);
}

打印

//打印
void PrintList(DuLinkList* plist) {
	assert(plist != nullptr);
	DuLNode* p = plist->head->next;
	while (p != plist->head) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

查询

//查询
DuLNode* FindValue(DuLinkList* plist, ElemType val) {
	assert(plist != nullptr);
	DuLNode* p = plist->head->next;
	while (p != plist->head && p->data != val) {
		p = p->next;
	}
	if (p == plist->head) {
		p = nullptr;
	}
	return p;
}

删除节点

//删除ptr节点
void Erase(DuLinkList* plist, DuLNode* ptr) {
	assert(plist != nullptr && ptr != nullptr);
	if (ptr == nullptr) return;
	ptr->next->prev = ptr->prev;
	ptr->prev->next = ptr->next;
	Freenode(ptr);
	plist->cursize -= 1;
}

尾删

//删除尾节点
void Pop_back(DuLinkList* plist)
{
	assert(plist != nullptr);
	Erase(plist, plist->head->prev);
}

头删

//删除第一个结点
void Pop_front(DuLinkList* plist)
{
	assert(plist != nullptr);
	Erase(plist, plist->head->next);
}

按数据值删

//删除val值的节点
void Remove(DuLinkList* plist, ElemType val)
{
	assert(plist != nullptr);
	DuLNode* p = FindValue(plist, val);
	if (p != nullptr)
	{
		Erase(plist, p);
	}
}

清空链表

void ClearList(DuLinkList* plist)
{
	assert(plist != nullptr);
	while (!IsEmpty(plist))
	{
		Pop_back(plist);
	}
}

销毁链表

//销毁链表
void DestroyList(DuLinkList* plist)
{
	assert(plist != nullptr);
	ClearList(plist);
	Freenode(plist->head);
	plist->head = nullptr;
}

源代码

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#define OK 0
#define ERROR -1
typedef int Status;
typedef int ElemType;
typedef struct DuLNode
{
	struct DuLNode* prev;
	struct DuLNode* next;
	ElemType data;
}DuLNode, * PDuLNode;  //12byte 
typedef struct
{
	DuLNode* head;
	int cursize;//个数
}DuLinkList;
//建立节点
DuLNode* Buynode(ElemType val, DuLNode* parg = nullptr, DuLNode* narg = nullptr)
{
	//DuLNode * s = (DuLNode*)malloc(sizeof(*s));
	DuLNode* s = (DuLNode*)malloc(sizeof(DuLNode));   //12
	if (nullptr == s)  // if(s = nullptr)
	{
		exit(EXIT_FAILURE);
	}
	s->prev = (parg == nullptr) ? s : parg;
	s->next = (narg == nullptr) ? s : narg;
	s->data = val;
	return s;
}
//释放节点
void Freenode(DuLNode* q)
{
	free(q);
}
void InitList(DuLinkList* plist) {
	assert(plist != nullptr);
	plist->cursize = 0;
	plist->head = Buynode(0);
}
//获得长度
int GetSize(DuLinkList* plist)
{
	assert(plist != nullptr);
	return plist->cursize;
}
//是否为空
bool IsEmpty(DuLinkList* plist)
{
	assert(plist != nullptr);
	return GetSize(plist) == 0;
}
//用Prev插入节点
void InsertPrev(DuLinkList* plist, DuLNode* ptr, ElemType val)
{
	assert(plist != nullptr && ptr != nullptr);
	ptr->prev = Buynode(val, ptr->prev, ptr);
	DuLNode* s = ptr->prev;
	s->prev->next = s;
	plist->cursize++;
}
//尾插
void Push_Back(DuLinkList* plist, ElemType val) {
	assert(plist != nullptr);
	InsertPrev(plist, plist->head, val);
}
//头插
void Push_Front(DuLinkList* plist, ElemType val) {
	assert(plist != nullptr);
	InsertPrev(plist, plist->head->next, val);
}
//打印
void PrintList(DuLinkList* plist) {
	assert(plist != nullptr);
	DuLNode* p = plist->head->next;
	while (p != plist->head) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}
//查询
DuLNode* FindValue(DuLinkList* plist, ElemType val) {
	assert(plist != nullptr);
	DuLNode* p = plist->head->next;
	while (p != plist->head && p->data != val) {
		p = p->next;
	}
	if (p == plist->head) {
		p = nullptr;
	}
	return p;
}
//删除ptr节点
void Erase(DuLinkList* plist, DuLNode* ptr) {
	assert(plist != nullptr && ptr != nullptr);
	if (ptr == nullptr) return;
	ptr->next->prev = ptr->prev;
	ptr->prev->next = ptr->next;
	Freenode(ptr);
	plist->cursize -= 1;
}
//删除尾节点
void Pop_back(DuLinkList* plist)
{
	assert(plist != nullptr);
	Erase(plist, plist->head->prev);
}
//删除第一个结点
void Pop_front(DuLinkList* plist)
{
	assert(plist != nullptr);
	Erase(plist, plist->head->next);
}
//删除val值的节点
void Remove(DuLinkList* plist, ElemType val)
{
	assert(plist != nullptr);
	DuLNode* p = FindValue(plist, val);
	if (p != nullptr)
	{
		Erase(plist, p);
	}
}
//销毁链表中每一个节点
void ClearList(DuLinkList* plist)
{
	assert(plist != nullptr);
	while (!IsEmpty(plist))
	{
		Pop_back(plist);
	}
}
//销毁链表
void DestroyList(DuLinkList* plist)
{
	assert(plist != nullptr);
	ClearList(plist);
	Freenode(plist->head);
	plist->head = nullptr;
}

最后,写文不易,不收藏也请给个赞,谢谢亲~! 

(本文仅供学习时参考,如有错误,纯属作者技术不到位,不足之处请多指教,谢谢)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值