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

目录

  • [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. 顺序表与链表的区别

区别 顺序表 链表
物理空间上 物理空间上连续 逻辑上连续 ,但物理空间上不一定连续
随机插入时 可能需要进行大量挪动空间的操作,效率低 可以直接进行插入
扩容时 需要重新申请一段更大的新的连续的空间 利用碎片化的空间
应用场景 大量数据的存储,对存储元素的高频率访问 进行多次的插入删除操作
相关推荐
zander2584 小时前
4. 寻找两个正序数组的中位数:用分割点代替合并
数据结构·算法
敲上瘾5 小时前
redis常用数据类型与操作方法
数据结构·数据库·redis·缓存
牢姐与蒯5 小时前
c++高级数据结构之图(基本概念,存储结构,BFS,DFS,最小生成树)
数据结构·c++·
Tongzhi20266 小时前
考勤数据本地化存储:通芝科技无感考勤一体机的数据安全逻辑
大数据·数据结构·科技·均值算法·数据库开发·推荐算法
她说可以呀6 小时前
Spring-ai-Rag-多文件格式生成 List<Document>
数据结构·list
郝学胜_神的一滴8 小时前
干货版《算法导论》17:双数极值配对与卡牌手牌编码最优解
数据结构·算法
我不会插花弄玉9 小时前
10.list【由浅入深-C++】
数据结构·c++·list
星轨初途9 小时前
LeetCode 热题 100——day6 三数之和
数据结构·c++·算法·leetcode·职场和发展
wabs66619 小时前
关于图论【卡码网117.软件构建的思考】
数据结构·算法·软件构建·图论·卡码网
Tongzhi202620 小时前
从部署到运维:通芝科技无感考勤一体机的全流程效率解析
运维·数据结构·科技·算法·贪心算法