数据结构——单链表

概念与结构

概念:

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

链表结构:

结点

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

  • 结点的组成主要有两个部分:当前结点要保存的数据和保存下一个结点的地址。
  • 图中指针变量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;
}
相关推荐
Protein_zmm1 小时前
[数据结构]图krusakl算法实现
数据结构·算法
勤劳的进取家2 小时前
贪心算法的使用条件
数据结构·python·算法·贪心算法·排序算法·动态规划
南玖yy2 小时前
数据结构C语言练习(设计循环队列)
java·c语言·数据结构
butiehua02022 小时前
Go语言常用算法实现
数据结构·算法·golang·排序算法
luckycoding3 小时前
1631. 最小体力消耗路径
数据结构·算法·leetcode
.YY001.3 小时前
数据结构第一轮复习--第七章查找(包含课程代码)
数据结构·算法
星星火柴9363 小时前
数据结构:红黑树
数据结构
对方正在长头发丿3 小时前
P1162 填涂颜色(BFS)
数据结构·c++·算法·蓝桥杯·宽度优先
菜就多练,以前是以前,现在是现在3 小时前
Codeforces Round 1000 (Div. 2)
数据结构·c++·算法
gentle_ice3 小时前
找树左下角的值(DFS 深度优先搜索)| LeetCode 513
数据结构·算法·leetcode·深度优先