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

一、链表概述

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


二、单向链表

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

相关推荐
江畔柳前堤8 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Doraemomo9 小时前
数据结构-环形链表
java·数据结构·链表
Forever Nore10 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考11 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX12 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面12 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号13 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽13 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI13 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
MC皮蛋侠客14 小时前
Redis 系列(一):全景与最小闭环——从 `SET` 命令到内存数据结构
数据结构·数据库·redis