数据结构——单链表

一、概念

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

在现实数据结构中:

1.链式结构在逻辑上是连续的,但在物理上不一定连续。

2.现实中的结点一般是从堆上申请出来的。

3.从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能连续,也可能不连续。

链表分类:

1.单向或双向

2.带头或不带头

3.循环或非循环

常用的链表结构为:无头单向非循环链表和带头双向循环链表。

二、结构体定义

//不带头单向非循环链表
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);// 单链表查找
void SListInsertAfter(SListNode* pos, SLTDateType x);// 单链表在pos位置之后插入x
void SListEraseAfter(SListNode* pos);// 单链表删除pos位置之后的值
void SListDestory(SListNode** plist);// 单链表的销毁

因为实现的是不带头结点的单链表,在函数中需要直接对指针进行操作,所以大部分操作函数传参都需要传递二级指针

1.动态申请一个个结点

通过malloc动态申请结点,并初始化数据域为x,指针域初始化为空。

SListNode* BuySListNode(SLTDateType x) {// 动态申请一个节点x
	SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
	if (newNode == NULL) {//申请失败
		assert(0);
		return NULL;
	}
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}

2.打印单链表

void SListPrint(SListNode* plist) {//打印单链表
	assert(plist);
	SListNode* node = plist;
	while (node) {
		printf("%d-->", node->data);
		node = node->next;
	}
	printf("NULL");
}

3.单链表尾插

对于不带头的单链表,每次插入都需要考虑到链表为空的特殊情况。

void SListPushBack(SListNode** pplist, SLTDateType x) {// 单链表尾插
	assert(pplist);
	SListNode* newNode = BuySListNode(x);//动态申请一个结点x
	if (*pplist == NULL) {//链表初始为空
		*pplist = newNode;
	}
	else {//链表非空
		SListNode* cur = *pplist;
		while (cur->next) {
			cur = cur->next;
		}
		cur->next = newNode;
	}
}

4.单链表头插

void SListPushFront(SListNode** pplist, SLTDateType x) {// 单链表的头插
	assert(*pplist);
	SListNode* newNode = BuySListNode(x);//动态申请一个结点x
	if (*pplist == NULL) {
		*pplist = newNode;
	}
	else {
		newNode->next = *pplist;
		*pplist = newNode;
	}
}

5.单链表尾删

对于不带头的单链表的删除,也需考虑链表为空和只有一个结点两种特殊情况。

void SListPopBack(SListNode** pplist) {// 单链表的尾删
	assert(pplist);
	if (*pplist == NULL) {//空链表
		return;
	}
	else if ((*pplist)->next == NULL) {//链表只有一个结点
		free(*pplist);
		*pplist = NULL;
	}
	else {
		SListNode* cur = *pplist;
		SListNode* prev = NULL;
		while (cur->next) {
			prev = cur;
			cur = cur->next;
		}
		free(cur);
		prev->next = NULL;
	}
}

6.单链表头删

void SListPopFront(SListNode** pplist) {// 单链表头删
	assert(*pplist);
	if (*pplist == NULL) {//空链表
		return;
	}
	else if ((*pplist)->next == NULL) {//链表只有一个结点
		free(*pplist);
		*pplist = NULL;
	}
	else {
		SListNode* cur = *pplist;
		*pplist = cur->next;
		free(cur);
	}
}

7.单链表查找

SListNode* SListFind(SListNode* plist, SLTDateType x) {// 单链表查找
	assert(plist);
	SListNode* cur = plist;
	while (cur) {
		if (cur->data == x) {
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

8.单链表任意位置插入

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

9.单链表任意位置删除

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

10.单链表销毁

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

四、代码测试

1.测试用例

void SListtest() {
	SListNode* plist = NULL;
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 4);
	SListPushBack(&plist, 5);
	SListPushFront(&plist, 0);
	SListInsertAfter(SListFind(plist, 3), 99);
	SListPrint(plist);
	printf("\n");
	SListEraseAfter(SListFind(plist, 3));
	SListPrint(plist);
	printf("\n");
	SListPopBack(&plist);
	SListPopFront(&plist);
	SListPrint(plist);
	SListDestory(&plist);
}

2.测试结果

 五、完整代码

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<assert.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);// 单链表查找
void SListInsertAfter(SListNode* pos, SLTDateType x);// 单链表在pos位置之后插入x
void SListEraseAfter(SListNode* pos);// 单链表删除pos位置之后的值
void SListDestory(SListNode** plist);// 单链表的销毁

void SListtest() {
	SListNode* plist = NULL;
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 4);
	SListPushBack(&plist, 5);
	SListPushFront(&plist, 0);
	SListInsertAfter(SListFind(plist, 3), 99);
	SListPrint(plist);
	printf("\n");
	SListEraseAfter(SListFind(plist, 3));
	SListPrint(plist);
	printf("\n");
	SListPopBack(&plist);
	SListPopFront(&plist);
	SListPrint(plist);
	SListDestory(&plist);
}

int main() {
	SListtest();
	return 0;
}

SListNode* BuySListNode(SLTDateType x) {// 动态申请一个节点x
	SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
	if (newNode == NULL) {//申请失败
		assert(0);
		return NULL;
	}
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}

void SListPrint(SListNode* plist) {//打印单链表
	assert(plist);
	SListNode* node = plist;
	while (node) {
		printf("%d-->", node->data);
		node = node->next;
	}
	printf("NULL");
}

void SListPushBack(SListNode** pplist, SLTDateType x) {// 单链表尾插
	assert(pplist);
	SListNode* newNode = BuySListNode(x);//动态申请一个结点x
	if (*pplist == NULL) {//链表初始为空
		*pplist = newNode;
	}
	else {//链表非空
		SListNode* cur = *pplist;
		while (cur->next) {
			cur = cur->next;
		}
		cur->next = newNode;
	}
}

void SListPushFront(SListNode** pplist, SLTDateType x) {// 单链表的头插
	assert(*pplist);
	SListNode* newNode = BuySListNode(x);//动态申请一个结点x
	if (*pplist == NULL) {
		*pplist = newNode;
	}
	else {
		newNode->next = *pplist;
		*pplist = newNode;
	}
}

void SListPopBack(SListNode** pplist) {// 单链表的尾删
	assert(pplist);
	if (*pplist == NULL) {//空链表
		return;
	}
	else if ((*pplist)->next == NULL) {//链表只有一个结点
		free(*pplist);
		*pplist = NULL;
	}
	else {
		SListNode* cur = *pplist;
		SListNode* prev = NULL;
		while (cur->next) {
			prev = cur;
			cur = cur->next;
		}
		free(cur);
		prev->next = NULL;
	}
}

void SListPopFront(SListNode** pplist) {// 单链表头删
	assert(*pplist);
	if (*pplist == NULL) {//空链表
		return;
	}
	else if ((*pplist)->next == NULL) {//链表只有一个结点
		free(*pplist);
		*pplist = NULL;
	}
	else {
		SListNode* cur = *pplist;
		*pplist = cur->next;
		free(cur);
	}
}

SListNode* SListFind(SListNode* plist, SLTDateType x) {// 单链表查找
	assert(plist);
	SListNode* cur = plist;
	while (cur) {
		if (cur->data == x) {
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

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

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

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hey小孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值