【零基础学数据结构】链表

目录

1.链表的概念

[​编辑 2.链表的雏形](#编辑 2.链表的雏形)

[​编辑 3.链表的组成](#编辑 3.链表的组成)

[​编辑 4.链表代码](#编辑 4.链表代码)

4.1创建节点

4.2链表的打印

4.3链表的尾插

4.4链表的头插

4.5链表的尾删

4.6链表的头删

4.7链表的查找

4.8链表在指定位置之前插⼊数据

4.9链表在指定位置之后插⼊数据

4.9-1删除pos节点

4.9-2删除pos之后的节点

4.9-3销毁链表

补充:测试文件:


1.链表的概念

2.链表的雏形

3.链表的组成

4.链表代码

创建准备;

  • SListNode.h文件
  • SListNode.c文件
  • text.c文件

4.1创建节点

数据+指向下一个节点的指针

cpp 复制代码
// 首先定义数据的类型,方便后续更改
typedef int SLTNodeDataType;

// 创建节点
typedef struct SListNode
{
	SLTNodeDataType data; // 存储数据
	struct SListNode* next;// 指向下一个节点的指针
}SLTNode;

4.2链表的打印

头文件声明:

cpp 复制代码
void SLTPrint(SLTNode* phead);

执行文件代码实现:

cpp 复制代码
// 链表的打印
void SLTPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;// 保证phead指向的位置是收节点,方便后续再次遍历
	while (pcur)// 等价于 pcur != NULL;
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}

4.3链表的尾插

头文件声明:

cpp 复制代码
void SLTPushBack(SLTNode** pphead, SLTNodeDataType x);
cpp 复制代码
// 创建新的节点
SLTNode* SLTBuyNode(SLTNodeDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (NULL == newnode)
	{
		perror("SLTBuyNode malloc err!");
		exit(1);
	}

	// 创建节点成功
	newnode->data = x;
	newnode->next = NULL;

	// 返回
	return newnode;
}

执行文件代码实现:

cpp 复制代码
// 链表的尾插
void SLTPushBack(SLTNode** pphead, SLTNodeDataType x)
{
	// 传参不可为空
	assert(pphead);

	// 创建一个新的节点
	SLTNode* newnode = SLTBuyNode(x);

	// 空链表和非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{

		// 找尾巴
		SLTNode* ptail = *pphead;
		while (ptail->next) // 等价于ptail->next !=NULL;
		{
			ptail = ptail->next;
		}

		// 找到尾巴,开始连接
		ptail->next = newnode;
	}
	
}

4.4链表的头插

头文件声明:

cpp 复制代码
// 链表的头插
void SLTPushFront(SLTNode** pphead, SLTNodeDataType x);

执行文件代码实现:

cpp 复制代码
// 链表的头插
void SLTPushFront(SLTNode** pphead, SLTNodeDataType x)
{
	// 传参不可为空
	assert(pphead);

	// 创建一个新的节点
	SLTNode* newnode = SLTBuyNode(x);

	// 头插
	newnode->next = *pphead;
	*pphead = newnode;
}

4.5链表的尾删

头文件声明:

cpp 复制代码
void SLTPopBack(SLTNode** pphead);

执行文件代码实现:

cpp 复制代码
// 链表的尾删
void SLTPopBack(SLTNode** pphead)
{
	// 链表不可以为空,传参不可为空
	assert(pphead && *pphead);

	// 链表有一个节点和多个节点
	// 一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else //多个节点
	{
		// 找尾
		SLTNode* prev = *pphead;
		SLTNode* ptail = *pphead;

		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}

		free(ptail); // 释放空间
		ptail = NULL;// 防止野指针
		prev->next = NULL;
	}
	
}

4.6链表的头删

头文件声明:

cpp 复制代码
void SLTPopFront(SLTNode** pphead);

执行文件代码实现:

cpp 复制代码
// 链表的头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

4.7链表的查找

头文件声明:

cpp 复制代码
SLTNode* SLTFind(SLTNode* phead, SLTNodeDataType x);

执行文件代码实现:

cpp 复制代码
// 链表的查找
SLTNode* SLTFind(SLTNode* phead, SLTNodeDataType x)
{
	
	SLTNode* prev = phead;
	while (prev)// 等价于 prev != NULL;
	{
		if (prev->data == x)
		{
			return prev;
		}
		prev = prev->next;
	}

	// 遍历完毕没有找到,返回空。
	return NULL;
}

4.8链表在指定位置之前插⼊数据

头文件声明:

cpp 复制代码
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTNodeDataType x);

执行文件代码实现:

cpp 复制代码
// 链表在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTNodeDataType x)
{
	// 不可以传入NULL
	assert(pphead && *pphead);
	assert(pos);

	// 创建一个新的节点
	SLTNode* newnode = SLTBuyNode(x);

	// 如果节点只有一个,就是头插
	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* pcur = *pphead;

		// pcur所指向的节点不为pos前一个节点
		while (pcur->next != pos)
		{
			pcur = pcur->next;
		}

		// pcur所指向的节点为pos前一个节点
		newnode->next = pos;
		pcur->next = newnode;
	}
}

4.9链表在指定位置之后插⼊数据

头文件声明:

cpp 复制代码
void SLTInsertAfter(SLTNode* pos, SLTNodeDataType x);

执行文件代码实现:

cpp 复制代码
// 链表在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTNodeDataType x)
{
	assert(pos);

	// 创建要插入的节点
	SLTNode* newnode = SLTBuyNode(x);

	// 开始插入
	newnode->next = pos->next;
	pos->next = newnode;
}

4.9-1删除pos节点

头文件声明:

cpp 复制代码
void SLTErase(SLTNode** pphead, SLTNode* pos);

执行文件代码实现:

cpp 复制代码
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;

		while (prev->next != pos)
		{
			prev = prev->next;
		}

		// prev所指向的就是pos前一个节点
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}

}

4.9-2删除pos之后的节点

头文件声明:

cpp 复制代码
void SLTEraseAfter(SLTNode* pos);

执行文件代码实现:

cpp 复制代码
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos && pos->next); // 传过来的参数不可以为空,pos下一个的参数也不可以是NULL

	SLTNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}

4.9-3销毁链表

文件声明:

cpp 复制代码
void SListDesTroy(SLTNode** pphead);

执行文件代码实现:

cpp 复制代码
//销毁链表
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	// 全部销毁完后,置为空NULL;
	*pphead = NULL;
}

补充:测试文件:

cpp 复制代码
//void SListNodeText01()
//{
//	// 创建节点
//	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
//	node1->data = 1;
//
//	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
//	node2->data = 2;
//
//	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
//	node3->data = 3;
//
//	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
//	node4->data = 4;
//
//	// 将四个节点连接起来
//	node1->next = node2;
//	node2->next = node3;
//	node3->next = node4;
//	node4->next = NULL;
//
//	// 打印
//	SLTPrint(node1);
//}

void SLTNodeText02()
{
	//SLTNode* plist = NULL;

	// 测试尾插
	//SLTPushBack(&plist, 1);
	//SLTPushBack(&plist, 2);
	//SLTPushBack(&plist, 3);
	//SLTPushBack(&plist, 4);
	/*SLTPrint(plist);*/// 1->2->3->4->NULL;


	// 测试头插
	/*SLTPushFront(&plist, 5);
	SLTPrint(plist);

	SLTPushFront(&plist, 6);
	SLTPrint(plist);

	SLTPushFront(&plist, 7);
	SLTPrint(plist);

	SLTPushFront(&plist, 8);
	SLTPrint(plist);*/


    // 测试尾删
	//SLTPopBack(&plist);
	//SLTPrint(plist);
	//SLTPopBack(&plist);
	//SLTPrint(plist);
	//SLTPopBack(&plist);
	//SLTPrint(plist);
	//SLTPopBack(&plist);
	//SLTPrint(plist);


	// 测试头删
	//SLTPopFront(&plist);
	//SLTPrint(plist);
	//SLTPopFront(&plist);
	//SLTPrint(plist);
	//SLTPopFront(&plist);
	//SLTPrint(plist);
	//SLTPopFront(&plist);
	//SLTPrint(plist);
	// 报错
	//SLTPopFront(&plist);
	//SLTPrint(plist);


	// 测试查找
	//SLTNode* find = SLTFind(plist, NULL);
	//if (find == NULL)
	//{
	//	printf("没有找到!\n");
	//}
	//else
	//{
	//	printf("找到了!\n");
	//}


	// 测试在pos位置之前插⼊数据
	//SLTNode* find = SLTFind(plist, 1);
	//SLTInsert(&plist, find, 11);
	//SLTPrint(plist);


	// 测试链表在指定位置之后插⼊数据
	/*SLTNode* find = SLTFind(plist, 4);
	SLTInsertAfter(find, 11);
	SLTPrint(plist);*/

	// 测试删除pos之后的节点
	/*SLTNode* find = SLTFind(plist, 1);
	SLTEraseAfter(find);
	SLTPrint(plist);*/

	// 测试销毁
	SListDesTroy(&plist);
}

int main()
{
	//SListNodeText01();
	SLTNodeText02();
	return 0;
}
相关推荐
ChoSeitaku1 小时前
链表交集相关算法题|AB链表公共元素生成链表C|AB链表交集存放于A|连续子序列|相交链表求交点位置(C)
数据结构·考研·链表
偷心编程1 小时前
双向链表专题
数据结构
香菜大丸1 小时前
链表的归并排序
数据结构·算法·链表
jrrz08281 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
@小博的博客1 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
南宫生2 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
泉崎3 小时前
11.7比赛总结
数据结构·算法
你好helloworld3 小时前
滑动窗口最大值
数据结构·算法·leetcode
JSU_曾是此间年少5 小时前
数据结构——线性表与链表
数据结构·c++·算法
sjsjs115 小时前
【数据结构-合法括号字符串】【hard】【拼多多面试题】力扣32. 最长有效括号
数据结构·leetcode