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

目录

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

区别 顺序表 链表
物理空间上 物理空间上连续 逻辑上连续 ,但物理空间上不一定连续
随机插入时 可能需要进行大量挪动空间的操作,效率低 可以直接进行插入
扩容时 需要重新申请一段更大的新的连续的空间 利用碎片化的空间
应用场景 大量数据的存储,对存储元素的高频率访问 进行多次的插入删除操作
相关推荐
墨染点香1 小时前
LeetCode 刷题【144. 二叉树的前序遍历】
数据结构·算法·leetcode
im_AMBER9 小时前
算法笔记 09
c语言·数据结构·c++·笔记·学习·算法·排序算法
凯芸呢9 小时前
Java中的数组(续)
java·开发语言·数据结构·算法·青少年编程·排序算法·idea
AI柠檬9 小时前
几种排序算法的实现和性能比较
数据结构·算法·c#·排序算法
zz07232012 小时前
数据结构 —— 栈
数据结构
Madison-No712 小时前
【C++】关于list的使用&&底层实现
数据结构·c++·stl·list·模拟实现
Bug退退退12312 小时前
ArrayList 与 LinkedList 的区别
java·数据结构·算法
2301_8079973814 小时前
代码随想录-day26
数据结构·c++·算法·leetcode
TL滕14 小时前
从0开始学算法——第一天(认识算法)
数据结构·笔记·学习·算法
代码雕刻家17 小时前
1.4.课设实验-数据结构-单链表-文教文化用品品牌2.0
c语言·数据结构