C++基础语法:链表和数据结构

前言

       "打牢基础,万事不愁" .C++的基础语法的学习

引入

        链表是最基础的数据集合,对标数组.数组是固定长度,随机访问,链表是非固定长度,不能随机访问.数组查找快,插入慢;链表是插入快,查找慢.

        前面推导过"数据结构+算法=数据集合".想建立一个数据集合,就要设计数据结构和他的算法.数据结构和算法是密不可分的.当然已经有优秀的前辈已经设计好了许多种数据结构供程序员选择使用.但学习最好是能知其所以然,

        链表和数组是所有数据结构的底层.比如链栈,链队列,动态数组这些概念,表示其底层是链表或者数组.链表的内容如此少,以至于<C++ Prime Plus> 6th Edition(以下称"本书")都没写.我想学习的目的在于吸收设计者的思想,以及一些固定的解决问题模式.所以对链表内容做个理解.

链表的类表示

        链表有数据域和指针域.数据域是数据集合的对象,指针域是链表本身的指针,他负责把数据链接在一起.以下为链表类示例,

typedef int Data;
class Node{Data data;        //数据域Node* next;       //指针域
};

        Data是泛指类型,data表示泛型的单个对象,数据域不是固定的,他还可以是指向数组的指针Data*,表示数组作为单个元素组成的集合;或者指向其他结点(头结点)的指针,表示结点组成的集合.结点表示另一个链表.

        指针域next也不是固定的,他还可以有其他指针,但类型必须是Node*,因为这样才可以把数据链接起来.例如加上一个Node* front,指向链表前一个元素,做成双向链表.next或者front只是符号,需要通过算法体现出来.

        所以Node类是一个极简版本的链表.

链表的图示 

       

 结点采用了类包含数据的形式

        前面的帖子C++基础语法:类包含-CSDN博客提到了类包含的用法,当时站在设计模式中的行为模式的角度去解释类包含,即类包含用于纳入已有行为类对象,形成一套解决方案.

        结点是另一种类包含的用法,结点类包含的类对象,建立结点类,作为数据结构的基本元素

链表的算法

        链表要做哪些事?他要建立一个集合,尾部指空;可以插入元素,删除元素,检索元素等,代码如下:

#include<iostream>	
using namespace std;struct Node {//数据可见int data;Node* next;
};
class LinkList {Node* firstNode;					//头结点,表示整个链表
public:/*初始化*/LinkList() {firstNode = new Node();			//建立头结点,数据空}/*插入int类型元素*/void add(int data) {Node* link = new Node();		//建立新结点link->data = data;				//传入数据link->next = firstNode->next;	firstNode->next = link;			//和上一行代码一起表示新结点插入头结点后面	}/*查找数据,返回所在位置*/int find(int data) {Node* p = firstNode->next;		//从第一个结点(非头结点)找起int num = 0;while (p) {num++;if (p->data == data)return num;p = p->next;}cout << "没找到数据" << endl;return -1;}/*删除数据所在所有结点*/bool erase(int data) {Node* p = firstNode;			//新建一个结点指向头结点bool success = true;			//声明标志位/*下面如果用while(p), 将产生异常, 原因暂不知道*/while (p->next) {				//从第一个元素开始遍历链表if (p->next->data == data) {//如果找到数据所在前一个结点Node* tmp = p->next;	//标识出要删除的结点p->next = p->next->next;//前结点的next指向将被删除结点的后面delete(tmp);			//删除所在结点success = false;		//修改标志位}p = p->next;				//指针指向下一个结点,把链表找遍,所有结点删除}if(success==false)return true;				//返回truecout << "没找到数据:"<<data << endl;	return false;					//遍历链表没找到数据,返回false}/*打印链表数据*/int printLinkList() {//下面这行如果用Node *p=firstNode;打印出来的是头结点值0Node* p = firstNode->next;		//从第一个结点(非头结点)开始打印cout << "当前链表内数据如下:" << endl;while (p) {cout << p->data << endl;p = p->next;}return 0;}
};

测试代码:

//测试代码
int main(void) {LinkList* p = new	LinkList();		//建立链表,生成头结点p->add(3);p->add(4);							//添加元素p->add(5);							//添加元素p->add(6);							//添加元素p->add(4);							//添加元素p->printLinkList();p->erase(4);						//删除数据4所在所有结点cout << "删除结点后链表内数据:" << endl;p->printLinkList();p->erase(7);						//删除一个链表中没有的元素return 0;
}

     ----说明: 用普通class类做的链表,没用template实现,结点固定了数据类型int

        代码的几处说明:

        1>为了方便书写,定义了struct结构的Node,相当于类数据不分私有private和公开public,全部公开,在LinkList类里可以用对象直接访问,省了一些步骤.如果用class定义Node,要在public里定义访问data的getData()方法,才能获得data.

        2>头结点

        在建立链表LiniList时建立了头结点firstNode,没有数据,指针指空.头结点是具体数据.通过头结点可以访问整个链表,所以头结点视为数据集合.在任何需要数据集合的地方,都需要使用头结点.如在erase和printLinkList中,遍历链表,都是声明一个指针,指向firstNode,凡是遍历链表的地方都是这个方法.初始化时就必须生成头结点

        3> 插入和删除

        在描述插入和删除这个地方要注意顺序:

        插入时,先说明插入结点的后一个结点是什么,再说明他在哪一个结点后面 

		link->next = firstNode->next;	//新结点插入头结点firstNode->next = link;

         删除时,先标记出结点,然后说明前后结点的关系,因为是单链表,所以只需要说明被删除结点的后一个结点,挂到他前一个结点的next即可(如果是双向链表,还要说明后一个结点的前面是被删除结点的前一个结点),然后用delete删除标识结点.

        删除时有一点小问题,可看出双向链表的优点   ----了解

				Node* tmp = p->next;	//标识出要删除的结点p->next = p->next->next;//前结点的next指向将被删除结点的后面delete(tmp);			//删除所在结点

        插入和删除在初学时是一个难点,需要多想想. 

        4>头插法

        每插入一个结点,都被放到头结点的后面,先前在头结点后面那个结点被放到新结点的后面.理解了插入,就明白了是怎么做的.

        5>find函数

        代码里定义了find函数,但没有使用他.

        1.链表本身不支持随机访问,找到位置意义不大.----但想要也可以实现数组那样的"[]"下标功能

        2.链表里可以多次出现同一个值,按照find函数定义只能找到最后插入的那个值的位置.所以严格来说这个函数存在bug.如果要找到最后一次出现的某个元素是第几次插入,倒是可以用find.操作步骤:先求出链表里所有元素的个数,再拿来减去find()函数的返回值.

        3.起个抛砖引玉的作用.数据结构是一种逻辑结构,可以由需求定义各种各样的算法,并不局限于增删查等几种.比如还可以写出统计链表元素个数的算法,将链表元素逆序排列,像数组一样的随机访问[]等等(多种多样)

以链表为基础的数据结构

        数据结构是有着某种逻辑结构的数据集合.数据集合的物理层是数组和链表.以链表为物理层的数据结构有链栈,链队列,二叉树等许多.他们有哪些共同特征呢?

        一是有结点类,把将要加入数据结构的数据,放入结点

        二是有头结点.在初始化容器时,把头结点建立起来.

        三是有增删查算法(栈和队列不需要查,可以不定义).四根据需要开发其他算法.

小结

        本贴没有用template泛型定义,适用面窄.用模板来做可以提高通用性,内部类可以方便实现更多功能,在后续数据结构中,用模板实现.

         数据结构是编程比较难的部分,考验逻辑思维能力.编写的代码也容易出bug,要反复调试,考验耐心.但也比较有趣,可以自己提需求自己实现(连最基本的链表都有很多"玩法"),同时也是比较有价值的部分.虽然有很多成熟代码可以用,但是代码要多写手熟

        

        

       

         

         

         

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

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

相关文章

鸿蒙 画布来了 我不允许你不会

前言: 作者:徐庆 团队:坚果派 公众号:“大前端之旅” 润开鸿生态技术专家,华为HDE,CSDN博客专家,CSDN超级个体,CSDN特邀嘉宾,InfoQ签约作者,OpenHarmony布道师,电子发烧友专家博客,51CTO博客专家,擅长HarmonyOS/OpenHarmony应用开发、熟悉服务卡片开发。欢迎合作…

WPF+MvvmLight 项目入门完整教程(一)

WPF+MvvmLight入门完整教程一 创建项目MvvmLight框架安装完善整个项目的目录结构创建自定义的字体资源下载更新和使用字体资源创建项目 打开VS2022,点击创建新项目,选择**WPF应用(.NET Framework)** 创建一个名称为 CommonProject_DeskTop 的项目,如下图所示:MvvmLight框架…

OpenCV开发笔记(七十八):在ubuntu上搭建opencv+python开发环境以及匹配识别Demo

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/140435870 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

【Nuxt3】vue3+tailwindcss+vuetify引入自定义字体样式

一、目的 在项目中引入自定义的字体样式&#xff08;全局页面都可使用&#xff09; 二、步骤 1、下载好字体 字体的后缀可以是ttf、otf、woff、eot或者svg&#xff08;推荐前三种&#xff09; 以抖音字体为例下载好放在静态文件夹&#xff08;font&#xff09;下 案例字…

【论文阅读】《Visual Prompt Tuning》

Abstract. 目前调整预训练模型的工作方式包括更新所有骨干参数&#xff0c;即全面微调。本文介绍了视觉提示调整&#xff08;VPT&#xff09;&#xff0c;作为大规模视觉变换器模型全面微调的高效替代方案。VPT 从高效调整大型语言模型的最新进展中汲取灵感&#xff0c;只在输…

软件测试——面试八股文(入门篇)

今天给大家分享软件测试面试题入门篇&#xff0c;看看大家能答对几题 一、 请你说一说测试用例的边界 参考回答&#xff1a; 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充&#xff0c;这种情况下&#xff…

IAR全面支持芯驰科技E3系列车规MCU产品E3119/E3118

中国上海&#xff0c;2024年7月11日 — 全球领先的嵌入式系统开发软件解决方案供应商IAR与全场景智能车芯引领者芯驰科技宣布进一步扩大合作&#xff0c;最新版IAR Embedded Workbench for Arm已全面支持芯驰科技的E3119/E3118车规级MCU产品。IAR与芯驰科技有着悠久的合作历史&…

线程池及其底层工作原理

一、线程池是什么 线程池就是事先将多个线程对象放到一个容器中&#xff0c;当使用的时候就不用 new 线程而是直接去池中拿线程即可&#xff0c;节省了开辟子线程的时间&#xff0c;提高的代码执行效率在 JDK 的 java.util.concurrent.Executors 中提供了生成多种线程池的静态方…

分页stater

自定义aop,以添加注解的方法为切入点&#xff0c;对目标方法做一层增强 PageXAop代码如下&#xff1a; package cn.smart.pagex.aop;import com.github.pagehelper.PageHelper; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.a…

漏洞复现 | Showdoc反序列化

非常简单的一个靶场 靶场地址&#xff1a;https://hack.zkaq.cn/ 打开靶场&#xff0c;弹出了这种登录框&#xff0c;这也成为了后面的一个坑点&#xff0c;记住这个登录框。 看到了注册功能&#xff0c;showdoc有注册功能我们就不用尝试前台SQL注入了&#xff0c;直接注册…

Verilog基础:简单标识符和转义标识符

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 标识符(identifier)是一个为了引用而给一个对象起的名字。一个标识符可以是一个简单标识符&#xff0c;也可以是一个转义标识符。本文将对两者进行详细阐述。 简…

Nuxt.js 错误侦探:useError 组合函数

title: Nuxt.js 错误侦探&#xff1a;useError 组合函数 date: 2024/7/14 updated: 2024/7/14 author: cmdragon excerpt: 摘要&#xff1a;文章介绍Nuxt.js中的useError组合函数&#xff0c;用于统一处理客户端和服务器端的错误&#xff0c;提供statusCode、statusMessage和…

【C++】—— 初识C++

【C】—— 初识C 一、什么是 C二、C 的发展历史三、C 版本更新四、C 的重要性五、C 在工作领域中的运用六、C 书籍推荐&#xff1a; 一、什么是 C C语言 是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要…

k8s快速部署一个网站

1&#xff09;使用Deployment控制器部署镜像&#xff1a; kubectl create deployment web-demo --imagelizhenliang/web-demo:v1 kubectl get deployment,pods[rootk8s-matser ~]# kubectl get pods NAME READY STATUS RESTARTS A…

STM32 BootLoader 刷新项目 (四) 通信协议

STM32 BootLoader 刷新项目 (四) 通信协议 文章目录 STM32 BootLoader 刷新项目 (四) 通信协议1. 通信流程2. 支持指令3. 通信流程4. 指令结构5. 操作演示 前面几章节&#xff0c;我们已经介绍了BootLoader的整体程序框架&#xff0c;方案设计&#xff0c;以及STM32CubdeMX的配…

数据结构(4.0)——串的定义和基本操作

串的定义(逻辑结构) 串&#xff0c;即字符串(String)是由零个或多个字符组成的有序数列。 一般记为Sa1a2....an(n>0) 其中&#xff0c;S是串名&#xff0c;单引号括起来的字符序列是串的值;ai可以是字母、数字或其他字符&#xff1b;串中字符的个数n称为串的长度。n0时的…

常开常闭液位传感器怎么选

在选择常开常闭传感器时&#xff0c;关键是根据其工作原理和应用需求来进行合适的选择&#xff0c;以确保系统的正常运行和效率。常开和常闭传感器的设计在信号输出时有明显差异&#xff0c;因此在不同的控制系统中选择合适的类型至关重要。 常开传感器的特点是在没有检测到目…

Nginx的访问限制与访问控制

访问限制 访问限制是一种防止恶意访问的常用手段&#xff0c;可以指定同一IP地址在固定时间内的访问次数&#xff0c;或者指定同一IP地址在固定时间内建立连接的次数&#xff0c;若超过网站指定的次数访问将不成功。 请求频率限制配置 请求频率限制是限制客户端固定时间内发…

C#小结:未能找到类型或命名空间名“xxx”(是否缺少 using 指令或程序集引用?)

方案一&#xff1a;移除这些失效的引用&#xff0c;下载对应版本的dll&#xff0c;重新添加引用 方案二&#xff1a;项目右键属性-调整目标框架版本&#xff08;一般是降低版本&#xff09; 方案三&#xff1a;调整编译顺序&#xff1a; 项目A&#xff1a;引用1、引用2 &…

鸿蒙架构之AOP

零、主要内容 AOP 简介ArkTs AOP 实现原理 JS 原型链AOP实现原理 AOP的应用场景 统计类&#xff1a; 方法调用次数统计、方法时长统计防御式编程&#xff1a;参数校验代理模式实现 AOP的注意事项 一、AOP简介 对于Android、Java Web 开发者来说&#xff0c; AOP编程思想并不…