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

目录

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

区别 顺序表 链表
物理空间上 物理空间上连续 逻辑上连续 ,但物理空间上不一定连续
随机插入时 可能需要进行大量挪动空间的操作,效率低 可以直接进行插入
扩容时 需要重新申请一段更大的新的连续的空间 利用碎片化的空间
应用场景 大量数据的存储,对存储元素的高频率访问 进行多次的插入删除操作
相关推荐
艾莉丝努力练剑3 小时前
【数据结构与算法】数据结构初阶:详解顺序表和链表(四)——单链表(下)
c语言·开发语言·数据结构·学习·算法·链表
笑衬人心。5 小时前
Hashtable 与 HashMap 的区别笔记
java·数据结构·笔记
秋说5 小时前
【PTA数据结构 | C语言版】根据层序序列重构二叉树
c语言·数据结构·算法
秋说7 小时前
【PTA数据结构 | C语言版】前序遍历二叉树
c语言·数据结构·算法
hy.z_7778 小时前
【数据结构】反射、枚举 和 lambda表达式
android·java·数据结构
秋说8 小时前
【PTA数据结构 | C语言版】二叉树层序序列化
c语言·数据结构·算法
xiaofann_8 小时前
【数据结构】单链表练习(有环)
数据结构
NuyoahC9 小时前
笔试——Day9
数据结构·c++·笔试
共享家95279 小时前
排序算法实战(上)
数据结构·算法·排序算法
abigale0311 小时前
JavaScript数据结构&算法
javascript·数据结构·算法