【数据结构】单链表

1.单链表的储存结构

cpp 复制代码
typedef int SLTDataType;//链表是由节点组成的

typedef struct SListNode
{
  SLTDataType data;
  struct SListNode* next;
}SLTNode;

typedef的int,因为存储的数据不一定是整型,所以为了以后的修改不必要每个地方都改。

cpp 复制代码
#include "SList.h"
int main()
{
	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;
	SLTNode* plist = node1;
	SLTPrint(plist);
	return 0;
}

2.遍历单链表

依次遍历链表中的每个节点直到遇到NULL指针停止。

cpp 复制代码
void SLTPrint(SLTNode* phead) {
	SLTNode* pcur = phead;
	while (pcur)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");

1.定义pcur是为了不改变原指针的前提下,让pcur往下走.

2.pcur = pcur->next;是链表中的关键代码,作用就是把链表穿起来,phead是指向链表的指针,用pcur代替phead往下走,pcur->next这句话意思是一块空间的后一个部分的指向就是下一块空间的指针,说明这个指针就是指向下一块空间的。

3.单链表的各个函数

申请一个节点

cpp 复制代码
//申请一个节点
SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

最后一句return newnode遗忘掉

尾插节点

cpp 复制代码
//尾插节点
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnodes = SLTBuyNode(x);
	//链表为空,新节点作为phead
	if (*pphead == NULL)
	{
		*pphead = newnodes;
	}
	//链表不为空,找尾节点
	else
	{
		SLTNode* ptail = *pphead;
		while (ptail->next)
		{
			ptail = ptail->next;
		}
		//patil就是尾节点
		ptail->next = newnodes;
	}
}

头插节点

cpp 复制代码
//头插节点
void SLTPushFornt(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

尾删节点

cpp 复制代码
//尾删节点
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	//链表为空
	assert(*pphead);
	//链表只有一个节点
	if ((*pphead)->next == NULL)
	{
		*pphead = NULL;
	}
	//链表有多个节点
	else
	{
		SLTNode* ptail = *pphead;
		SLTNode* prev = NULL;
		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		free(ptail);
		ptail = NULL;
		prev->next = NULL;
	}
}

头删节点

cpp 复制代码
//头删节点
void SLTPopFornt(SLTNode** pphead)
{
	assert(pphead);
	//链表不为空
	assert(*pphead);
	//让第二个节点成为新头
	//把旧空间释放
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

查找节点

cpp 复制代码
//查找节点
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x)
{
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

在指定位置前插入数据

cpp 复制代码
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);
	SLTNode* newnode = SLTBuyNode(x);

	if (pos == *pphead)
	{
		SLTPushFornt(pphead, x);
		return;
	}

	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	newnode->next = pos;
	prev->next = newnode;
}

在指定位置后插入数据

cpp 复制代码
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	/*SLTNode* next = pos->next;
	newnode->next = next;*/
	newnode->next = pos->next;
	pos->next = newnode;
}

在指定位置前删除数据

cpp 复制代码
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);

	if (*pphead == pos)
	{
		SLTPopFornt(pphead);
		return;
	}

	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	SLTNode* next = pos->next;
	free(pos);
	pos = NULL;
	prev->next = next;
}

在指定位置后删除数据

cpp 复制代码
//删除pos之后节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);
	SLTNode* next = pos->next->next;
	free(pos->next);
	pos->next = next;
}

销毁链表

cpp 复制代码
//销毁链表
void SLTDestory(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

4.单链表全部代码

SList.h

cpp 复制代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLTDataType;

//链表是由节点组成的
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

//打印节点
void SLTPrint(SLTNode* phead);

//尾插节点
void SLTPushBack(SLTNode** pphead,SLTDataType x);

//头插节点
void SLTPushFornt(SLTNode** pphead, SLTDataType x);

//尾删节点
void SLTPopBack(SLTNode** pphead);

//头删节点
void SLTPopFornt(SLTNode** pphead);

//查找节点
SLTNode* SLTFind(SLTNode* phead,SLTDataType x);

//在指定位置插入数据

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead,SLTNode* pos, SLTDataType x);

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

//在指定位置删除节点

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);

//删除pos之后节点
void SLTEraseAfter(SLTNode* pos);

//销毁链表
void SLTDestory(SLTNode** pphead);

SList.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include "SList.h"

//打印单链表
void SLTPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}

SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

//尾插节点
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnodes = SLTBuyNode(x);
	//链表为空,新节点作为phead
	if (*pphead == NULL)
	{
		*pphead = newnodes;
	}
	//链表为空,找尾节点
	else
	{
		SLTNode* ptail = *pphead;
		while (ptail->next)
		{
			ptail = ptail->next;
		}
		//patil就是尾节点
		ptail->next = newnodes;
	}
}

//头插节点
void SLTPushFornt(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

//尾删节点
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	//链表为空
	assert(*pphead);
	//链表只有一个节点
	if ((*pphead)->next == NULL)
	{
		*pphead = NULL;
	}
	//链表有多个节点
	else
	{
		SLTNode* ptail = *pphead;
	/*	SLTNode* prev = NULL;
		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		free(ptail);
		ptail = NULL;
		prev->next = NULL;*/

		while (ptail->next->next)
		{
			ptail = ptail->next;
		}
		free(ptail->next);
		ptail->next = NULL;
	}
}

//头删节点
void SLTPopFornt(SLTNode** pphead)
{
	assert(pphead);
	//链表不为空
	assert(*pphead);
	//让第二个节点成为新头
	//把旧空间释放
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

//查找节点
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x)
{
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);
	SLTNode* newnode = SLTBuyNode(x);

	if (pos == *pphead)
	{
		SLTPushFornt(pphead, x);
		return;
	}

	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	newnode->next = pos;
	prev->next = newnode;
}

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	/*SLTNode* next = pos->next;
	newnode->next = next;*/
	newnode->next = pos->next;
	pos->next = newnode;
}

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);

	if (*pphead == pos)
	{
		SLTPopFornt(pphead);
		return;
	}

	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	SLTNode* next = pos->next;
	free(pos);
	pos = NULL;
	prev->next = next;
}

//删除pos之后节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);
	SLTNode* next = pos->next->next;
	free(pos->next);
	pos->next = next;
}

//销毁链表
void SLTDestory(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

test.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include "SList.h"

int main()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);


	SLTNode* FindRet = SLTFind(&plist, 3);
	if (FindRet == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("找到了\n");
	}
	SLTDestory(&plist);
	return 0;
}
相关推荐
C雨后彩虹3 小时前
任务最优调度
java·数据结构·算法·华为·面试
SmartRadio5 小时前
CH585M+MK8000、DW1000 (UWB)+W25Q16的低功耗室内定位设计
c语言·开发语言·uwb
微露清风5 小时前
系统性学习C++-第十八讲-封装红黑树实现myset与mymap
java·c++·学习
CSARImage6 小时前
C++读取exe程序标准输出
c++
一只小bit6 小时前
Qt 常用控件详解:按钮类 / 显示类 / 输入类属性、信号与实战示例
前端·c++·qt·gui
一条大祥脚6 小时前
26.1.9 轮廓线dp 状压最短路 构造
数据结构·c++·算法
项目題供诗7 小时前
C语言基础(一)
c++
@areok@7 小时前
C++opencv图片(mat)传入C#bitmap图片
开发语言·c++·opencv
鸽芷咕7 小时前
【2025年度总结】时光知味,三载同行:落笔皆是沉淀,前行自有光芒
linux·c++·人工智能·2025年度总结
羑悻的小杀马特7 小时前
指尖敲代码,笔尖写成长:2025年度总结与那些没说出口的碎碎念
linux·c++·博客之星·2025年度总结