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

一、链表概述

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


二、单向链表

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.双向链表的创建,插入,删除,寻找,替换,销毁。

相关推荐
2401_841495642 小时前
【LeetCode刷题】对称二叉树
数据结构·python·算法·leetcode·二叉树··递归
飞机和胖和黄2 小时前
王道考研C语言第五周
c语言·考研·算法
市场部需要一个软件开发岗位2 小时前
一个无人机平台+算法监督平台的离线部署指南
java·python·算法·bash·无人机·持续部署
ygklwyf2 小时前
零基础薄纱树套树——高级数据结构的结合
算法·线段树·树状数组·树套树
Hello World . .2 小时前
排序算法:常用排序算法
c语言·数据结构·算法·vim·排序算法
寻寻觅觅☆3 小时前
东华OJ-基础题-86-字符串统计(C++)
开发语言·c++·算法
偷吃的耗子3 小时前
【CNN算法理解】:MNIST手写数字识别训练过程
算法·机器学习·cnn
念越3 小时前
从概念到实现:深入解析七大经典排序算法
java·算法·排序算法
虢薪3 小时前
双向链表与循环链表基础操作&进阶操作
数据结构·链表