前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【数据结构】单链表

【数据结构】单链表

作者头像
YoungMLet
发布2024-03-01 10:26:05
510
发布2024-03-01 10:26:05
举报
文章被收录于专栏:C++/LinuxC++/Linux
单链表

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

1. 函数的声明部分

代码语言:javascript
复制
		#pragma once
		#include <stdio.h>
		#include <stdlib.h>
		#include <assert.h>
		
		typedef int SLTDateType;
		
		typedef struct SingleListNode
		{
		
			SLTDateType data;
			struct SingleListNode* next;
		
		}SLTNode;
		
		
		//打印
		void SLTPrint(SLTNode* phead);
		
		//头插
		void SLTPushFront(SLTNode** pphead, SLTDateType x);
		
		//尾插
		void SLTPushBack(SLTNode** pphead, SLTDateType x);
		
		//头删
		void SLTPopFront(SLTNode** pphead);
		
		//尾删
		void SLTPopBack(SLTNode** pphead);
		
		//在pos位置之后插入x
		void SLTInsertAfter(SLTNode* pos, SLTDateType x);
		
		//删除pos位置之后的值
		void SLTEraseAfter(SLTNode* pos);
		
		//单链表查找
		SLTNode* SLTFind(SLTNode** pphead, SLTDateType x);

2. 函数的实现部分

由于头插,尾插等需要开辟一个节点,所以把开辟节点单独作为一个函数,需要开辟节点的时候直接调用;

代码语言:javascript
复制
		SLTNode* BuyListNode(SLTDateType x)
		{
			//开辟一个节点
			SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
			assert(newnode);
		
			//对newnode初始化
			newnode->data = x;
			newnode->next = NULL;
		
			return newnode;
		}

(1)打印链表

代码语言:javascript
复制
		//打印
		void SLTPrint(SLTNode* phead)
		{
			SLTNode* cur = phead;
			while (cur)
			{
				printf("%d->", cur->data);
				cur = cur->next;
			}
			printf("NULL\n");
		}

(2)头插

头插需要传二级指针,因为在调用函数SLTPushFront的时候,实参plist本来是结构体指针,现在头插需要改变链表的头,即需要传地址去改变plist的头;

如进行以下操作,值传递操作:

假设链表是如下形式:

当头插函数使用一级指针接收实参时,实参和形参同为一级指针,它们是同等类型的,它们在两个不同的栈空间,假如进行以下操作:

在这里插入图片描述
在这里插入图片描述

实际上phead并不会改变plist的值:

因为它们两个在不同的栈空间,phead只是plist的临时拷贝,只要出了SLTPushFront这个函数,栈帧被销毁,phead也被销毁了,但是phead的改变也没有改变plist的值,所以相当于什么也没有发生;

所以需要传二级指针,存放plist的指针,到函数内部需要解引用找到plist,再去改变plist的值,这样才能达到我们想要的效果;

代码语言:javascript
复制
		//头插
		void SLTPushFront(SLTNode** pphead, SLTDateType x)
		{
			SLTNode* newnode = BuyListNode(x);
			
			//将newnode的next更新为原来的头节点
			newnode->next = *pphead;
		
			//将newnode更新为新的头节点
			*pphead = newnode;
		
		}

(3)尾插

尾插的时候,当链表为空时,需要改变的是plist这个结构体指针,所以这个时候也是要传二级指针;当链表为非空链表时,需要改变的是结构体,所以不需要用到二级指针;但为了防止链表为空,这里干脆直接传二级指针;

代码语言:javascript
复制
		//尾插
		void SLTPushBack(SLTNode** pphead, SLTDateType x)
		{
		
			SLTNode* newnode = BuyListNode(x);
		
			//空链表
		 	if (*pphead == NULL)
			{
				*pphead = newnode;
			}
		
			//非空链表
			else
			{
				SLTNode* tail = *pphead;
		
				while (tail->next)
				{
					tail = tail->next;
				}
		
				tail->next = newnode;
			}
		}

(3)头删

代码语言:javascript
复制
		//头删
		void SLTPopFront(SLTNode** pphead)
		{
			//没有节点
			assert(*pphead);
		
			//一个节点
			if ((*pphead)->next == NULL)
			{
				free(*pphead);
				*pphead = NULL;
			}
		
			//多个节点
			else
			{
				SLTNode* cur = *pphead;
				*pphead = cur->next;
		
				free(cur);
				cur = NULL;
			}
		}

(4)尾删

代码语言:javascript
复制
		//尾删
		void SLTPopBack(SLTNode** pphead)
		{
			//空链表
			assert(*pphead);
		
			//一个节点
			if ((*pphead)->next == NULL)
			{
				free(*pphead);
				*pphead = NULL;
			}
		
			//多个节点
			else
			{
				SLTNode* tail = *pphead;
		
				while (tail->next->next)
				{
					tail = tail->next;
				}
		
				free(tail->next);
				tail->next = NULL;
			}
		}

(5)单链表的查找

代码语言:javascript
复制
		SLTNode* SLTFind(SLTNode* phead, SLTDateType x)
		{
			SLTNode* cur = phead;
		
			while (cur)
			{
				if (cur->data == x)
				{
					return cur;
				}
				cur = cur->next;	
			}
			return NULL;
		}

(6)删除pos位置之后的值

代码语言:javascript
复制
		void SLTEraseAfter(SLTNode* pos)
		{
			assert(pos && pos->next);
		
			SLTNode* cur = pos;
		
			cur->next = cur->next->next;
		}

(7)在pos位置之后插入x

代码语言:javascript
复制
		void SLTInsertAfter(SLTNode* pos, SLTDateType x)
		{
			SLTNode* cur = BuyListNode(x);
			assert(cur);
		
			cur->next = pos->next;
			pos->next = cur;
		}

3. 函数的测试部分

代码语言:javascript
复制
		#define _CRT_SECURE_NO_WARNINGS 1
		#include "Single List.h"
		
		int main()
		{
			SLTNode* plist = NULL;
		
			SLTPushFront(&plist, 2);
		
		
			SLTPushFront(&plist, 1);
		
			SLTPushBack(&plist, 3);
			SLTPushBack(&plist, 4);
			SLTPushBack(&plist, 5);
		
			//SLTPopFront(&plist);
			
		
			//SLTPopBack(&plist);
		
		
			//SLTInsertAfter(plist->next->next, 10);
		
		
			SLTEraseAfter(plist);
			
		
			SLTPrint(plist);
		
			
		
			SLTNode* ret = SLTFind(plist, 5);
			if (ret != NULL)
			{
				printf("%d->", ret->data);
			}
			else
			{
				printf("NULL\n");
			}
		
		
			SListDestroy(&plist);
		
			return 0;
		}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单链表
  • 1. 函数的声明部分
  • 2. 函数的实现部分
    • (1)打印链表
      • (2)头插
        • (3)尾插
          • (3)头删
            • (4)尾删
              • (5)单链表的查找
                • (6)删除pos位置之后的值
                  • (7)在pos位置之后插入x
                  • 3. 函数的测试部分
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档