双向循环链表

duanchangdi
15
2025-05-18

一、介绍

特点

带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个链表虽然结构复杂,但是使用代码实现以后会发现能带来很多优势.

结构

image-JAEP.png

二、实现

在List.h需要声明的头文件

#include <stdio.h>
//malloc函数用到
#include <stdlib.h>
//assert函数用到
#include <assert.h>

链表结构

在List.h中声明

typedef int ListNodeDate;

typedef struct ListNode
{
	ListNodeDate date;

	struct ListNode* next;//指向下一个
	struct ListNode* prev;//指向上一个
}ListNode;

动态申请内存节点函数

申请成功后将值赋给新节点的,后返回ListNode*类型的节点
如果申请内存失败将退出

ListNode* buyListNode(ListNodeDate x)
{
	ListNode* newListNode = (ListNode*)malloc(sizeof(ListNode));
	if (newListNode==NULL)
	{
		printf("申请内存失败!");
		exit(-1);//退出
	}
	newListNode->date = x;
	newListNode->next = NULL;
	newListNode->prev = NULL;

	return newListNode;
}

初始化函数

初始化一个头尾指向自己的head“哨兵位”头结点(不存储有效值)

ListNode* ListInit()
{

	ListNode* head = buyListNode(0);
	head->next = head;
	head->prev = head;

	return head;
}

实现尾插函

传入链表的head地址跟要尾插的值

void List_pushback(ListNode* head, ListNodeDate x)
{
//如果这个不指向什么还不为空,则结束程序
	assert(head);

	ListNode* tail = head->prev;
	ListNode* NewNode = buyListNode(x);

	tail->next = NewNode;
	NewNode->prev = tail;

	NewNode->next = head;
	head->prev = NewNode;
}

实现尾删函数

void List_popback(ListNode* head)
{
	assert(head);

	ListNode* tail = head->prev;
	ListNode* tail_prev = tail->prev;

	tail_prev->next = head;
	head->prev = tail_prev;
	free(tail);//清除malloc开辟的动态内存空间
	tail = NULL;//并置为空
}

实现打印函数

void List_printf(ListNode* head)
{
	assert(head);
	ListNode* cur = head->next;
	while (cur != head)
	{
		printf("%d ", cur->date);
		cur = cur->next;
	}
}

实现头插函数

void List_pushfront(ListNode* head, ListNodeDate x)
{
	assert(head);

	ListNode* tail = head->next;
	ListNode* NewNode = buyListNode(x);

	head->next = NewNode;
	NewNode->prev = head;

	NewNode->next = tail;
	tail->prev = NewNode;
}

实现头删函数

void List_popfront(ListNode* head)
{
	assert(head);

	ListNode* tail = head->next;
	ListNode* tail_next = tail->next;

	head->next = tail_next;
	tail_next->prev = head;

	free(tail);
	tail = NULL;
}

更多

还有一些函数例如
中间插如删除
查找替换

三、代码

list.h文件

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int ListNodeDate;

typedef struct ListNode
{
	ListNodeDate date;

	struct ListNode* next;
	struct ListNode* prev;
}ListNode;

//动态申请内存
ListNode* buyListNode(ListNodeDate x);
//初始化
ListNode* ListInit();
//打印
void List_printf(ListNode* head);
//尾插尾删
void List_pushback(ListNode* head, ListNodeDate x);
void List_popback(ListNode* head);
//头插头删
void List_pushfront(ListNode* head, ListNodeDate x);
void List_popfront(ListNode* head);

list.cpp文件

#include"List.h"

ListNode* buyListNode(ListNodeDate x)
{
	ListNode* newListNode = (ListNode*)malloc(sizeof(ListNode));
	if (newListNode==NULL)
	{
		printf("申请内存失败!");
		exit(-1);
	}
	newListNode->date = x;
	newListNode->next = NULL;
	newListNode->prev = NULL;

	return newListNode;
}

void List_pushback(ListNode* head, ListNodeDate x)
{
	assert(head);

	ListNode* tail = head->prev;
	ListNode* NewNode = buyListNode(x);

	tail->next = NewNode;
	NewNode->prev = tail;

	NewNode->next = head;
	head->prev = NewNode;
}

ListNode* ListInit()
{

	ListNode* head = buyListNode(0);
	head->next = head;
	head->prev = head;

	return head;
}

void List_printf(ListNode* head)
{
	assert(head);
	ListNode* cur = head->next;
	while (cur != head)
	{
		printf("%d ", cur->date);
		cur = cur->next;
	}
}

void List_popback(ListNode* head)
{
	assert(head);

	ListNode* tail = head->prev;
	ListNode* tail_prev = tail->prev;

	tail_prev->next = head;
	head->prev = tail_prev;
	free(tail);
	tail = NULL;
}

void List_pushfront(ListNode* head, ListNodeDate x)
{
	assert(head);

	ListNode* tail = head->next;
	ListNode* NewNode = buyListNode(x);

	head->next = NewNode;
	NewNode->prev = head;

	NewNode->next = tail;
	tail->prev = NewNode;
}

void List_popfront(ListNode* head)
{
	assert(head);

	ListNode* tail = head->next;
	ListNode* tail_next = tail->next;

	head->next = tail_next;
	tail_next->prev = head;

	free(tail);
	tail = NULL;
}

main.cpp文件

#include"List.h"

void test()
{
	ListNode* head = NULL;
	head = ListInit();
	List_pushback(head, 1);
	List_pushback(head, 2);
	List_pushback(head, 3);
	List_pushback(head, 4);
	List_popback(head);
	List_pushfront(head, 0);
	List_pushfront(head, -1);
	List_popfront(head);
	List_printf(head);
}

int main()
{
	test();

	return 0;
}