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

news2024/9/19 10:34:16

前言

       "打牢基础,万事不愁" .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;				//返回true
		cout << "没找到数据:"<<data << endl;	
		return false;					//遍历链表没找到数据,返回false
	}
	/*打印链表数据*/
	int printLinkList() {
	//下面这行如果用Node *p=firstNode;打印出来的是头结点值0
		Node* 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.coloradmin.cn/o/1916859.html

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

相关文章

K8S中部署 Nacos 集群

1. 准备 GitK8Skubectlhelm 咱也没想到 K8S 部署系列能搞这么多次&#xff0c;我一个开发天天干运维的活&#xff0c;前端后端运维测试工程师实至名归。 2. 方案选择 https://github.com/nacos-group/nacos-k8s 我替你们看了一下&#xff0c;有好几种方式能部署&#xff…

极狐Gitlab安装部署

GitLab 是一个基于 Git 的开源 DevOps 平台&#xff0c;提供代码仓库管理、CI/CD&#xff08;持续集成和持续交付&#xff09;、项目管理、监控和安全等功能。它集成了多种工具&#xff0c;帮助开发团队在一个平台上进行代码开发、测试、部署和运维。以下是 GitLab 的主要功能和…

LLM - 绝对与相对位置编码 与 RoPE 旋转位置编码 源码

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/140281680 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 Transformer 是基于 MHSA (多头自注意力),然而,MHSA 对于位置是不敏感…

自定义类型:联合体

像结构体一样&#xff0c;联合体也是由一个或者多个成员组成&#xff0c;这些成员可以是不同的类型。 联合体类型的声明 编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫&#xff1a;共⽤体。 输出结果&#xff1a; 联合体…

AcWing 3381:手机键盘

【题目来源】https://www.acwing.com/problem/content/3384/【题目描述】 请你计算按照手机键盘&#xff08;9键输入法&#xff09;输入字母的方式&#xff0c;键入给定字符串&#xff08;由小写字母构成&#xff09;所花费的时间。 具体键入规则和花费时间如下描述&#xff1a…

科普文:Java对象在堆中的内存结构

概叙 今天来讲些抽象的东西 -- 对象头&#xff0c;因为我在学习的过程中发现很多地方都关联到了对象头的知识点&#xff0c;例如JDK中的 synchronized锁优化 和 JVM 中对象年龄升级等等。 对象内存构成# Java 中通过 new 关键字创建一个类的实例对象&#xff0c;对象存于内存的…

【人工智能】-- 反向传播

个人主页&#xff1a;欢迎来到 Papicatch的博客 课设专栏 &#xff1a;学生成绩管理系统 专业知识专栏&#xff1a; 专业知识 文章目录 &#x1f349;引言 &#x1f349;反向传播 &#x1f348;定义 &#x1f348;反向传播的作用 &#x1f34d;参数优化 &#x1f34d;学…

软件测试学习之-ADB命令

ADB命令 adb工具即Android Debug Bridge&#xff08;安卓调试桥&#xff09; tools。它就是一个命令行窗口&#xff0c;用于通过电脑端与模拟器或者真实设备交互。在某些特殊的情况下进入不了系统&#xff0c;adb就派上用场啦&#xff01; Android程序的开发通常需要使用到一…

解决Anaconda下载pytorch常见问题

1.问题一 安装完Anaconda后&#xff0c;输入conda命令&#xff0c;出现 conda不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 分析原因&#xff1a;未配置环境到系统变量 解决方法&#xff1a;将Anaconda安装路径和Anaconda目录下的Scripts文件的路径配…

本地部署,GFPGAN: 实用的面部修复算法

目录 什么是 GFPGAN&#xff1f; 技术原理 主要功能 应用场景 本地安装 运行结果 结语 Tip&#xff1a; 在图像处理和计算机视觉领域&#xff0c;面部修复是一个重要且具有挑战性的研究方向。随着深度学习技术的不断进步&#xff0c;许多新的算法被提出&#xff0c;用于…

Linux笔记之使用系统调用sendfile高速拷贝文件

Linux笔记之使用系统调用sendfile高速拷贝文件 code review! 文章目录 Linux笔记之使用系统调用sendfile高速拷贝文件sendfile 性能优势sendfile 系统调用优点&#xff1a;缺点&#xff1a; cp 命令优点&#xff1a;缺点&#xff1a; 实际测试&#xff1a;拷贝5.8个G的文件&a…

《Windows API每日一练》9.1.5 自定义资源

自定义资源&#xff08;Custom Resources&#xff09;是在 Windows 程序中使用的一种资源类型&#xff0c;用于存储应用程序特定的数据、图像、音频、二进制文件等。通过自定义资源&#xff0c;开发者可以将应用程序所需的各种资源文件集中管理和存储&#xff0c;便于在程序中访…

开源可视化Flutter图表库:Graphic

Graphic&#xff1a;用Graphic绘制数据的无限可能- 精选真开源&#xff0c;释放新价值。 概览 Graphic&#xff0c;这个基于Flutter的图表库&#xff0c;以其源自《The Grammar of Graphics》的灵感&#xff0c;为数据可视化提供了一种全新的方法。它不仅仅是一个工具&#xf…

安全策略与用户认证综合实验

一、实验拓扑 二、实验需求 1,DMZ区内的服务器,办公区仅能在办公时间内(9:00-18:00)可以访问,生产区的设备全天可以访问. 2,生产区不允许访问互联网,办公区和游客区允许访问互联网 3,办公区设备10.0.2.10不允许访问DMz区的FTP服务器和HTTP服务器,仅能ping通10.0.3.10 4,办公区…

【运维】docker批量删除临时镜像(两种方式)

docker批量删除Tag<none>的临时镜像 在开发的时候&#xff0c;需要经常发布开发包&#xff0c;在使用docker build构建镜像的时候&#xff0c;同一个版本经常会使用相同tag&#xff0c;频繁打包一段时间后&#xff0c;本地会出现很多Tag<none>的临时镜像&#xff…

WordPress知识付费系统+自动采集插件

采集功能&#xff1a; 1.支持分类替换 将主站同步过来的文章分类进行替换 2.支持自定义文章作者&#xff08;选择多个作者则同步到的文章作者将会随机分配&#xff09; 3.支持添加黑名单分类 添加后 如果同步过来的文章包含黑名单分类将不会发布文章 4.自动检测同步&#xf…

禁止使用存储过程

优质博文&#xff1a;IT-BLOG-CN 灵感来源 什么是存储过程 存储过程Stored Procedure是指为了完成特定功能的SQL语句集&#xff0c;经编译后存储在数据库中&#xff0c;用户可通过指定存储过程的名字并给定参数&#xff08;如果该存储过程带有参数&#xff09;来调用执行。 …

wifi ping ip地址可以但是域名失败

需求&#xff1a; 当连接上wifi之后获取&#xff0c;能正常获取IP并且能ping ip地址&#xff0c;但是不能ping域名&#xff0c;比如ping www.baidu.com 会显示坏地址 解决&#xff1a; 在/etc/resolv.conf中添加域名即可

NLP入门——词袋语言模型的搭建、训练与预测

卷积语言模型实际上是取了句子最后ctx_len个词作为上下文输入模型来预测之后的分词。但更好的选择是我们做一个词袋&#xff0c;将所有分词装在词袋中作为上下文&#xff0c;这样预测的分词不只根据最后ctx_len个分词&#xff0c;而是整个词袋中的所有分词。 例如我们的序列是&…

以太网的演变之路:技术进步与应用拓展

最初的以太网是由美国施乐&#xff08;Xerox&#xff09;公司的Palo Alto研究中心&#xff08;简称为PARC&#xff09;于1975年研制成功的。以太网从标准以太网&#xff08;10Mbit/s&#xff0c;也称为传统以太网&#xff09;开始逐步在有线局域网市场中占据了统治地位&#xf…