啊哈!算法-第2章-栈、队列、链表

news2025/1/10 20:39:18

啊哈!算法-第2章-栈、队列、链表

  • 第1节 解密qq号——队列
  • 第2节 解密回文——栈
  • 第3节 纸牌游戏——小猫钓鱼
  • 第4节 链表
  • 第5节 模拟链表

第1节 解密qq号——队列

  1. 新学期开始了,小哈是小哼的新同桌(小哈是个大帅哥哦~),小哼向小哈询问 QQ 号, 小哈当然不会直接告诉小哼啦,原因嘛你懂的。所以小哈给了小哼一串加密过的数字,同时 小哈也告诉了小哼解密规则。规则是这样的:首先将第 1 个数删除,紧接着将第 2 个数放到 这串数的末尾,再将第 3 个数删除并将第 4 个数放到这串数的末尾,再将第 5 个数删除… 直到剩下最后一个数,将最后一个数也删除。按照刚才删除的顺序,把这些删除的数连在一 起就是小哈的 QQ 啦。现在你来帮帮小哼吧。小哈给小哼加密过的一串数是“5 3 0 3 9 3 0 1”。
密文删除的数字移到最后的数字QQ号
53039301535
03930130350
93013393509
01333015090
33313350903
31331509033
3135090333
1150903331

解密的第一步是将第一个数删除,你可以想一下如何在数组中删除一个数呢。最简单的 方法是将所有后面的数都往前面挪动一位,将前面的数覆盖。就好比我们在排队买票,最前 面的人买好离开了,后面所有的人就需要全部向前面走一步,补上之前的空位,但是这样的 做法很耗费时间。
在这里,我将引入两个整型变量 head 和 tail。head 用来记录队列的队首(即第一位), tail 用来记录队列的队尾(即最后一位)的下一个位置。你可能会问:为什么 tail 不直接记 录队尾,却要记录队尾的下一个位置呢?这是因为当队列中只剩下一个元素时,队首和队尾重合会带来一些麻烦。我们这里规定队首和队尾重合时,队列为空。
现在有 n 个数,n 个数全部放入队列之后 head = 0;tail = strlen(QQ);此时 head 和 tail 之间的数就是
目前队列中“有效”的数。如果要删除一个数的话,就将 head++就 OK 了,这样仍然可以保 持 head 和 tail 之间的数为目前队列中“有效”的数。这样做虽然浪费了一个空间,却节省了 大量的时间,这是非常划算的。新增加一个数也很简单,把需要增加的数放到队尾即 q[tail] 之后再 tail++就 OK 啦。

  1. 在队首删除一个数的操作是 head++;
  2. 在队尾增加一个数(假设这个数是 x)的操作是 q[tail] = x; tail++;
  3. 以上操作重复执行若干次,直到head < tail结束即可
#include<iostream>

using namespace std;

const int maxn = 100;
int head, tail;
char QQ[maxn];
int main(){
    cin >> QQ;
    head = 0; // head指向密文的开始位置,tail指向密文的结束位置+1
    tail = strlen(QQ);
    // 当队列不为空的时候执行循环
    while (head < tail){
        // 打印队首,并将队首出队
        cout << QQ[head++];
        //先将新队首的数添加到队尾,再将队首出队
        QQ[tail++] = QQ[head++];
        
    }
    return 0;
}

队列是一种特 殊的线性结构,它只允许在队列的首部(head)进行删除操作,这称为“出队”,而在队列 的尾部(tail)进行插入操作,这称为“入队”。
当队列中没有元素时(即 head==tail),称为 空队列。
“先进先出”(First In First Out,FIFO)原则。

struct queue{
	int data[100]; // 队列的主体,用来存储内容
	int head; // 队首
	int tail; // 队尾
};

上面定义了一个结构体类型,我们通常将其放在 main 函数的外面,请注意结构体的定 义末尾有个;号。struct 是结构体的关键字,queue 是我们为这个结构体起的名字。这个结构 体有三个成员分别是:整型数组 data、整型 head 和整型 tail。这样我们就可以把这三个部分 放在一起作为一个整体来对待。你可以这么理解:我们定义了一个新的数据类型,这个新类 型非常强大,用这个新类型定义出的每一个变量可以同时存储一个整型数组和两个整数。
在这里插入图片描述

有了新的结构体类型,如何定义结构体变量呢?很简单,这与我们之前定义变量的方式 是一样的,具体做法如下。

struct queue QQ;

请注意 struct queue 需要整体使用,不能直接写 queue q;。这样我们就定义了一个结构体 变量 q。这个结构体变量就可以满足队列的所有操作了。那又该如何访问结构体变量的内部 成员呢?可以使用.号,它叫做成员运算符或者点号运算符,如下:

QQ.head = 1;
QQ.tail = 1;
scanf("%d", &QQ.data[q.tail]);

下面这段代码就是使用结构体来实现的队列操作。

#include<iostream>

using namespace std;

struct queue{
    string data; // 队列主体,用来存储内容
    int head, tail; // 队首和队尾
};

int main(){
    queue QQ;
    cin >> QQ.data;
    // 初始化队列
    QQ.head = 0;
    QQ.tail = QQ.data.length();
    // //当队列不为空的时候执行循环
    while (QQ.head <= QQ.tail){
        cout << QQ.data[QQ.head]; //打印队首
        QQ.head++; // 将队首出队
        QQ.data[QQ.tail] = QQ.data[QQ.head];  // 先将新队首的数添加到队尾
        QQ.head++; // 再将队首出队
        QQ.tail++;
    }
    return 0;
}

第2节 解密回文——栈

栈是后进先出的数据 结构。它限定为只能在一端进行插入和删除操作。比如说有一个小桶,小桶的直 径只能放一个小球,我们现在小桶内依次放入 2、1、3 号小球。假如你现在需要拿出 2 号小球, 那就必须先将 3 号小球拿出,再拿出 1 号小球,最后才能将 2 号小球拿出来。在刚才取小球的 过程中,我们最先放进去的小球最后才能拿出来,最后放进去的小球却可以最先拿出来。

在这里插入图片描述

栈究竟有哪些作用呢?我们来看一个例子。“xyzyx”是一个回文字符串,所谓回文字符 串就是指正读反读均相同的字符序列,如“席主席”、“记书记”、“aha”和“ahaha”均是回 文,但“ahah”不是回文。通过栈这个数据结构我们将很容易判断一个字符串是否为回文。
首先我们需要读取这行字符串,并求出这个字符串的长度。

char arr[100];
int len;
cin >> arr;
len = strlen(arr);

如果一个字符串是回文的话,那么它必须是中间对称的,我们需要求中点,即:

mid = len / 2 + 1;

接下来就轮到栈出场了。
我们先将 mid 之前的字符全部入栈。因为这里的栈是用来存储字符的,所以这里用来实 现栈的数组类型是字符数组即 char s[101];,初始化栈很简单,top = 0;就可以了。入栈的操作 是top++; s[top] = x(;假设需要入栈的字符暂存在字符变量x中),其实可以简写为arr[++top] = x;。
现在我们就来将 mid 之前的字符依次全部入栈。

for (int i = 0; i <= mid; i++){
	s[++top] = arr[i];

接下来进入判断回文的关键步骤。将当前栈中的字符依次出栈,看看是否能与 mid 之后 的字符一一匹配,如果都能匹配则说明这个字符串是回文字符串,否则这个字符串就不是回 文字符串。

for(i = mid+1; i <= len - 1; i++){
    if (a[i] != s[top]){
		break; 
	}
	top--; 
}
if(top == 0)
    printf("YES");
else
    printf("NO");

最后如果 top 的值为 0,就说明栈内所有的字符都被一一匹配了,那么这个字符串就是 回文字符串。完整的代码如下。

#include<iostream>

using namespace std;
const int maxn = 200;
int main(){
    char arr[maxn], s[maxn];
    int len, mid, next, top;
    cin >> arr; // 读入一行字符串
    len = strlen(arr); // 求字符串的长度
    mid = len / 2 - 1; // 求字符串的终点
    
    top = 0; // 栈的初始化
    // 将mid前的字符一次入栈
    for (int i = 0; i <= mid; i++){
        s[++top] = arr[i];
    }
    // 判断字符串的长度是奇数还是偶数,并找出需要进行字符匹配的起始下标
    if (len % 2 == 0){
        next = mid + 1;
    }else{
        next = mid + 2;
    }
    // 开始匹配
    for (int i = next; i < len; i++){
        if (arr[i] != s[top]){
            break;
        }
        top--;
    }
    // 如果top的值为0,则说明栈内所有的字符都被一一匹配了
    if (top == 0){
        cout << "YES";
    }else{
        cout << "NO";
    }
    return 0;
}

第3节 纸牌游戏——小猫钓鱼

星期天小哼和小哈约在一起玩桌游,他们正在玩一个非常古怪的扑克游戏——“小猫钓 鱼”。游戏的规则是这样的:将一副扑克牌平均分成两份,每人拿一份。小哼先拿出手中的 第一张扑克牌放在桌上,然后小哈也拿出手中的第一张扑克牌,并放在小哼刚打出的扑克牌 的上面,就像这样两人交替出牌。出牌时,如果某人打出的牌与桌上某张牌的牌面相同,即可将两张相同的牌及其中间所夹的牌全部取走,并依次放到自己手中牌的末尾。当任意一人 手中的牌全部出完时,游戏结束,对手获胜。

假如游戏开始时,小哼手中有 6 张牌,顺序为 2 4 1 2 5 6,小哈手中也有 6 张牌,顺序 为 3 1 3 5 6 4,最终谁会获胜呢?现在你可以拿出纸牌来试一试。接下来请你写一个程序来 自动判断谁将获胜。这里我们做一个约定,小哼和小哈手中牌的牌面只有 1~9。
在这里插入图片描述
我们先来分析一下这个游戏有哪几种操作。小哼有两种操作,分别是出牌和赢牌。这恰 好对应队列的两个操作,出牌就是出队,赢牌就是入队。小哈的操作和小哼是一样的。而桌 子就是一个栈,每打出一张牌放到桌上就相当于入栈。当有人赢牌的时候,依次将牌从桌上 拿走,这就相当于出栈。那如何解决赢牌的问题呢?赢牌的规则是:如果某人打出的牌与桌 上的某张牌相同,即可将两张牌以及中间所夹的牌全部取走。那如何知道桌上已经有哪些牌 了呢?最简单的方法就是枚举桌上的每一张牌,当然也有更好的办法我们待会再说。OK, 小结一下,我们需要两个队列、一个栈来模拟整个游戏。

首先我们先来创建一个结构体用来实现队列,如下。

struct queue{
  int data[1000];
  int head;
  int tail;
}

上面代码中 head 用来存储队头,tail 用来存储队尾。数组 data 用来存储队列中的元素, 数组 data 的大小我预设为 1000,其实应该设置得更大一些,以防数组越界。当然对于本题 的数据来说 1000 已经足够了。
再创建一个结构体用来实现栈,如下。

struct stack{
	int data[10];
	int top;
};

其中 top 用来存储栈顶,数组 data 用来存储栈中的元素,大小设置为 10。因为只有 9 种不同的牌面,所以桌上最多可能有 9 张牌,因此数组大小设置为 10 就够了。提示一下: 为什么不设置为 9 呢?因为 C ++数组下标是从 0 开始的。

接下来我们需要定义两个队列变量 q1 和 q2。q1 用来模拟小哼手中的牌,q2 用来模拟小 哈手中的牌。定义一个栈变量 s 用来模拟桌上的牌。

struct queue heng, ha;
struct stack table;

接下来来初始化一下队列和栈。

// 初始化队列heng, ha为空,此时两人手中都还没有牌
heng.head = 1;
heng.tail = 1;
ha.head = 1;
ha.tail = 1;
// 初始化栈table为空,最开始的时候桌上也没有牌
table.top = 0;

未完待续… …

第4节 链表

第5节 模拟链表

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

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

相关文章

揭秘:如何使用Python统计女友生日还剩几天?

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;为何需要统计生日天数&#xff1f; 二、需求分析与准备 1. 用户输入格…

【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)

&#x1f50d;目的 允许派生组件从与派生类型兼容的基本组件继承某些功能。 &#x1f50d;解释 真实世界例子 对于正在策划赛事的综合格斗推广活动来说&#xff0c;确保在相同重量级的运动员之间组织比赛至关重要。这样可以防止体型明显不同的拳手之间的不匹配&#xff0c;例如…

云服务器平台AutoDL--基本介绍与使用感受

因为课程作业需要复现DreamBooth&#xff0c;找了几个教程之后&#xff0c;发现了AutoDL这个好东西&#xff0c;芜湖~ 相关概念 以下回答来自于ChatGPT。 云计算平台&#xff1a;云服务器平台是提供按需计算资源和服务的在线平台&#xff0c;通常包括存储、处理能力、数据库、…

Servlet跳转404(解决)

1.解决无法跳转的404问题&#xff08;最根本&#xff0c;最重要&#xff09; 查看Project Structure&#xff0c;检查你的JDK版本不要选错版本&#xff1b; 2.页面跳转&#xff0c;url栏输入的是web.xml中的url-pattern内容&#xff0c;请仔细检查 3.关于配置信息Applicatio…

TIM输出比较

一、OC&#xff08;Output Compare&#xff09;输出比较 1、输出比较可以通过比较CNT&#xff08;计数器&#xff09;与CCR&#xff08;捕获/比较寄存器&#xff09;寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PW…

C++之对象的使用

1、static成员 2、static成员优点 2、static成员函数 静态成员函数不能访问非静态成员原因&#xff1a;因为没有this指针。也不可以访问非静态成员函数。 可以通过对象来访问静态成员&#xff0c;但是不推荐这么使用&#xff0c;会让人误解成这个x_是属于对象的&#xff0c;但…

Unity3D插件开发教程(二):制作批处理工具

Unity3D插件开发教程&#xff08;二&#xff09;&#xff1a;制作批处理工具 文章来源&#xff1a;Unity3D插件开发教程&#xff08;二&#xff09;&#xff1a;制作批处理工具 - 知乎 (zhihu.com) 声明&#xff1a; 题图来自于Gratisography | Free High Resolution Pictures…

区块链的运行原理与演示

目录 前言 具体演示 1、在浏览器中输入区块链演示网址&#xff1a; 2、创建新区块 3、篡改区块信息使其无效 4、新增P2P 网络节点。 5、节点连接。 6、区块信息同步 总结 前言 区块链系统是由一系列分布在全球各地的分布式节点组成的。这些节点互不隶属&#xff0c;通过…

目标检测基础初步学习

目标检测&#xff08;Object Detection&#xff09; 目标检测任务说明 在动手学习深度学习中对目标检测任务有如下的描述。 图像分类任务中&#xff0c;我们假设图像中只有一个主要物体对象&#xff0c;我们只关注如何识别其类别。 然而&#xff0c;很多时候图像里有多个我们…

中心入侵渗透

问题1. windows登录的明文密码&#xff0c;存储过程是怎么样的&#xff1f;密文存在哪个文件下&#xff1f;该文件是否可以打开&#xff0c;并且查看到密文&#xff1f; 回答&#xff1a; Windows登录的明文密码的存储过程是&#xff1a; 当用户尝试登录Windows时&#xff0…

MM模块六(收货)

接到供应商收到的货以后&#xff0c;进行一个收货的动作 收货&#xff1a;MIGO 1.消耗物料的采购订单 数量是供应商的数量 消耗物料的采购订单&#xff0c;收进来的货物直接进入消耗&#xff0c;不会增加库存&#xff0c;所以这里没有库存地点进行选择 点击过账 收货后在采购…

ubuntu 配置用户登录失败尝试次数限制

前言&#xff1a; 通过修改pam配置来达到限制密码尝试次数&#xff01; 1&#xff1a;修改 /etc/pam.d/login 配置&#xff08;这里只是终端登录配置&#xff0c;如果还需要配置SSH远程登录限制&#xff0c;只配置下面的 /etc/pam.d/pam.d/common-auth 即可&#xff09; vim…

go-zero 实战(1)

环境准备 go 版本 go version go1.22.2 linux/amd64 goctl 安装 goctl&#xff08;官方建议读 go control&#xff09;是 go-zero微服务框架下的代码生成工具。使用 goctl 可以显著提升开发效率&#xff0c;让开发人员将时间重点放在业务开发上&#xff0c;其功能有&#xff1a…

【东山派Vision K510开发板试用笔记】WiFi配网问题

目录 概述 WiFi配网的修改 悬而未决的问题 概述 最近试用了百问网提供的东山派Vision开发板&#xff0c;DongshanPI-Vision开发板是百问网针对AI应用开发设计出来的一个RSIC-V架构的AI开发板&#xff0c;主要用于学习使用嘉楠的K510芯片进行Linux项目开发和嵌入式AI应用开发…

手撕C语言题典——返回倒数第 k 个节点(面试题)

前言 依旧力扣&#xff0c;这道题之前有做过类似的题&#xff0c;今天给一个新的思路去做&#xff0c;应对面试时候遇到的奇奇怪怪的问题 面试题 02.02. 返回倒数第 k 个节点 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/kth-node-from-end-of-list-…

英特尔LLM技术挑战记录

英特尔技术介绍&#xff1a; Flash Attention Flash Attention 是一种高效的注意力机制实现&#xff0c;旨在优化大规模 Transformer 模型中的自注意力计算。在深度学习和自然语言处理领域&#xff0c;自注意力是 Transformer 架构的核心组件&#xff0c;用于模型中不同输入元…

PMP报考条件怎么查询?如何判定自己是否符合条件?

PMP报考条件在PMI官网上就可以查询&#xff0c;PMP报考条件只需要符合项目管理培训经历和项目管理经验两个方面的要求即可&#xff0c;大家可以对照下方的规定判断自己是否符合PMP报名条件 PMP报考条件 以下是PMI&#xff08;中国&#xff09;官网对于PMP报名条件的规定&…

3D点云焊缝提取 平面交线 投影

文章目录 1. 效果2. 思路3. 源码 1. 效果 2. 思路 计算点云法向量&#xff1b;计算点云位姿Pose;翻转Pose中的Z轴方向&#xff0c;使其一致&#xff1b;通过Pose的Z轴对点云进行方向过滤&#xff1b;对点云聚类&#xff1b;根据目标点云的高度提取目标点云&#xff1b;提取两块…

Unity Dotween 定位点的制作

目录 前言 一、动画预览 二、动画拆分 三、素材准备 四、曲线 OutCirc详解 五、速度分类详解 六、代码 七、组件和设置 八、作者的话 前言 我答应我的粉丝接下来更新Dotween系列&#xff0c;但是我一直没想好&#xff0c;从哪里开始讲。 Dotween的安装我就跳过了&…

Java基础之 API 字符串

文章目录 API字符串String概述创建对象 java的内存模型java的常用方法(比较)练习 API 概念: APl(Application ProgrammingInterface): 应用程序编程接口 简单理解: API就是别人已经写好的东西&#xff0c;我们不需要自己编写&#xff0c;直接使用即可。 Java API: 指的就是J…