IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【数据结构】单链表 -> 正文阅读

[数据结构与算法]【数据结构】单链表


前言

为什么存在链表?因为顺序表存在一定问题,需要优化,而链表可以将顺序表的这些问题优化。

顺序表的问题:

  1. 中间/头部的插入删除,时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到
    200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

一、单链表的概念及结构

链表概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。

单链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

在这里插入图片描述

在这里插入图片描述
注意:

1.链式结构在逻辑上是连续的,在物理结构上不一定连续,也就是说实际上链表是没有那个箭头的连接的,只是结点的指针域存储着下一个结点的地址(结构体变量的地址),才得以在逻辑上是连续的。

2.结点,即一个结构体变量,一般是在堆上申请,在堆上申请的空间,是操作系统按一定的策略来分配的,两次动态开辟的空间可能连续,也可能不连续。

3.结点包括数据域和指针域,假设在32位系统上,结点的值域为int类型,则一个结点的大小为8个字节(指针变量的大小是4个字节)。

4.最后指向NULL

二、单链表的实现

1.单链表初始化

void TestSList()
{
	//单链表一般不需要初始化
	//头结点一般没有数据域,只有指针域为null
	SLTNode* pList = NULL;
	SListPrint(pList);
}

2.单链表打印

void SListPrint(SLTNode* phead)
{
	//这里不需要断言,因为phead有可能是空指针的
	//创建结构体辅助指针cur
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;//cur->next存的是下一个结点的地址,这样操作cur就从逻辑上移到下一个结点了
	}
	printf("NULL\n");
}

3.创建结点

//创建新结点
//返回类型为SLTNode*,即新的结点的地址
SLTNode* BuyNewnode(SLTDataType x)
{
	//创建结点:结点是在堆区创建的,这样出函数后,才不会被销毁
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	{                                                                                                                                                                                                             
		perror("mallo fail");
		exit(-1);//exit(0)表示程序正常退出;除了0之外,其他参数均代表程序异常退出,如:exit(1),exit(-1)。
		//但是在函数中就会有所区别,return会跳出函数,而exit会结束程序。
	}                  
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

4.单链表头插

//单链表头插
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
	//SLTNode newnode;我们不能定义局部变量的结构体结点,因为它出了作用域就销毁了
	SLTNode* newnode = BuyNewnode(x);
	newnode->next = *pphead;//phead接收的是pList的地址
	*pphead = newnode;
}

头插测试
在这里插入图片描述

5.单链表尾插

//单链表尾插
void SListPushBack(SLTNode** pphead, SLTDataType x)
{
	//传过来的是pList的地址,不是pList的值,所以可以断言
	assert(pphead);

	//尾插前要创建新结点
	SLTNode* newnode = BuyNewnode(x);

	//1.空
	if (*pphead == NULL)//即pList为NULL,还没创建新结点
	{
		//这里要注意一点:
		//*pphead就是pList,pList是指针,指针就是地址
		//也就是说pList就是下一个结点的地址
		*pphead = newnode;
	}
	//2.非空
	//(1)先找到最后一个结点,特征是指针域为NULL
	else
	{
		SLTNode* tail = *pphead;//第一个结点的地址
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		//当tail->next==NULL时
		//连接新的结点的地址
		tail->next = newnode;
	}
}

尾插测试
在这里插入图片描述

6.单链表头删

//头删
void SListPopFront(SLTNode** pphead)// 传pList的地址过来
{
	assert(pphead);

	//有可能删到最后,pList为NULL,就不能头删
	assert(*pphead != NULL);
	//保留头结点的地址
	SLTNode* del = *pphead;
	//让pList指针保存删除的头结点的下一个结点的地址
	*pphead = (*pphead)->next;
	//释放被头删的结点
	free(del);
	del = NULL;
}

在这里插入图片描述

7.单链表尾删

注意要分为一个结点和多个结点的情况

//尾删
void SListPopBack(SLTNode** pphead)
{
	assert(*pphead);

	//目标:找到尾部的结点
	//释放尾部结点的空间
	//让尾部结点的上一个结点的指针域为NULL

	//只有一个结点的情况
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		//写法1:只使用于有两个及两个以上的结点
		SLTNode* prev = NULL;
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		prev->next = NULL;
		free(tail);
		tail = NULL;
	}

	写法2:
	//SLTNode* tail = *pphead;
	//while (tail->next->next != NULL)
	//{
	//	tail = tail->next;
	//}
	//free(tail->next);
	//tail->next = NULL;
}

在这里插入图片描述

8.单链表销毁

注意有可能有结点,有可能没有结点

//销毁链表
void SListDestory(SLTNode** pphead)
{
	assert(pphead);

	SLTNode* cur = *pphead;
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

在这里插入图片描述

9.单链表查找

//链表的查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;//返回结点地址
		}
		cur = cur->next;
	}
	//找不到返回空指针
	return NULL;
}

测试结果

在这里插入图片描述

10.单链表插入

在这里插入图片描述

注意一定要先用单链表查找函数找到位置为pos的结点
特殊情况:要插入位置的是第一个结点
在pos之前插入

//链表插入:在pos之前插入
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)//在pos之前插入你
{
	assert(pphead);
	assert(pos);//要在pos的位置插入,所以pos不能为空

	//要插入的是第一个位置
	if (pos == *pphead)
	{
		SListPopFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		//找到pos的位置,和pos之前的结点prev的地址
		while (prev->next != pos)
		{
			prev = prev->next;
			//暴力检查:pos是否为NULL
			assert(prev);
		}
		//创建一个新结点
		SLTNode* newnode = BuyNewnode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

在pos之后插入

//在pos之后插入
void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = BuyNewnode(x);//先创建一个新结点
	newnode->next = pos->next;
	pos->next = newnode;
}

11.单链表删除

//删除pos的位置
void SListDele(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	//删除的是第一个结点
	if (*pphead == pos)
	{
		//调用头删
		SListPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		//找pos
		while (prev->next != pos)
		{
			prev = prev->next;
			//检查pos是否存在
			assert(prev);
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}                                      

删除pos后面的位置

//删除pos后面的位置
void SListDeleAfter(SLTNode* pos)
{
	assert(pos);

	if (pos->next == NULL)
	{
		return;
	}
	else
	{
		SLTNode* next = pos->next;
		pos->next = next->next;
		free(next);
	}
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 11:07:37  更:2022-08-06 11:11:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:38:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码