当前位置: 首页 > news >正文

单链表的概念,结构和优缺点

1. 概念

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

2. 单链表的结构

单链表是由一系列节点组成的线性结构,每个结点包含两个域。:数据域和指针域。

数据域用来存储数据,指针域用来存储下一个结点的指针。单链表的头结点指向第一个结点,最后一个结点的指针域为空。

一个结点的结构:

逻辑结构:为了方便形象理解,想象出来的。

物理结构:实际内存中,真实的样子。

1.3 单链表的优缺点

优点:

1. 插入和删除操作效率高(只需修改指针的指向)

2. 空间利用率高(不需要预先分配空间)

3. 长度可变

缺点:

1. 随机访问效率低(只能挨个遍历)

2. 存储空间浪费(每个结点包含数据和指针)

3. 链接信息的丢失 (无法访问前一个节点)

2. 单链表的实现

单链表各接口函数

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;//这样做的目的是为了增加代码的可读性和可维护性,以及提高代码的可移植性,
//因为如果将来需要更改 SLTDataType 的类型,只需要在 typedef 语句中修改一处即可,
// 如果我们在程序的其他地方需要修改 SLTDataType 的类型,
//只需在 typedef 语句中修改 int 为其他类型即可,不需要修改其他代码。
//typedef int SLTADataType;
 
typedef struct SListNode //--single Linked List
{
	SLTDataType data;//成员变量
	struct SListNode* next;
}SLTNode;
 
void SLTPrint(SLTNode* phead);
void SLPushFront(SLTNode** pphead, SLTDataType x);//头部插入
void SLPushBack(SLTNode** pphead, SLTDataType x);//尾部插入
 
void SLPopFront(SLTNode** pphead);//头部删除
void SLPopBack(SLTNode** pphead);//尾部删除
 
//单链表查找
SLTNode* STFind(SLTNode* phead, SLTDataType x);
 
//单链表pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//单链表pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);
//单链表pos位置删除
void SLErase(SLTNode** pphead, SLTNode* pos);
//单链表pos之后删除
void SLEraseAfter(SLTNode* phead);

2.1 结点的定义

单链表的英文为:Single linked list --简写为SL

而顺序表的英文是:Sequence table -- 简写为Seq

结点的英文为:node

typedef int SLTDataType;
typedef struct SListNode //--single Linked List
{
	SLTDataType data;//成员变量
	struct SListNode* next;
}SLTNode;

2.2 链表的打印

//函数的作用是遍历单链表,并将每个节点的数据元素打印到屏幕上。
void SLTPrint(SLTNode* phead)//参数是一个指向 SLTNode 类型的指针 phead,表示单链表的头节点。
{
	SLTNode* cur = phead;//头结点存储的地址给cur指针。
	while (cur != NULL)//使用一个while循环对单链表进行遍历,循环条件为 cur 不为 NULL。
	{    		
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

2.3 创建一个新节点

SLTNode* BuyLTNode(SLTDataType x)//表示要创建的节点的数据元素。
//函数的作用是创建一个新的单链表节点,并将其初始化为包含数据元素 x 的节点。
{ 
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	
	newnode->data = x;
	newnode->next = NULL;
	return newnode;//返回的是一个结点的地址
}

2.4 单链表尾插

void SLPushBack(SLTNode** pphead, SLTDataType x)//尾插的本质是让上一个结点链接下一个结点
{
	SLTNode* newnode = BuyLTNode(x);
	// 1、空链表
	// 2、非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		    tail->next = newnode;
	}
 
}

2.5 单链表头插

void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);
 
	newnode->next = *pphead;
	*pphead = newnode;
}

2.6 单链表头删

void SPopFront(SLTNode** pphead)
{
	//没有节点
	//暴力检查
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//多个节点
	else
	{
		SLTNode* del = *pphead;//相当于一个标记,删掉的标记
		//写法一
		//*pphead = del->next;
		//写法二 
		*pphead = (*pphead)->next;
		free(del);
	}
 
 
 
}

2.7 单链表尾删

void SLPopBack(SLTNode** pphead)
{
	//没有节点(空链表)
	//暴力检查
	assert(*pphead);
	//一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}//多个节点
	else
	{
		SLTNode* prev = NULL;
		SLTNode* tail = *pphead;
		//找尾
		//方法一
		/*while (tail->next)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		prev->next = NULL;*/
 
		//方法二
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}
 
		free(tail->next);
		tail->next = NULL;
	}
}

2.8 单链表查找/修改某个值

SLTNode* STFind(SLTNode* phead, SLTDataType x)
{
	//assert(phead);
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

2.9 单链表在pos之前插入

void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);//&plist
	assert(pos);
	//assert(*pphead);
	//一个节点
	if (*pphead == NULL)
	{
		SLPushFront(pphead, x);
	}
	else//多个节点
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

2.10 单链表在pos之后插入

void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
 
	SLTNode* newnode = BuyLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

2.11 单链表删除pos的值

void SLErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);
 
	if (pos == *pphead)
	{
		SLPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next!=pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

2.12 单链表删除pos之后的值

void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	SLTNode* next= pos->next;
	pos->next = next->next;
	free(next);
}

相关文章:

  • 使用Python和OpenCV实现图像像素压缩与解压
  • Llama3.0论文学习笔记: The Llama 3 Herd of Models
  • 硬件实用技巧:核心板与底板之间的连接方式:DIP、板对板连接器、金手指和邮票孔
  • volatile关键字
  • 贝壳和鹅卵石分类数据集4250张2类别
  • ReactiveSwift模拟登录功能
  • Java+数据可视化的红酒信息分享系统(程序+论文+讲解+安装+调试+售后等)
  • C++17中的LegacyContiguousIterator(连续迭代器)
  • SNARKs 和 UTXO链的未来
  • 【Javascript Day13、14、15、16】
  • 【练习】【双指针】力扣热题100 283. 移动零
  • 安全筑基,智能赋能:BeeWorks IM引领企业协同新纪元
  • 回文数:简单问题中的多种优化思路
  • 蓝桥杯篇---IAP15F2K61S2定时器
  • 开业盛典活动策划方案拆解
  • Django中数据库迁移命令
  • pyqt写一个待办程序
  • 惠普HP Color LaserJet CP1215/1210彩色打印机打印校准方法
  • 比较5点结构的减一对称性
  • KT1025A蓝牙音频芯片歌名歌词ID3显示芯片的功能说明
  • 巴防空系统击落印度无人机,印称巴方违反停火协议
  • 告别户口本!今天起婚姻登记实现全国通办
  • 竞彩湃|霍芬海姆看到保级曙光,AC米兰专注于意大利杯
  • 中日有关部门就日本水产品输华问题进行第三次谈判,外交部回应
  • 纽约大学朗格尼医学中心的转型带来哪些启示?
  • 苹果Safari浏览器上的搜索量首次下降