数据结构——单链表

概念与结构

概念:

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

链表结构:

结点

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

  • 结点的组成主要有两个部分:当前结点要保存的数据和保存下一个结点的地址。
  • 图中指针变量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;
}
相关推荐
Thanks_ks43 分钟前
深入链表剖析:从原理到 C 语言实现,涵盖单向、双向及循环链表全解析
数据结构·链表·c 语言·双向链表·单向链表·循环链表·算法与编程
moz与京1 小时前
【数据结构】字符串操作整理(C++)
开发语言·数据结构·c++
初遇你时动了情3 小时前
dart常用语法详解/数组list/map数据/class类详解
数据结构·flutter·list
@我漫长的孤独流浪5 小时前
数据结构测试模拟题(2)
数据结构·c++·算法
黑牛先生5 小时前
【数据结构】图的存储(邻接矩阵与邻接表)
数据结构
似水এ᭄往昔8 小时前
【数据结构】——二叉树--链式结构
数据结构·算法
闪电麦坤958 小时前
数据结构:栈(Stack)和堆(Heap)
数据结构
Musennn10 小时前
leetcode17.电话号码的字母组合:字符串映射与回溯的巧妙联动
java·数据结构·算法·leetcode
开压路机12 小时前
算法:滑动窗口
数据结构·算法