当前位置: 首页 > article >正文

【数据结构】_不带头非循环单向链表

目录

1. 链表的概念及结构

2. 链表的分类

3. 单链表的实现

3.1 SList.h头文件

3.2 SList.c源文件

3.3 Test_SList.c测试文件


关于线性表,已介绍顺序表,详见下文:

【数据结构】_顺序表-CSDN博客

本文介绍链表;

基于顺序表的特点,思考改善方案:

按需申请释放空间,不再将数据存储于连续的一整块空间中,而是需要一个数据开辟一个小空间。为了方便访问数据,首先创建一个头指针(头结点)指向存放第一个数据的内存位置处,而在该位置处,除了存储该数据本身,再分配一块空间用于存放下一个数据的地址,直至某位置存放的下一个位置的指针为空则数据截止。

同时,这种存储方式也有效地提高了插入删除数据时的效率,无需再大量挪动数据。

这种数据结构就称为链表。

1. 链表的概念及结构

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

链表在逻辑上是连续的,在物理上不是连续的

2. 链表的分类

单向和双向:

带头和不带头:

循环和非循环:

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

3. 单链表的实现

3.1 SList.h头文件

#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 SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
SLTNode* SLTCreatNode(SLTDataType x);
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);

3.2 SList.c源文件

#include"SList.h"
void SLTPrint(SLTNode* phead) {
	SLTNode* pcur = phead;
	while (pcur) {
		printf("%d-> ", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}
SLTNode* SLTCreatNode(SLTDataType x) {
	SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newNode == NULL) {
		perror("malloc fail\n");
		exit(1);
	}
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
	assert(pphead);
	SLTNode* newNode = SLTCreatNode(x);
	// 空链表
	if (*pphead == NULL) {
		*pphead = newNode;
	}
	else {
		// 非空链表
		SLTNode* curNode = *pphead;
		while (curNode->next) {
			curNode = curNode->next;
		}
		curNode->next = newNode;
	}
}
void SLTPushFront(SLTNode** pphead, SLTDataType x) {
	assert(pphead);
	SLTNode* newNode = SLTCreatNode(x);
	newNode->next = *pphead;
	// 令新结点为链表的头结点
	*pphead = newNode;
}
void SLTPopBack(SLTNode** pphead) {
	assert(pphead && *pphead);
	// 链表只有一个结点
	if ((*pphead)->next == NULL) {
		free(*pphead);
		*pphead = NULL;
	}
	// 链表有多个结点
	else {
		SLTNode* tailPrevNode = *pphead;
		SLTNode* tailNode = *pphead;
		while (tailNode->next) {
			tailPrevNode = tailNode;
			tailNode = tailNode->next;
		}
		free(tailNode);
		tailNode = NULL;
		tailPrevNode->next = NULL;
	}
}
void SLTPopFront(SLTNode** pphead) {
	assert(pphead && *pphead);
	SLTNode* secNode = (*pphead)->next;
	free(*pphead);
	*pphead = secNode;
}
SLTNode* SLTFind(SLTNode* phead, SLTDataType x) {
	SLTNode* curNode = phead;
	while (curNode) {
		if (curNode->data == x) {
			return curNode;
		}
		curNode = curNode->next;
	}
	return NULL;
}
// 在指定位置前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) {
	assert(pphead && *pphead && pos);
	SLTNode* newNode = SLTCreatNode(x);
	if (pos == *pphead) {
		// 调用头插方法
		SLTPushFront(pphead, x);
	}
	else {
		SLTNode* posPrevNode = *pphead;
		while (posPrevNode->next != pos) {
			posPrevNode = posPrevNode->next;
		}
		posPrevNode->next = newNode;
		newNode->next = pos;
	}
}
// 在指定位置后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
	assert(pos);
	SLTNode* newNode = SLTCreatNode(x);
	SLTNode* posAfterNode = pos->next;
	pos->next = newNode;
	newNode->next = posAfterNode;
}
// 删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos) {
	assert(pphead && *pphead && pos);
	if (*pphead == pos) {
		// 调用头删方法
		SLTPopFront(pphead);
	}
	else {
		SLTNode* posPrevNode = *pphead;
		while (posPrevNode->next != pos) {
			posPrevNode = posPrevNode->next;
		}
		posPrevNode->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
// 删除pos后的结点
void SLTEraseAfter(SLTNode* pos) {
	assert(pos && pos->next);
	SLTNode* posAfterNode = pos->next;
	pos->next = posAfterNode->next;
	free(posAfterNode);
	posAfterNode = NULL;
}
// 销毁
void SLTDestory(SLTNode** pphead) {
	assert(pphead && *pphead);
	SLTNode* curNode = *pphead;
	while (curNode) {
		SLTNode* curNextNode= curNode->next;
		free(curNode);
		curNode = NULL;
	}
	*pphead = NULL;
}

3.3 Test_SList.c测试文件

#include"SList.h"
void Test11() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTDestory(&plist);
	SLTPrint(plist);
}
void Test10() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTNode* aimNode1 = SLTFind(plist, 3);
	SLTEraseAfter(aimNode1);
	SLTPrint(plist);
	SLTNode* aimNode2 = SLTFind(plist, 1);
	SLTEraseAfter(aimNode2);
	SLTPrint(plist);
}
void Test9() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTNode* aimNode1 = SLTFind(plist, 3);
	SLTErase(&plist, aimNode1);
	SLTPrint(plist);
	SLTNode* aimNode2 = SLTFind(plist, 1);
	SLTErase(&plist, aimNode2);
	SLTPrint(plist);
}
void Test8() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTNode* aimNode1 = SLTFind(plist, 3);
	SLTInsertAfter(aimNode1, 85);
	SLTPrint(plist);
	SLTNode* aimNode2 = SLTFind(plist, 1);
	SLTInsertAfter(aimNode2, 97);
	SLTPrint(plist);
}
void Test7(){
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTNode* aimNode1 = SLTFind(plist, 3);
	SLTInsert(&plist, aimNode1, 85);
	SLTPrint(plist);
	SLTNode* aimNode2 = SLTFind(plist, 1);
	SLTInsert(&plist, aimNode2, 97);
	SLTPrint(plist);
}
void Test6() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	// SLTNode* aimNode = SLTFind(plist, 3);
	SLTNode* aimNode = SLTFind(plist, 6);
	if (aimNode == NULL)
		printf("Find nothing\n");
	else
		printf("Find successfully\n");
}
void Test5() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPrint(plist);
	SLTPopFront(&plist);
	SLTPrint(plist);
	SLTPopFront(&plist);
	SLTPrint(plist);
	SLTPopFront(&plist);
	SLTPrint(plist);
}
void Test4() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPrint(plist);
	SLTPopBack(&plist);
	SLTPrint(plist);
	SLTPopBack(&plist);
	SLTPrint(plist);
	SLTPopBack(&plist);
	SLTPrint(plist);
}
void Test3() {
	SLTNode* plist = NULL;
	SLTPushFront(&plist, 1);
	SLTPushFront(&plist, 2);
	SLTPushFront(&plist, 3);
	SLTPushFront(&plist, 4);
	SLTPrint(plist);
}
void Test2() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
}

void Test1() {
	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);
}
int main() {
	//Test1();
	//Test2();
	//Test3();
	//Test4();
	//Test5();
	//Test6();
	//Test7();
	//Test8();
	//Test9();
	//Test10();
	Test11();
	return 0;
}


http://www.kler.cn/a/518337.html

相关文章:

  • ComfyUI实现老照片修复——AI修复老照片(ComfyUI-ReActor / ReSwapper)解决天坑问题及加速pip下载
  • Poseidon哈希为什么适合做ZKP
  • Android Studio:视图绑定的岁月变迁(2/100)
  • 【图文详解】lnmp架构搭建Discuz论坛
  • Ubuntu20.04 深度学习环境配置(持续完善)
  • Cpp::静态 动态的类型转换全解析(36)
  • 安全扫描Django项目解决存在敏感信息常见问题
  • redis主从集群中的哨兵机制
  • 探索 Web3 技术:如何推动数字身份的自主管理
  • 第4章 神经网络【1】——损失函数
  • css-设置元素的溢出行为为可见overflow: visible;
  • SpringBoot集成Flink-CDC,实现对数据库数据的监听
  • 解锁罗技键盘新技能:轻松锁定功能键(罗技K580)
  • NFT Insider #166:Nifty Island 推出 AI Agent Playground;Ronin 推出1000万美元资助计划
  • jQuery阶段总结(二维表+思维导图)
  • Vue 3 30天精进之旅:Day 03 - Vue实例
  • Linux(Centos、Ubuntu) 系统安装jenkins服务
  • Windows中如何查看Java进程对应的进程ID(PID),以及如何kill进程详解
  • 【线上问题定位处理】及【性能优化】系列文章
  • uniapp中h5的微应用解决办法
  • 中级运维工程师面试题汇总(含答案)
  • Java NIO方面面试题及答案解析
  • qt--Qml控件库如何从外部导入2.0
  • [GXYCTF2019]Ping Ping Ping1
  • Coolbpf最新特性解读:profiler功能上线,助力性能分析和优化
  • C++使用异或找出数组中奇数次出现的数据