数据结构:单向链表和双向链表

一、链表概述

链表是一种线性数据结构,通过节点之间的指针链接实现数据存储,属于链式存储结构。与顺序表(数组)相比,链表在动态内存分配和插入删除操作上具有明显优势,但随机访问效率较低。


二、单向链表

1. 结构特点

  • 每个节点包含数据域和指向下一个节点的指针。

  • 只能从头节点开始顺序访问,不支持反向遍历。

2. 基本操作

  • 创建与销毁:动态分配节点内存,遍历释放。

cpp 复制代码
note_t *creat(void)
{
	note_t *pnew = NULL;
	pnew = malloc(sizeof(note_t));
	if(NULL == pnew)
	{
		perror("malloc fail");
		return NULL;
	}
	pnew -> pnext = NULL;
	return pnew;
}
int insert(note_t *phead,DateType TmpData)
{
	note_t *pnew = NULL;

	pnew = malloc(sizeof(note_t));
	if(NULL == pnew)
	{
		perror("fail to malloc");
		return -1;
	}
	pnew->Date = TmpData;
	pnew->pnext = phead->pnext;
	phead->pnext = pnew;

	return 0;
}
  • 插入:可在头、尾或任意位置插入,时间复杂度为 O(1)O(1)(头插)或 O(n)O(n)(中间插入)。

  • 删除:需定位前驱节点,修改指针指向,释放节点内存。

cpp 复制代码
int delete(note_t *phead,DateType TmpData)
{
	note_t *ptmp = NULL;
	note_t *pter = NULL;
	int cnt = 0;
	pter = phead;
	ptmp = phead->pnext;
	while(ptmp != NULL)
	{
		if(ptmp->Date == TmpData)
		{
			pter->pnext = ptmp->pnext;
			free(ptmp);
			cnt++;
			ptmp = pter->pnext;
		}
		else
		{
			ptmp = ptmp->pnext;
			pter = pter->pnext;
		}
	}


	return cnt;
}
  • 遍历 :从头节点开始,依次访问直到指针为 NULL

3. 进阶问题:环检测与处理

  • 判断是否有环:使用快慢指针(Floyd 判圈算法),若相遇则有环。

  • 求环长:从相遇点出发,指针再次回到该点所走过的节点数即为环长。

  • 找环入口:两指针分别从头节点和相遇点同步前进,再次相遇点即为环入口。

cpp 复制代码
int IsCircleList(Node_t *pHead, int *plen, Node_t **ppTmpNode)
{
	Node_t *pFast = NULL;
	Node_t *pSlow = NULL;
	Node_t *pMeetNode = NULL;
	int len = 0;

	pSlow = pFast = pHead->pNext;
	while (1)
	{
		pFast = pFast->pNext;
		if (NULL == pFast)
		{
			return 0;
		}
		pFast = pFast->pNext;
		if (NULL == pFast)
		{
			return 0;
		}

		pSlow = pSlow->pNext;
		if (pSlow == pFast)
		{
			pMeetNode = pSlow;
			break;
		}
	}
	
	pSlow = pMeetNode->pNext;
	len++;
	while (pSlow != pMeetNode)
	{
		len++;
		pSlow = pSlow->pNext;
	}
	*plen = len;

	pFast = pMeetNode;
	pSlow = pHead->pNext;
	while (pFast != pSlow)
	{
		pFast = pFast->pNext;
		pSlow = pSlow->pNext;
	}

	*ppTmpNode = pSlow;

	return 1;
}

三、双向链表

1. 结构特点

  • 节点除数据域外,包含前驱指针 prev 和后继指针 next

  • 支持双向遍历,可从任意节点向前或向后访问。

2. 操作优势

  • 插入与删除:在已知节点位置时,时间复杂度为 O(1)O(1),因可直接修改前驱和后继指针。

  • 遍历:支持正向与反向遍历,灵活性更高。

3. 实现要点

  • 创建与销毁:需同时维护双向指针关系。

  • 头插与尾插 :注意更新头节点或尾节点的 prevnext

  • 删除操作:需处理被删除节点前后节点的指针指向,避免断链。


四、链式存储与顺序存储对比

特性 顺序存储(数组) 链式存储(链表)
访问效率 O(1)O(1) O(n)O(n)
插入删除效率 O(n)O(n) O(1)O(1)(已知位置)
空间利用 连续空间,可能浪费 动态分配,利用率高
内存开销 仅数据 数据 + 指针

今日练习

1.双向链表的创建,插入,删除,寻找,替换,销毁。

相关推荐
岛雨QA9 小时前
链表「Java数据结构与算法学习笔记3」
数据结构·算法
Sunsets_Red9 小时前
P8277 [USACO22OPEN] Up Down Subsequence P 题解
c语言·c++·算法·c#·学习方法·洛谷·信息学竞赛
菜鸟小九9 小时前
redis原理篇(基本数据结构)
数据结构·数据库·redis
汉克老师9 小时前
GESP2023年12月认证C++二级( 第三部分编程题(2) 小杨的H字矩阵)
c++·算法·矩阵·循环结构·gesp二级·gesp2级
_Li.9 小时前
Simulink-螺旋桨动力模块
人工智能·算法·机器学习
Charlie_lll9 小时前
力扣解题-438. 找到字符串中所有字母异位词
后端·算法·leetcode
奶茶树9 小时前
【数据结构】红黑树
数据结构·c++·算法
AI周红伟9 小时前
周红伟:OpenAI 首席运营官,尚未真正看到人工智能渗透到企业业务流程中
人工智能·算法·性能优化
问好眼10 小时前
《算法竞赛进阶指南》0x01 位运算-2.增加模数
c++·算法·位运算·信息学奥赛
Full Stack Developme10 小时前
哈希是什么
算法·哈希算法