初阶数据结构:链表(补充:带头双向循环链表)

目录

  • [1. 带头双向循环链表的实现](#1. 带头双向循环链表的实现)
    • [1.1 引子](#1.1 引子)
    • [1.2 带头双向循环链表功能分析](#1.2 带头双向循环链表功能分析)
    • [1.3 带头双向循环链表的实现](#1.3 带头双向循环链表的实现)
      • [1.3.1 双向链表:存储数据的结构体](#1.3.1 双向链表:存储数据的结构体)
      • [1.3.2 双向链表:结点创建与链表数据清理](#1.3.2 双向链表:结点创建与链表数据清理)
      • [1.3.3 双向链表:数据插入与删除](#1.3.3 双向链表:数据插入与删除)
  • [2. 顺序表与链表的区别](#2. 顺序表与链表的区别)

1. 带头双向循环链表的实现

1.1 引子

单链表在实现随机插入与删除上效率低,实现困难。其结构上不够优秀与完美,由此我们引入新的一种更优的链表结构。带头双向循环链表。

1.2 带头双向循环链表功能分析

数据存储方式:

  1. 零碎的内存空间做结点

数据管理方式:

  1. 增(头插,尾插,随机插入):push_front,push_back,insert,insertafter
  2. 删(头删,尾删,随机删除):pop_front,pop_back,erase,eraseafter
  3. 改(指定数据的修改):modify
  4. 查(指定数据的查询):find

1.3 带头双向循环链表的实现

链表结构:

1.3.1 双向链表:存储数据的结构体

链表结点的构建:

c 复制代码
typedef struct ListNode
{
	struct ListNode* pre;
	struct ListNode* next;
	int val;
}ListNode;

1.3.2 双向链表:结点创建与链表数据清理

结点创建:

c 复制代码
ListNode* BuyNewNode(LTDataType val)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}

	newnode->val = val;
	newnode->next = newnode->pre = NULL;

	return newnode;
}

链表创建:

c 复制代码
ListNode* ListCreate()
{
	ListNode* head = BuyNewNode(0);
	head->next = head;
	head->pre = head;
	
	return head;
}

链表销毁:

c 复制代码
void ListDestory(ListNode* plist)
{
	assert(plist);

	ListNode* count = plist->next;
	while (count != plist)
	{
		plist->next = count->next;
		count->next->pre = plist;

		free(count);
		count = plist->next;
	}
}

1.3.3 双向链表:数据插入与删除

头插头删:

c 复制代码
//头插
void ListPushFront(ListNode* plist, LTDataType x)
{
	assert(plist);

	ListNode* newnode = BuyNewNode(x);
	newnode->next = plist->next;
	newnode->pre = plist;
	newnode->next->pre = newnode;
	plist->next = newnode;
}

//头删
void ListPopFront(ListNode* plist)
{
	assert(plist);
	//不为空
	assert(plist->next != plist);

	ListNode* cur = plist->next;
	plist->next = cur->next;
	cur->next->pre = plist;
	free(cur);
}

尾插,尾删:

c 复制代码
void ListPushBack(ListNode* plist, LTDataType x)
{
	assert(plist);

	ListNode* newnode = BuyNewNode(x);
	newnode->next = plist;
	newnode->pre = plist->pre;
	plist->pre->next = newnode;
	plist->pre = newnode;
}

void ListPopBack(ListNode* plist)
{
	assert(plist);
	//不为空
	assert(plist->next != plist);

	ListNode* cur = plist->pre;
	ListNode* pre = cur->pre;
	pre->next = plist;
	plist->pre = pre;
	free(cur);
}

随机插入,删除

c 复制代码
//寻找指定结点
ListNode* ListFind(ListNode* plist, LTDataType x)
{
	assert(plist);

	ListNode* cur = plist->next;
	while (cur != plist)
	{
		if (cur->val == x)
		{
			return cur;
		}

		cur = cur->next;
	}

	return NULL;
}

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

	ListNode* newnode = BuyNewNode(x);
	newnode->pre = pos->pre;
	newnode->next = pos;
	
	pos->pre->next = newnode;
	pos->pre = newnode;
}

//删除pos
void ListErase(ListNode* pos)
{
	assert(pos);

	ListNode* pre = pos->pre;
	ListNode* cur = pos->next;

	pre->next = cur;
	cur->pre = pre;

	free(pos);
}

2. 顺序表与链表的区别

区别 顺序表 链表
物理空间上 物理空间上连续 逻辑上连续 ,但物理空间上不一定连续
随机插入时 可能需要进行大量挪动空间的操作,效率低 可以直接进行插入
扩容时 需要重新申请一段更大的新的连续的空间 利用碎片化的空间
应用场景 大量数据的存储,对存储元素的高频率访问 进行多次的插入删除操作
相关推荐
库玛西5 小时前
攻克 408 数据结构:图论基石深度拆解(数学极值推演 + 存储内存剖析 + BFS/DFS 双核模板)
数据结构·算法·深度优先·广度优先·图搜索算法
m0_547486666 天前
《数据结构教程》全套 PPT课件2026
数据结构
tryxr6 天前
矩阵的几种基础变换
java·数据结构·算法·矩阵
mmmmath_36 天前
LeetCode.028.找出字符串中第一个匹配项的
数据结构·算法·leetcode
All for pursuit.6 天前
【栈-4】739.每日温度
数据结构·c++·算法·leetcode
All for pursuit.6 天前
【栈-5】84.柱状图中最大的矩形
数据结构·c++·算法·leetcode
渡我白衣6 天前
HttpRequest与HttpResponse的实现
服务器·数据结构·c++·人工智能·tcp/ip·机器学习·caffe
晴天的雨.9926 天前
【C++算法】和为s的两个数
开发语言·数据结构·c++·算法
无敌贵点大王6 天前
RTThread学习记录11——RT-Thread 设备模型吃透:UART/ADC/PWM/PIN 到底有什么区别?
c语言·stm32·学习·链表
淡海水6 天前
13-04-面试-源码级深度追问链
数据结构·unity·面试·c#·游戏引擎·源码·il2cpp