前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据结构:线性表的链式储存

数据结构:线性表的链式储存

作者头像
编程交流
发布2024-05-11 17:58:34
630
发布2024-05-11 17:58:34
举报
文章被收录于专栏:编程编程

🌈个人主页:Rookie Maker 🔥 系列专栏:数据结构 🏆🏆关注博主,随时获取更多关于IT的优质内容!🏆🏆


😀欢迎来到我的代码世界~ 😁 喜欢的小伙伴记得一键三连哦 ૮(˶ᵔ ᵕ ᵔ˶)ა


一.线性表的链式储存

链表:线性表的链式储存方式,逻辑结构不一定连续,物理结构不一定连续

描述:由数据域和指针域组成

二.单链表

介绍:

由指针域和数据域组成,头指针,头结点,头结点中存储的首元素的地址

可以用头指针命名

1.优缺点

🔥任意位置插入删除,时间复杂度小 🔥没有增容问题,插入一个开辟一个空间

🔥不支持随机访问

2.创建​

代码语言:javascript
复制
//定义链表
typedef int SLTDataType;//数值域
//链表是由节点组成
typedef struct SListNode
{
	SLTDataType data;//int data
	struct  SListNode* next;//它用来存储当前节点的下一个节点的地址
}SLTNode;//

3.打印

代码语言:javascript
复制
void SLTPrint(SLTNode* phead) {
	SLTNode* pcur = phead;//头指针
	while (pcur)//pcur不为空!
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;//依次找到下一个结点
	}
	printf("NULL\n");
}

4.申请空间

代码语言:javascript
复制
SLTNode* SLTBuyNode(SLTDataType x) {
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL) {
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

4.增加元素

尾插:​

代码语言:javascript
复制
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
	assert(pphead);

	SLTNode* newnode = SLTBuyNode(x);

	//链表为空,新节点作为phead
	if (*pphead == NULL) {
		*pphead = newnode;
		return;
	}
	//链表不为空,找尾节点
	SLTNode* ptail = *pphead;
	while (ptail->next)
	{
		ptail = ptail->next;
	}
	//ptail就是尾节点
	ptail->next = newnode;
}

头插:

代码语言:javascript
复制
void SLTPushFront(SLTNode** pphead, SLTDataType x) {
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);

	//newnode *pphead
	newnode->next = *pphead;
	*pphead = newnode;
}

在指定位置插入​

代码语言:javascript
复制
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) {
	assert(pphead);
	assert(pos);
	//要加上链表不能为空
	assert(*pphead);

	SLTNode* newnode = SLTBuyNode(x);
	//pos刚好是头结点
	if (pos == *pphead) {
		//头插
		SLTPushFront(pphead, x);
		return;
	}

	//pos不是头结点的情况
	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	//prev -> newnode -> pos
	prev->next = newnode;
	newnode->next = pos;
}

5.删除元素

尾删​

代码语言:javascript
复制
void SLTPopBack(SLTNode** pphead) {
	assert(pphead);
	//链表不能为空
	assert(*pphead);
	//链表不为空
	//链表只有一个节点,有多个节点
	if ((*pphead)->next == NULL) {
		free(*pphead);
		*pphead = NULL;
		return;
	}
	SLTNode* ptail = *pphead;
	SLTNode* prev = NULL;
	while (ptail->next)
	{
		prev = ptail;
		ptail = ptail->next;
	}
	prev->next = NULL;
	//销毁尾结点
	free(ptail);
	ptail = NULL;
}

头删​

代码语言:javascript
复制
void SLTPopFront(SLTNode** pphead) {
	assert(pphead);
	//链表不能为空
	assert(*pphead);
	//让第二个节点成为新的头
	//把旧的头结点释放掉
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

🔥指定位置删除:注意删除的逻辑​

代码语言:javascript
复制
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos) {
	assert(pphead);
	assert(*pphead);
	assert(pos);

	//pos刚好是头结点,没有前驱节点,执行头删
	if (*pphead == pos) {
		//头删
		SLTPopFront(pphead);
		return;
	}

	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	//prev pos pos->next
	prev->next = pos->next;
	free(pos);
	pos = NULL;
}
void SLTEraseAfter(SLTNode* pos) {
	assert(pos);
	//pos->next不能为空
	assert(pos->next);

	//pos  pos->next  pos->next->next
	SLTNode* del = pos->next;
	pos->next = pos->next->next;
	free(del);
	del = NULL;
}

6.修改元素

代码语言:javascript
复制
//给一个数据,找到这个数据所在的节点,并用新数据修改
void SListChangeDate(SLTNode*pphead, SLTDataType x, SLTDataType y)
//不需要改变节点的地址,所以值传递即可 
//x是查找的数据,y是新的数据,用来修改查找的数据                                              
{
	SLTNode*cru = pphead;
	while (cru != NULL)//如果没有节点,根本不会进入循环去找
	{
		if (cru->data == x)
		{
			cru->data = y;
			break;//修改完数据后,就跳出循环
		}
		else
		{
			cru = cru->next;
		}
	}
	if (cru == NULL)//如果循环完单链表,没有找到要修改的那个数据
	{
		printf("要修改的数据不存在,请重新修改数据\n");
	}
	else
	{
		printf("修改成功\n");
	}
}

7.查找元素

代码语言:javascript
复制
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x) {
	assert(pphead);
	//遍历链表 
	SLTNode* pcur = *pphead;
	while (pcur) //pcur != NULL
	{
		if (pcur->data == x) {
			return pcur;
		}
		pcur = pcur->next;
	}
	//没有找到
	return NULL;
}

8.销毁链表​

代码语言:javascript
复制
void SListDesTroy(SLTNode** pphead) {
	assert(pphead);
	assert(*pphead);

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

三.双向链表

1.注意

🔥带头双向循环链表

🔥当链表中只要头节点的时候,为空链表

🔥头节点是不能删除的,指向可以改变

🔥不需要改变头节点的指向,不需要传二级指针

🔥二级指针对实参会产生影响 ​

2.创建

代码语言:javascript
复制
typedef int LTDataType;
typedef struct ListNode {
	LTDataType data;
	struct ListNode* prev;
	struct ListNode* next;
}LTNode;

3.打印

代码语言:javascript
复制
LTNode* LTInit() {
	LTNode* phead = LTBuyNode(-1);
	return phead;
}

4.增加元素

尾插(不需要找尾操作)

代码语言:javascript
复制
//尾插
void LTPushBack(LTNode* phead, LTDataType x) {
	assert(phead);
	LTNode* newnode = LTBuyNode(x);
	//phead phead->prev(ptail)  newnode
	newnode->next = phead;
	newnode->prev = phead->prev;

	phead->prev->next = newnode;
	phead->prev = newnode;
}
代码语言:javascript
复制
//头插
void LTPushFront(LTNode* phead, LTDataType x) {
	assert(phead);

	LTNode* newnode = LTBuyNode(x);
	//phead newnode phead->next
	newnode->next = phead->next;
	newnode->prev = phead;

	phead->next->prev = newnode;
	phead->next = newnode;
}

任意位置插入

代码语言:javascript
复制
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x) {
	assert(pos);
	LTNode* newnode = LTBuyNode(x);
	//pos newnode pos->next
	newnode->next = pos->next;
	newnode->prev = pos;

	pos->next->prev = newnode;
	pos->next = newnode;
}
//删除pos位置的数据
void LTErase(LTNode* pos) {
	assert(pos);

	//pos->prev pos  pos->next
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;

	free(pos);
	pos = NULL;
}

5.删除元素

头删

代码语言:javascript
复制
void LTPopFront(LTNode* phead) {
	assert(phead);
	assert(phead->next != phead);

	LTNode* del = phead->next;
	LTNode* next = del->next;

	//phead del next
	next->prev = phead;
	phead->next = next;

	free(del);
	del = NULL;
}

尾删

代码语言:javascript
复制
void LTPopBack(LTNode* phead) {
	assert(phead);
	//链表为空:只有一个哨兵位节点
	assert(phead->next != phead);

	LTNode* del = phead->prev;
	LTNode* prev = del->prev;

	prev->next = phead;
	phead->prev = prev;

	free(del);
	del = NULL;
}

任意位置删除

代码语言:javascript
复制
void LTErase(LTNode* pos) {
	assert(pos);

	//pos->prev pos  pos->next
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;

	free(pos);
	pos = NULL;
}

6.修改元素

代码语言:javascript
复制
void DeleteNode(LTNode** pHead, LTNode* toBeDeleted) {
    if (pHead == NULL || toBeDeleted == NULL) {
        return;
    }

    LTNode* head = *pHead;

    // 要删除的节点是头节点
    if (head == toBeDeleted) {
        *pHead = toBeDeleted->next;
    }
    
    // 调整前驱节点的next指针
    if (toBeDeleted->prev != NULL) {
        toBeDeleted->prev->next = toBeDeleted->next;
    }
    
    // 调整后继节点的prev指针
    if (toBeDeleted->next != NULL) {
        toBeDeleted->next->prev = toBeDeleted->prev;
    }
    
    free(toBeDeleted);
}

7.查找元素

代码语言:javascript
复制
LTNode* LTFind(LTNode* phead, LTDataType x) {
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		if (pcur->data == x) {
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

8.销毁链表

代码语言:javascript
复制
void LTDesTroy(LTNode* phead) {
	//哨兵位不能为空
	assert(phead);

	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		LTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	//链表中只有一个哨兵位
	free(phead);
	phead = NULL;
}

🎁🎁🎁今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,您的支持就是我前进的动力!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.线性表的链式储存
  • 二.单链表
    • 1.优缺点
      • 2.创建​
        • 3.打印
          • 4.申请空间
            • 4.增加元素
              • 5.删除元素
                • 6.修改元素
                  • 7.查找元素
                    • 8.销毁链表​
                    • 三.双向链表
                      • 1.注意
                        • 2.创建
                          • 3.打印
                            • 4.增加元素
                              • 5.删除元素
                                • 6.修改元素
                                  • 7.查找元素
                                    • 8.销毁链表
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档