手搓带头双向循环链表(C语言)

目录

List.h

List.c

ListTest.c

测试示例

带头双向循环链表优劣分析


List.h

复制代码
#pragma once

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

typedef int LTDataType;

typedef struct ListNode
{
	struct ListNode* prev;
	struct ListNode* next;
	LTDataType data;
}ListNode;

//创建节点
ListNode* BuyListNode(LTDataType x);
//初始化
ListNode* ListInit();
//打印链表
void ListPrint(ListNode* phead);
//尾插
void ListPushBack(ListNode* phead, LTDataType x);
//尾删
void ListPopBack(ListNode* phead);
//销毁
void ListDistroy(ListNode* phead);
//头插
void ListPushFront(ListNode* phead, LTDataType x);
//头删
void ListPopFront(ListNode* phead);
//查找
ListNode* ListFind(ListNode* phead, LTDataType x);
//在pos位置之前插入
void ListInsert(ListNode* pos, LTDataType x);
//删除pos位置的值
void ListErase(ListNode* pos);

List.c

复制代码
#include "List.h"

//创建节点
ListNode* BuyListNode(LTDataType x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	//申请空间失败
	if (node == NULL)
	{
		perror("BuyListNode");
		exit(-1);
	}
	node->data = x;
	node->prev = NULL;
	node->next = NULL;
	
	return node;
}

//初始化
ListNode* ListInit()
{
	ListNode* phead = BuyListNode(-1);
	phead->prev = phead;
	phead->next = phead;

	return phead;
}

//打印链表
void ListPrint(ListNode* phead)
{
	assert(phead);

	ListNode* cur = phead->next;

	printf("phead<=>");
	while (cur != phead)
	{
		printf("%d<=>", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

//尾插
void ListPushBack(ListNode* phead, LTDataType x)
{
	assert(phead);

	ListNode* tail = phead->prev;
	ListNode* newnode = BuyListNode(x);

	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}

//尾删
void ListPopBack(ListNode* phead)
{
	assert(phead);
	assert(phead->prev != phead);

	ListNode* tailPrev = phead->prev->prev;
	free(phead->prev);
	tailPrev->next = phead;
	phead->prev = tailPrev;
}

//销毁
void ListDistroy(ListNode* phead)
{
	assert(phead);

	ListNode* cur = phead->next;
	ListNode* tmp = cur;

	while (cur != phead)
	{
		cur = cur->next;
		free(tmp);
		tmp = cur;
	}
	
	phead->prev = phead;
	phead->next = phead;
}

//头插
void ListPushFront(ListNode* phead, LTDataType x)
{
	assert(phead);

	ListNode* first = phead->next;
	ListNode* newnode = BuyListNode(x);

	newnode->next = first;
	first->prev = newnode;
	newnode->prev = phead;
	phead->next = newnode;
}

//头删
void ListPopFront(ListNode* phead)
{
	assert(phead);
	assert(phead->next != phead);

	ListNode* first = phead->next;
	ListNode* second = first->next;
	free(first);
	second->prev = phead;
	phead->next = second;
}

//查找
ListNode* ListFind(ListNode* phead, LTDataType x)
{
	assert(phead);

	ListNode* cur = phead->next;

	while (cur != phead)
	{
		if (cur->data == x)
			return cur;
		cur = cur->next;
	}

	return NULL;
}

//在pos位置之前插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);

	ListNode* posPrev = pos->prev;
	ListNode* newnode = BuyListNode(x);

	posPrev->next = newnode;
	newnode->prev = posPrev;
	newnode->next = pos;
	pos->prev = newnode;
}

//删除pos位置的值
void ListErase(ListNode* pos)
{
	assert(pos);

	ListNode* posPrev = pos->prev;
	ListNode* posNext = pos->next;
	free(pos);
	posPrev->next = posNext;
	posNext->prev = posPrev;
}

头插尾插复用:

复制代码
//在pos位置之前插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);

	ListNode* posPrev = pos->prev;
	ListNode* newnode = BuyListNode(x);

	posPrev->next = newnode;
	newnode->prev = posPrev;
	newnode->next = pos;
	pos->prev = newnode;
}

//头插
void ListPushFront(ListNode* phead, LTDataType x)
{
	ListInsert(phead->next, x);
}

//尾插
void ListPushBack(ListNode* phead, LTDataType x)
{
	ListInsert(phead, x);
}

头删尾删复用:

复制代码
//删除pos位置的值
void ListErase(ListNode* pos)
{
	assert(pos);

	ListNode* posPrev = pos->prev;
	ListNode* posNext = pos->next;
	free(pos);
	posPrev->next = posNext;
	posNext->prev = posPrev;
}

//头删
void ListPopFront(ListNode* phead)
{
    assert(phead->next != phead);

	ListErase(phead->next);
}

//尾删
void ListPopBack(ListNode* phead)
{
	assert(phead->prev != phead);
    
    ListErase(phead->prev);
	
}

ListTest.c

复制代码
#include "List.h"

void test1()
{
	ListNode* phead = NULL;
	//初始化
	phead = ListInit();
	ListPrint(phead);
	//测试尾插
	ListPushBack(phead, 1);
	ListPushBack(phead, 2);
	ListPushBack(phead, 3);
	ListPushBack(phead, 4);
	ListPushBack(phead, 5);
	ListPrint(phead);

	//测试尾删
	ListPopBack(phead);
	ListPrint(phead);
	ListPopBack(phead);
	ListPrint(phead);
	ListPopBack(phead);
	ListPrint(phead);
	ListPopBack(phead);
	ListPrint(phead);
	ListPopBack(phead);
	ListPrint(phead);
	/*ListPopBack(phead);
	ListPrint(phead);*/

	ListDistroy(phead);
}

void test2()
{
	ListNode* phead = NULL;
	//初始化
	phead = ListInit();
	ListPrint(phead);
	//测试头插
	ListPushFront(phead, 1);
	ListPushFront(phead, 2);
	ListPushFront(phead, 3);
	ListPushFront(phead, 4);
	ListPushFront(phead, 5);
	ListPrint(phead);

	//测试头删
	ListPopFront(phead);
	ListPrint(phead);
	ListPopFront(phead);
	ListPrint(phead);
	ListPopFront(phead);
	ListPrint(phead);
	ListPopFront(phead);
	ListPrint(phead);
	ListPopFront(phead);
	ListPrint(phead);
	/*ListPopFront(phead);
	ListPrint(phead);*/

	ListDistroy(phead);
}
void test3()
{
	ListNode* phead = NULL;
	//初始化
	phead = ListInit();
	ListPrint(phead);
	//测试在pos位置之前插入
	ListInsert(phead, 1);
	ListInsert(phead, 2);
	ListInsert(phead, 3);
	ListInsert(phead, 4);
	ListInsert(phead, 5);
	ListPrint(phead);
	ListInsert(phead->next, 6);
	ListInsert(phead->next, 7);
	ListInsert(phead->next, 8);
	ListInsert(phead->next, 9);
	ListInsert(phead->next, 10);
	ListPrint(phead);

	//测试删除pos位置的值
	ListNode* pos = ListFind(phead, 1);
	ListErase(pos);
	ListPrint(phead);

	pos = ListFind(phead, 5);
	ListErase(pos);
	ListPrint(phead);

	pos = ListFind(phead, 10);
	ListErase(pos);
	ListPrint(phead);
	ListDistroy(phead);
}
int main()
{
	//测试尾插尾删
	//test1();
	//测试头插头删
	//test2();
	//测试在pos位置插入删除
	test3();
	return 0;
}

测试示例

尾插尾删:

头插头删:

在pos位置插入删除:

带头双向循环链表优劣分析

|--------------|------------------|-----------------|
| 不同点 | 顺序表 | 链表 |
| 存储空间上 | 物理上一定连续 | 逻辑上连续,但物理上不一定连续 |
| 随机访问 | 支持O(1) | 不支持:O(N) |
| 任意位置插入或者删除元素 | 可能需要搬移元素,效率低O(N) | 只需修改指针指向 |
| 插入 | 动态顺序表,空间不够时需要扩容 | 没有容量的概念 |
| 应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |
| 缓存利用率 | 高 | 低 |

相关推荐
爱吃橘的橘猫几秒前
嵌入式系统与嵌入式 C 语言(2)
c语言·算法·嵌入式
235163 分钟前
【LeetCode】146. LRU 缓存
java·后端·算法·leetcode·链表·缓存·职场和发展
聪明的笨猪猪7 分钟前
Java Redis “运维”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
小张的博客之旅2 小时前
2025年“羊城杯”网络安全大赛 线上初赛 (WriteUp)
python·学习·网络安全
周杰伦_Jay2 小时前
【Java集合体系】全面解析:架构、原理与实战选型
java·开发语言·数据结构·链表·架构
~无忧花开~3 小时前
JavaScript学习笔记(二十八):JavaScript性能优化全攻略
开发语言·前端·javascript·笔记·学习·性能优化·js
机器学习之心3 小时前
PINN物理信息神经网络风电功率预测!引入物理先验知识嵌入学习的风电功率预测新范式!Matlab实现
神经网络·学习·matlab·风电功率预测·物理信息神经网络
tkevinjd3 小时前
反转链表及其应用(力扣2130)
数据结构·leetcode·链表
HalvmånEver4 小时前
红黑树实现与原理剖析(上篇):核心规则与插入平衡逻辑
数据结构·c++·学习·算法·红黑树
BreezeJuvenile4 小时前
外设模块学习(5)——DS18B20温度传感器(STM32)
stm32·嵌入式硬件·学习·温度传感器·ds18b20