服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++ 数据结构超详细讲解单链表

C++ 数据结构超详细讲解单链表

2022-10-28 13:33琅時壹 C/C++

这篇文章主要介绍了C++数据结构之单链表,链表是由一个个结点链结成的。结点包括数据域和指针域两部分,数据域用来存储数据元素的信息,指针域用来存储下一个结点的地址,更详细内容请需要的小伙伴参考下面文章内容

单链表

前言

上篇顺序表结尾了解了顺序表的诸多缺点,链表的特性很好的解决了这些问题,本期我们来认识单链表。

一、链表是什么

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

C++ 数据结构超详细讲解单链表

  • 由图,链式结构在逻辑上是连续的,但是物理上不一定连续
  • 显示中结点一般是从堆上申请出来的
  • 从堆上申请的空间,是按照一定的策略划分的,两次申请的空间,可能连续,可能不连续,见顺序表

C++ 数据结构超详细讲解单链表

链表的分类

链表也可以分为很多种

1. 单向或者双向
2. 带头或者不带头
3. 循环或非循环

C++ 数据结构超详细讲解单链表

C++ 数据结构超详细讲解单链表

C++ 数据结构超详细讲解单链表

我们最常用的还是无头单向非循环链表和带头双向循环链表 本篇我们实现无头单向非循环链表增删查改

 

二、链表的实现

基本结点结构

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

头文件

//llist.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);
// 单链表的销毁
void SListDestory(SListNode* plist);

动态申请一个节点

C++ 数据结构超详细讲解单链表

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)//申请失败
	{
		printf("malloc fail\n");
		exit(-1);
	}
	else
	{
		newnode->data = x;
		newnode->next = NULL;
	}
	return newnode;
}                     

单链表打印

链表单个结点中,data存储数据,next存储下一个结点的地址,可以通过next访问下一个结点

C++ 数据结构超详细讲解单链表

C++ 数据结构超详细讲解单链表

// 单链表打印
void SListPrint(SListNode* plist)
{
	SListNode* cur = plist;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;//访问下一个结点
	}
	printf("NULL\n");
}

单链表尾插

C++ 数据结构超详细讲解单链表

这里传入了头结点的地址的指针,是因为有可能要改变头结点的情况,传址调用幻术,如果只传入*plist,相当于只改变形参,实参不会有实际改变,通过pplist可以解决这个问题

C++ 数据结构超详细讲解单链表

// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
	SListNode* newnode = BuySListNode(x);
	if (*pplist == NULL)//空链表
	{
		*pplist = newnode;
	}
	else
	{
		SListNode* tail = *pplist;//遍历至最后插入
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

单链表的尾删

一前一后遍历,找到空后直接free(tail),将prev->next置空即可

C++ 数据结构超详细讲解单链表

// 单链表的尾删
void SListPopBack(SListNode** pplist)
{
	assert(pplist);
	if (*pplist == NULL)//空链表,无需删除
	{
		return;
	}
	else
	{
		SListNode* prev = NULL;
		SListNode* tail = *pplist;
		{
			while (tail->next != NULL)
			{
				prev = tail;
				tail = tail->next;
			}

			free(tail);
			tail = NULL;
			prev->next = NULL;
		}
	}
}

单链表的头插

C++ 数据结构超详细讲解单链表

有点绕,要多想想

// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* newnode = BuySListNode(x);
	newnode->next = *pplist;
	*pplist = newnode;
}

单链表头删

C++ 数据结构超详细讲解单链表

比较简单

// 单链表头删
void SListPopFront(SListNode** pplist)
{
	assert(pplist);
	if (*pplist == NULL)//链表为空
	{
		return;
	}
	else
	{
		SListNode* next = (*pplist)->next;
		free(*pplist);
		*pplist = next;
	}
}
// 单链表查找
遍历即可
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* cur = plist;
	while (cur != NULL)
	{
		if (cur->data = x)
		{
			return cur;
		}
		cur = cur->next;
	}

	retuen NULL;
}

*单链表在pos位置之后插入x

为什么不在pos之前插入,由于我们是单向链表,需要从头遍历查找pos,如果在pos之前插入,找到pos还需找到pos之前的地址,对所传参数不友好,所以我们一般在后插入

C++ 数据结构超详细讲解单链表

//单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

单链表删除pos位置之后的值 为什么不删除pos位置,同上,在逻辑上和传参不友好.

C++ 数据结构超详细讲解单链表

// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	SListNode* next = pos->next;
	if (next)
	{
		pos->next = next->next;
		free(next);
		next = NULL;
	}
}

单链表的销毁 链表不像顺序表连续删头就可以,由于链表是一个一个分散的结点,需要逐一删除

C++ 数据结构超详细讲解单链表

// 单链表的销毁
void SListDestory(SListNode** pplist)
{
	assert(*pplist);
	SListNode* cur = *pplist;
	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pplist = NULL;
}

总结

链表相比但链表难度提升不少,对c的掌握也变大,不清晰的地方要多想多画图。还请斧正

到此这篇关于C++ 数据结构超详细讲解单链表的文章就介绍到这了,更多相关C++ 单链表内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_62852431/article/details/123542116

延伸 · 阅读

精彩推荐
  • C/C++C++ 中"emplace_back" 与 "push_back" 的区别

    C++ 中"emplace_back" 与 "push_back" 的区别

    这篇文章主要介绍了C++ 中"emplace_back" 与 "push_back" 的区别的相关资料,需要的朋友可以参考下...

    lqh7482021-05-06
  • C/C++用C语言实现扫雷小游戏

    用C语言实现扫雷小游戏

    这篇文章主要为大家详细介绍了用C语言实现扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    技术新人王小明4302021-11-15
  • C/C++C语言解决百钱买百鸡问题

    C语言解决百钱买百鸡问题

    本文给大家分享的是一个经典的算法(百元百鸡)的C语言版的解决方法,使用的是比较偷懒的穷举法,有需要的小伙伴可以参考下。...

    C语言教程网12072021-03-25
  • C/C++c++ 完备的运行时类型信息(动态类型信息)

    c++ 完备的运行时类型信息(动态类型信息)

    这篇文章主要介绍了c++ 完备的运行时类型信息,需要的朋友可以参考下...

    huaxiazhihuo9182021-05-25
  • C/C++c/c++小游戏源代码

    c/c++小游戏源代码

    这篇文章主要介绍了c/c++小游戏源代码,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    恪愚6282021-11-01
  • C/C++C++实现简易五子棋游戏

    C++实现简易五子棋游戏

    这篇文章主要为大家详细介绍了C++实现简易五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    PlanetRT6902021-09-15
  • C/C++浅析C++中memset,memcpy,strcpy的区别

    浅析C++中memset,memcpy,strcpy的区别

    本篇文章是对C++中memset,memcpy,strcpy的区别进行了详细的分析介绍,需要的朋友参考下...

    C++教程网5282020-12-17
  • C/C++visual studio 建立dll类型工程、控制台程序

    visual studio 建立dll类型工程、控制台程序

    这篇文章主要介绍了visual studio 建立dll、控制台类型工程的相关知识,感兴趣的朋友跟随脚本之家小编一起学习吧...

    Victoria_W7372021-06-25