单链表-基本结构_插入查找

举报
芒果_Mango 发表于 2022/02/26 21:29:22 2022/02/26
【摘要】 「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」 不带头单向非循环单链表 顺序表的缺陷中间/头部的插入删除,时间复杂度为O(N)增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。 链表是什么...

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

不带头单向非循环单链表

顺序表的缺陷

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

链表是什么

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


顺序表:空间连续

链表:结点的地址随机

image-20211225185117361


逻辑结构和物理结构

image-20211025202243637

  • 现实中的结点一般都是从堆上申请出来的
  • 从堆上申请空间,是按照一定的策略来分配,两次申请的空间可能连续,也可能不连续

链表种类

  • 单向/双向
  • 带头/不带头
  • 循环/非循环

3者互相组合,又2*2*2 = 8种链表


00.基本结构

typedef int SLTDateType;

typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SLTNode;

带头与不带头的问题:

image-20211025203555135


  • ==不带头==:用头指针,指针指向的就是第一个结点
    • 因为函数中可能要修改一级指针plist,所以我们要传plist的地址进行操作,即要使用二级指针
  • ==带头==:plist指向的就是哨兵位结点,这个结点不存储有效数据。哨兵位的next,是第一个结点
    • 因为函数中不会修改plist,插入和删除都不会改变plist,因此不需要使用二级指针。插入删除改变的是plist指向的哨兵位的内容,plist本身不被修改

*函数内部要改变int类型的变量 ->传int **(传int的地址)

函数内部要改变int*类型变量->传int**(传int*的地址)


我们选择的是不带头的链表,也就是使用头指针,头指针指向的就是第一个结点


01.创建结点

每一个结点都是动态开辟的 动态开辟的变量放在堆区

1M = 1024KB = 1024*1024 Byte

栈区:8M 堆区:2M 栈的空间比堆的空间大

//创建新节点函数
SLTNode* BuyList(SLTDateType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);//退出整个程序
	}
	//开辟成功
	newnode->next = NULL;
	newnode->data = x;
	return newnode;
}

02.打印链表

由于打印不改变plist,所以可以传一级指针

  • 遍历打印即可,最后指针走到NULL结束
//打印 
//因为不改变头指针,所以传值传地址都可以
void SListPrint(SLTNode* phead)
{
	//遍历链表进行打印 
	//可以打印空链表 所以不能断言assert(phead !=NULL)
	SLTNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

03.尾插

  • 考虑链表为空的情况:直接把新节点赋给头指针
  • 多个结点:
    • ==方法==:遍历链表找到尾结点(特点:tail->next == NULL)
    • 尾结点的next链接新新节点
//尾插
void SListPushBack(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	SLTNode* newnode = BuyList(x);
	//情况1:当链表为空
	if (*pphead == NULL)
	{
		//头指针指向新结点
		*pphead = newnode;
	}
	//情况2:一个或者多个结点
	//找到尾结点
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next)
		{
			tail = tail->next;
		}
		//跳出循环时,tail就是尾结点
		//尾结点链接新结点
		tail->next = newnode;
	}
}

04.头插

头插要改变plist,所以传二级指针

  • 新节点的next链接第一个结点
  • 头指针指向新结点

当链表为空时,新节点的next指向NULL,然后头指针指向新结点 符合!不需要单独判断

//头插
void SListPushFront(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	SLTNode* newnode = BuyList(x);
	//新结点链接第一个结点
	newnode->next = *pphead;
	//新节点成为新的头
	*pphead = newnode;
	//当链表为空,一个或多个结点上述都正确
}

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。