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

目录

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

区别 顺序表 链表
物理空间上 物理空间上连续 逻辑上连续 ,但物理空间上不一定连续
随机插入时 可能需要进行大量挪动空间的操作,效率低 可以直接进行插入
扩容时 需要重新申请一段更大的新的连续的空间 利用碎片化的空间
应用场景 大量数据的存储,对存储元素的高频率访问 进行多次的插入删除操作
相关推荐
jeffery8926 小时前
4056:【GESP2403八级】接竹竿
数据结构·c++·算法
一枝小雨8 小时前
【数据结构】排序算法全解析
数据结构·算法·排序算法
略知java的景初8 小时前
深入解析十大经典排序算法原理与实现
数据结构·算法·排序算法
liweiweili12610 小时前
main栈帧和func栈帧的关系
数据结构·算法
竹杖芒鞋轻胜马,夏天喜欢吃西瓜10 小时前
二叉树学习笔记
数据结构·笔记·学习
_OP_CHEN10 小时前
数据结构(C语言篇):(二)顺序表
c语言·数据结构·学习笔记·入门·顺序表·动态顺序表·静态顺序表
爱编程的鱼11 小时前
C# 数组&C# 多维数组
数据结构·算法·c#
上海迪士尼3513 小时前
除自身以外数组的乘积是什么意思
数据结构·算法
野犬寒鸦14 小时前
力扣hot100:字母异位词分组和最长连续序列(49,128)
java·数据结构·后端·算法·哈希算法
j_xxx404_15 小时前
数据结构:单链表的应用(力扣算法题)第一章
c语言·数据结构·算法·leetcode