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

目录

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;
}
相关推荐
代码雕刻家21 分钟前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
Kalika0-02 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
代码雕刻家2 小时前
课设实验-数据结构-单链表-文教文化用品品牌
c语言·开发语言·数据结构
小字节,大梦想3 小时前
【C++】二叉搜索树
数据结构·c++
我是哈哈hh4 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
丶Darling.4 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5205 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法
Indigo_code5 小时前
【数据结构】【链表代码】合并有序链表
数据结构·windows·链表
jiyisuifeng19915 小时前
代码随想录训练营第54天|单调栈+双指针
数据结构·算法
我言秋日胜春朝★5 小时前
【C++】红黑树
数据结构