数据结构——单链表

概念与结构

概念:

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

链表结构:

结点

与顺序表不同的是,链表里的每节"车厢"都是独立申请下来的空间,我们称之为"结点"。

  • 结点的组成主要有两个部分:当前结点要保存的数据和保存下一个结点的地址。
  • 图中指针变量plist保存的是第一个结点的地址,我们称*plist此时指向第一个结点,*如果我们希望plist指向第二个节点时,只需要修改plist保存的地址为0x00000B.
  • 链表中每个结点都是独立申请的(即需要插入数据时才去申请一块结点的空间),我们需要通过指针变量来保存下一个结点位置才能从当前结点找到下一个结点。

链表的性质

  • 链式机制在逻辑上是连续的,在物理结构上不一定连续。
  • 结点一般是从堆上申请的。
  • 从堆上申请来的空间,是按照一定策略分配出来的,每次申请的空间可能连续,可能不连续。

假设我们当前保存的结点为整型:

cpp 复制代码
struct SListNode
{
	int data;//结点数据
	struct SListNode* next;//指针变量:用来保存下一个结点的地址
};

当我们想要保存一个整型数据时,实际是向操作系统申请了一块内存,这个内存不仅要保存整型数据,也需要保存下一个结点的地址。

链表的打印

cpp 复制代码
typedef int SLDateType;
typedef struct SListNode
{
	SLDateType data;
	struct SListNode* next;
}SLTNode;
void SLPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		printf("%d", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}

当我们想要保存的数据类型为浮点型,字符型时,我们也可以改变。

链表的实现

接下来我们来实现这些函数

cpp 复制代码
// 动态申请一个节点
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位置之前插入?
//需要找到pos之前的位置
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);

// 在pos的前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x);
// 删除pos位置
//需要找到pos之前的位置
void SLTErase(SListNode** pphead, SListNode* pos);
void SLTDestroy(SListNode** pphead);
cpp 复制代码
//向操作系统申请一个新空间
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
cpp 复制代码
void SListPrint(SListNode* plist)
{
	SListNode* pcur = plist;
	while (pcur)
	{
		printf("%d ", pcur->data);
		pcur = pcur->next;

	}
	printf("\n");
}
cpp 复制代码
void SListPushBack(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* newnode = BuySListNode(x);
	//链表为空
	if (*pplist == NULL)
	{
		*pplist=newnode;
	}
	//链表不为空
	else
	{
		SListNode* ptail = *pplist;
		while (ptail->next!=NULL)
		{
			ptail = ptail->next;
		}
		ptail->next = newnode;
	}
	
}
cpp 复制代码
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* newnode = BuySListNode(x);
	newnode->next = *pplist;
	*pplist = newnode;
}
cpp 复制代码
void SListPopBack(SListNode** pplist)
{
	assert(pplist && *pplist);
	//只有一个结点
	if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* prev=NULL, * ptail=*pplist;
		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		free(ptail);
		ptail = NULL;
		prev->next = NULL;
	}
	
}
cpp 复制代码
void SListPopFront(SListNode** pplist)
{
	assert(pplist && *pplist);
	SListNode* pcur = *pplist;
	*pplist = pcur->next;
	free(pcur);
}
cpp 复制代码
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* pos = plist;
	while(pos)
	{
		if (pos->data == x)
		{
			return pos;	
		}
		pos = pos->data;
	}
	return NULL;
	
}
cpp 复制代码
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
cpp 复制代码
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{
	
	assert(pphead && *pphead && pos);
	SListNode* prev = *pphead;
//pos为第一个结点时
	if (pos == *pphead)
		SListPushFront(pphead, x);
	else
	{
		SListNode* newnode = BuySListNode(x);
		while (prev->next!= pos)
		{
			prev = prev->next;
		}
		newnode->next = pos;
		prev->next = newnode;
	}
}
cpp 复制代码
void SListEraseAfter(SListNode* pos)
{
	assert(pos && pos->next);
	SListNode* pcur = pos->next;
	pos->next = pcur->next;
	free(pcur);
	pcur = NULL;
}
cpp 复制代码
void SLTErase(SListNode** pphead, SListNode* pos)
{
	assert(pphead && *pphead && pos);
	if (pos == *pphead)
	{
		SListPopFront(pphead);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
	
}
void SLTDestroy(SListNode** pphead)
{
	assert(pphead);
	SListNode* pcur = *pphead;
	SListNode* prev = pcur;
	while (pcur)
	{
		pcur = pcur->next;
		free(prev);
		prev = pcur;
	}
	*pphead = NULL;
}
相关推荐
xin007hoyo5 小时前
算法笔记.染色法判断二分图
数据结构·笔记·算法
wuqingshun31415910 小时前
蓝桥杯 11. 打印大X
数据结构·算法·职场和发展·蓝桥杯·深度优先
wuqingshun31415911 小时前
蓝桥杯 2. 确定字符串是否是另一个的排列
数据结构·c++·算法·职场和发展·蓝桥杯
长沙火山12 小时前
9.ArkUI List的介绍和使用
数据结构·windows·list
AAAA劝导tx13 小时前
List--链表
数据结构·c++·笔记·链表·list
格格Code13 小时前
八大排序——冒泡排序/归并排序
数据结构·算法·排序算法
fantasy_413 小时前
LeetCode238☞除自身以外数组的乘积
java·数据结构·python·算法·leetcode
Phoebe鑫14 小时前
数据结构每日一题day12(链表)★★★★★
数据结构·算法·链表
八股文领域大手子15 小时前
深入浅出限流算法(三):追求极致精确的滑动日志
开发语言·数据结构·算法·leetcode·mybatis·哈希算法
新时代苦力工16 小时前
处理对象集合,输出Map<String, Map<String, List<MyObject>>>格式数据,无序组合键处理方法
java·数据结构·list