数据结构零基础入门篇(C语言实现)

news2024/11/28 21:36:48

前言:数据结构属于C++学习中较难的一部分,对应学习者的要求较高,如基础不扎实,建议着重学习C语言中的指针和结构体,万丈高楼平地起。

一,链表

1)单链表的大致结构实现

用C语言实现链表一般是使用结构体,首先我们可以通过链表的结构特性反推结构体的成员。单链表是只能通过前一个节点找到下一个节点,并且是单向的,每一个节点还要存储数据元素,我们实现这个的手段是指针,因此我们需要在前一个结点存储下一个地址。

typedef int SLTDateType;//方便以后修改链表类型
typedef struct STLListNode {
	SLTDateType n;
	struct STLListNode* next;
}SListNode;//减少代码的冗余

2)单链表的思考(然后找到链表和判断链表的结束)

首先是如何找到链表的第一个元素,每次,我们之前的图上给了提示,我们可以用一个head指针来标记第一个结点,但有一个很大的注意事项,我们不能随便改变head的地址,不然我们将会无法找到这个链表。

那如何判断链表的结束呢,看上面的手绘图,最后一个结点所指向的是NULL指针,根据这个特点我们就可以判断链表的结束。

注:我们为什么要考虑这两个问题是因为如果我们不严格的控制指针的指向,当指针指向为开辟的空间,会导致程序出现各种意外甚至无法运行。

3)单链表的程序实现及源代码讲解

1)链表的实现前提准备
#include<stdio.h>
#include<assert.h>
typedef int SLTDateType;//方便以后修改链表类型
typedef struct STLListNode {
	SLTDateType n;
	struct STLListNode* next;
}SListNode;//减少代码的冗余
2)单链表的创建及初始化
SListNode* BuySListNode(SLTDateType x);
SListNode* BuySListNode(SLTDateType x) {
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));//分配内存空间
	assert(newnode);//防止分配失败导致的访问非法空间
	newnode->n= x;
	return newnode;//返回创建空间地址
}
3)单链表的尾插

void SListPushBack(SListNode** pplist, SLTDateType x);
void SListPushBack(SListNode** pplist, SLTDateType x) {//链表要传地址用二级指针接受,因为头插的时候是要改变链表的地址,是需要二级指针才能改变一级指针
	SListNode* ptemp = *pplist;
	SListNode** plist = pplist;//防止头指针丢失
	if (*plist == NULL) {
		*plist = BuySListNode(x);
		(*plist)->next = NULL;
		return;
	}//如果是空链表需要单独处理
	while ((*plist)->next != NULL) {
		*plist = (*plist)->next;
	}//找到尾节点
	(*plist)->next  = BuySListNode(x);//分配一个新空间
	(*plist)->next->next = NULL;//置空方便下次找尾结点
	*pplist = ptemp;//维持头指针
}
4)单链表的头插

void SListPushFront(SListNode** pplist, SLTDateType x) {//要改变头指针的地址,需要二级指针
	if (*pplist == NULL) {
		*pplist = BuySListNode(x);
		(*pplist)->next = NULL;
		return;//如果链表为空,单独处理
	}
	SListNode* plist= BuySListNode(x);//分配空间
	plist->next = (*pplist);//将新结点的next指针指向原来的头指针
	*pplist = plist;//改变头指针
}
5)单链表的头删

void SListPopFront(SListNode** pplist){
	assert(*pplist);//判断是否为空链表,防止访问非法空间
	SListNode* plist = *pplist;
	*pplist = (*pplist)->next;//保留新头
	plist->next = NULL;//老的头指针置空,防止通过这个非法访问
	free(plist);//释放老头指针空间
}
6)单链表的尾删

void SListPopBack(SListNode** pplist) {
	assert(*pplist);//判断是否为空链表,防止访问非法空间
	SListNode* plist = (*pplist);//保存头指针,防止丢失
	if (plist->next == NULL) {
		free(plist);
		plist = NULL;
	}//如果只有一个元素,直接释放
	while (plist->next->next != NULL) {
		plist = plist->next;
	}//找到尾结点
	free(plist->next);
	plist->next = NULL;//置空
}
7)在单链表中查找元素
SListNode* SListFind(SListNode* plist, SLTDateType x) {
	assert(plist);//判断是否为空链表,防止访问非法空间
	while (plist->next != NULL) {
		if (plist->n = x)
			return plist;//如果找到直接返回地址
		plist = plist->next;//否则下一个
	}
	return NULL;//找到了尾结点都没找到,返回空指针
}
8)单链表指定结点的后面插入和删除元素
void SListInsertAfter(SListNode* pos, SLTDateType x) {
	assert(pos);//判断是否为空链表,防止访问非法空间
	SListNode* temp = pos->next;
	pos->next = BuySListNode(x);
	pos->next->next = temp;
}
void SListEraseAfter(SListNode* pos) {
	assert(pos);//判断是否为空链表,防止访问非法空间
	assert(pos->next );//判断是否有下一个元素
	SListNode* temp = pos->next;
	pos->next = pos->next->next;//改变前一个指针的next指针,防止断层
	free(temp);
}
9)单链表的内存销毁
void SListDestroy(SListNode* plist) {
	assert(plist);//防止多次释放空间
	SListNode* cur = plist->next;//记录当前指针,因为当前指针释放后无法访问到下一个指针的地址
	while (cur) {
		free(plist);
		plist = cur;
		cur = plist->next;
	}
	plist = NULL;
}

2)带头双向循环链表的提示(自己实现)

与单链表相比,带头双向循环链表,会有多开辟一个空间,不用来存储数据,用来指向head指针,这样可以简化许多操作。还要多一个指针指向前一个结点,并且尾指针不在置空,而且指向第一个结点。

二,队列和栈

1)队列特性

就像如图的核酸检测,你先进入队列,你就能比别人先做完核酸离开。因此队列的特性是先进先出。

2)栈的特性

栈的特性就像往一个一次只能拿出一个石头的瓶子里面投石头,你想要拿到最下面的石头你就需要先拿出前面所有的石头,因此栈的特性就是先进后出。

3)队列用链表实现(源代码及详细讲解)

1)队列结构和功能实现前准备

和链表一样,我们队列也使用结构体指针的方法实现,与链表实现大同小异,但会有一个另外的结构体用来存储队列的第一个元素指针的地址,和最后一个元素指针的地址,这样方便我们接下来的各个功能实现,可以省下很多代码量。

#include<stdio.h>
#include<assert.h>
typedef int QDataType;//方便以后将队列修改为其他类型
typedef struct QListNode
{
	struct QListNode* _next;//下一个队列的指针
	QDataType _data;//数据元素
}QNode;//减少代码长度
typedef struct Queue
{
	QNode* _front;//队列第一个元素指针
	QNode* _rear;//队列最后一个元素指针
}Queue;
2)初始化队列
void QueueInit(Queue* q) {
	q->_front = (QNode*)malloc(sizeof(QNode));//开辟空间
	q->_front->_data = -1;//数据随意初始化
	q->_rear = q->_front ;//此时只有一个元素,头和尾相等
}
3)入列数据
void QueuePush(Queue* q, QDataType data) {
	q->_rear->_data = data;//从尾开始入列
	q->_rear->_next = (QNode*)malloc(sizeof(QNode));//给下一个队列分配空间
	q->_rear = q->_rear->_next;//移动尾指针
}
4)出列数据
void QueuePop(Queue* q) {
	assert(q->_front!=q->_rear );//防止出列空队列
	QNode* list = q->_front ;//保存头指针,防止丢失
	while (list->_next != q->_rear) {
		list = list->_next;
	}//找到尾指针
	free(q->_rear);//释放尾指针
	q->_rear = list;//重新恢复尾指针
}
5)获取队列头部元素 
QDataType QueueFront(Queue* q) {
	assert(q->_front != q->_rear);
	return q->_front->_data;
}
6)获取队列尾部元素
QDataType QueueBack(Queue* q) {
	assert(q->_front != q->_rear);//判断是否有至少两个元素,防止数组越界
	QNode* list = q->_front;//保存头指针,防止丢失
	while (list->_next != q->_rear) {
		list = list->_next;
	}//找到尾结点,队列最后一个元素指针
	return list->_data;
}
7)销毁队列元素
void QueueDestroy(Queue* q) {
	while (q->_front != q->_rear) {
		QNode* list = q->_front;//利用list来销毁上一个指针,防止销毁之后找不到下一个元素
		q->_front = q->_front->_next;//头指针换为下一个元素
		free(list);//销毁
	}
	free(q->_rear);//不要忘记还落下了一个尾结点
	q->_front = NULL;
	q->_rear = NULL;//置空,防止非法访问
}

4)栈的代码实现(提供另外一种思路,自己实现)

之前说过栈就像往一次只够拿一个石头的瓶子里放石头和取石头,有没有发现栈和数组有很大的相似,当我们打开这个思路,我们会发现如果用数组实现的话,我们的代码思路和代码量突然就小了很多。我这里只提供结构和功能实现前的准备,其他望诸君自己勤练。

#include<stdio.h>
#include<assert.h>
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* _a; //到时候用maolloc开辟空间,可以随时调节数组大小
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;

最后言:数据结构是需要大量题目来练手的,单纯的理论知识是纸上谈兵,真正实现的时候是变化万千。牢记:纸上得来终觉浅,绝知此事要躬行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/975737.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mendix如何实现导出文件

刚刚接触Mendix低代码两周&#xff0c;花了一周在b站看初级视频然后考完初级&#xff0c;第二周开始做个列表查询感觉照葫芦画瓢没啥难度。但最近要求写个导出列表数据&#xff0c;在mendix社区翻了翻&#xff0c;这个功能算是常见的。找了mendix官方提供的Docs磕磕盼盼才实现了…

学会这几步,教你1分钟辨出B站优质UP主!

品牌想要投放某UP主&#xff0c;该如何判断UP主是否优质并且同品牌相匹配呢&#xff1f;运用这一套多维度的UP主评估方法 &#xff0c;帮助你高效判断&#xff0c;快来看看具体怎么操作吧&#xff01; 一、up主粉丝涨跌 有些广告主在判断UP主是否值得投放时&#xff0c;会陷入…

OLED透明屏 裸屏:透明未来的创新之选

OLED透明屏 裸屏作为一项领先的显示技术&#xff0c;正以其独特的优势和创新的设计特点引起广泛关注。 根据市场调研数据显示&#xff0c;预计到2025年&#xff0c;OLED透明屏 裸屏市场规模将达到250亿美元&#xff0c;年均增长率超过25%。 本文将通过深入探讨OLED透明屏 裸屏…

Vue2基础学习

vue基础学习 Vue基础指令v-show 和 v-ifv-on指令v-bind指令v-bind操作classv-bind 操作stylev-for 指令练习&#xff1a;图书管理案例v-model 指令修饰符v-model指令修饰符click.stop-》阻止冒泡按键修饰符阻止默认行为 计算属性计算属性简写computed计算属性VS方法methods计算…

Java版本+企业电子招投标系统源代码+支持二开+Spring cloud

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及…

生成式人工智能促使社会转变

作者&#xff1a;JEFF VESTAL 了解 Elastic 如何处于大型语言模型革命的最前沿 – 通过提供实时信息并将 LLM 集成到数据分析的搜索、可观察性和安全系统中&#xff0c;帮助用户将 LLM 提升到新的高度。 iPhone 社会转变&#xff1a;新时代的黎明 曾几何时&#xff0c;不久前…

别再埋头苦干了,标准化财务数据分析方案开箱即用!

在这个数字化、智能化的时代&#xff0c;一味埋头苦干只会换来效率低下的结果&#xff0c;还是得巧用各种现成资源&#xff0c;以财务数据分析为例&#xff0c;就可以下载奥威BI财务数据分析方案。一键套用&#xff0c;立得覆盖各个主题的财务数据分析报表&#xff0c;快速摸清…

纯前端读写文件?

事情是这样的我发现vscode在线版居然可以打开文件目录和文件&#xff0c;还能保存文件。 兼容性一般 目前 谷歌 edge Opera 支持 其他均不支持 https://vscode.dev/ 查了一下MDN 发现增加新的API 了 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/showDirectoryP…

使用js搭建简易的WebRTC实现视频直播

首先需要一个信令服务器&#xff0c;我们使用nodejs来搭建。两个端&#xff1a;发送端和接收端。我的目录结构如下图&#xff1a;流程 创建一个文件夹 WebRTC-Test。进入文件夹中&#xff0c;新建一个node的文件夹。使用终端并进入node的目录下&#xff0c;使用 npm init 创建p…

易基因:MeRIP-seq等揭示mRNA m6A甲基化调控拟南芥的抗寒性分子机制|植物抗逆

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 植物通过改变数千个基因的mRNA丰度以促进其生理和代谢过程&#xff0c;从而对低温应激进行响应。在转录后水平上&#xff0c;这些冷应激应答转录本经历可变剪接、microRNA介导的调控和可…

气象站的工作内容有哪些?

气象站的工作内容包括观测、记录和报告天气数据。具体来说&#xff0c;气象站需要通过各种传感器和数据记录器来测量和记录气温、湿度、风速、风向、气压、降雨量、雪深等气象参数&#xff0c;对数据的分析、处理和存储。例如&#xff0c;气象站需要将收集到的数据与历史数据进…

Redis设置开机自启动

&#xff08;配置环境变量&#xff09;需要重启电脑 1、在安装目录打开命令行&#xff0c;输入&#xff1a;打开一个命令窗进入文件夹内&#xff0c;输入redis-server --service-install redis.windows-service.conf 2、windowsR ---->services.msc 找到Redis&#xff0c;右…

【好书推荐】人月神话

《人月神话》一书被评为神品之作&#xff0c;以其深入的思想和优美的文字而享誉于软件工程领域。该书由Frederick P. Brooks撰写于28年前&#xff0c;探讨了软件工程领域的现实问题&#xff0c;揭示了软件行业在解决问题上存在的错误方案和缺乏专业性的现象。 在这本书中&…

独立站新手引流,谷歌SEO工具汇总

俗话说“工欲善其事&#xff0c;必先利其器”&#xff0c;做谷歌SEO也一样&#xff0c;要想做好并提升SEO效果&#xff0c;卖家就需要了解并利用好SEO工具。那我们今天就来盘点一下&#xff0c;常用的SEO工具有哪些吧~ 网站检测工具 1、PageSpeed Insights&#xff1a;这是谷…

Python足球训练打卡系统SpringBoot足球场地预约系统源码 调试 lw

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

财报解读:德尔玛净利润同比增长10.79%,自研将延续增长态势?

高成长性的小家电领域&#xff0c;近年来已成为家电行业的热门赛道。数据显示&#xff0c;我国小家电行业未来将保持6%-7%左右增速&#xff0c;预计2026年市场规模将接近6000亿元。在庞大的市场机遇中&#xff0c;德尔玛等后起之秀也频频迎来投资者关注。 从进行品牌设计&…

图片转pdf软件有哪些?这几款收藏下来

图片转pdf软件有哪些&#xff1f;图片转PDF的需求很常见。有时候我们需要将一些图片文件合并成一个PDF文件&#xff0c;方便浏览和共享。比如说&#xff0c;你可能需要将一份报告或者简历的图片转换成PDF文件&#xff0c;以便于分享给其他人。此外&#xff0c;将图片转换成PDF文…

计算机网络自顶向下-web页面请求历程

1. 准备: DHCP、 UDP、 IP 和以太网 假定 Bob 启动他的便携机&#xff0c;然后将其用一根以太网电缆连接到学校的以太网交换机 &#xff0c; 交换机与学校的路由器相连。学校的路由器与一个 ISP 连接&#xff0c; 本例中 ISP 为 comcast.net &#xff0c;为学校提供了 DNS 服务…

0010Java程序设计-springboot+vue影院售票系统设计与实现

摘 要目 录系统实现开发环境 摘 要 看电影已经成为了人们生活中不可缺少的一部分&#xff0c;电影院售票及管理系统是电影院的日常管理及售票任务的核心&#xff0c; 在电影院中&#xff0c; 工作人员并非只是放映电影&#xff0c; 还有诸如票房统计、影片放映、影片场次安排、…

TypeScrip第一课

前言 TypeScript是一个开源的、渐进式包含类型的JavaScript超集。 作用是让开发者增强js的能力并使应用的规模扩展变得更容易。 这两点是废话&#xff0c;至于什么是超集&#xff1f; S1是S2的子集。S2是S1的超集&#xff08;类似于扩展extend&#xff09; TS基于ES6为 …