Java玩转《啊哈算法》解密QQ号之队列

2024-02-02 13:52

本文主要是介绍Java玩转《啊哈算法》解密QQ号之队列,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

行有不得,反求诸己

文章目录

  • 开头
  • 代码地址
  • 引子
    • 案例
    • 分析
    • 代码
  • 队列
    • 封装
    • 升级
    • 演示

开头

各位好!本人在看《啊哈算法》,写的确实不错。

但略微遗憾的是,书籍示例代码是c语言,不是本人常用的Java。

那就弥补遗憾,说干就干,把这本书的示例语言用java过一遍, 顺便附上自己的一些理解!

于是就有了本篇博客,本篇博客主要是讲常见数据结构的一种:队列。

在这里插入图片描述

来不及买纸质书但又想尽快感受算法魅力的童鞋也甭担心,电子版的下载链接已经放到下方了,可尽情下载。

链接:https://pan.baidu.com/s/1imxiElcCorw2F-HJEnB-PA?pwd=jmgs
提取码:jmgs

在这里插入图片描述

代码地址

本文代码已开源:

git clone https://gitee.com/guqueyue/my-blog-demo.git

请切换到gitee分支,

然后查看aHaAlgorithm模块下的src/main/java/com/guqueyue/aHaAlgorithm/chapter_2_StackAndChainTable即可!

引子

案例

在书中,作者直接给出了一个案例来引出队列这个概念:

新学期开始了,小哈是小哼的新同桌(小哈是个小美女哦~),小哼向小哈询问QQ号,小哈当然不会直接告诉小哼啦,原因嘛你懂的。所以小哈给了小哼一串加密过的数字,同时小哈也告诉了小哼解密规则。

规则是这样的:首先将第1个数删除,紧接着将第2个数放到这串数的末尾,再将第3个数删除并将第4个数放到这串数的末尾,再将第5个数删除……直到剩下最后一个数,将最后一个数也删除。按照刚才删除的顺序,把这些删除的数连在一起就是小哈的QQ啦

现在你来帮帮小哼吧。小哈给小哼加密过的一串数是“6 3 1 7 5 8 9 2 4”。

在这里插入图片描述

分析

那么,如何通过抽象化的编程来解决这个具体化的问题呢?

其实很简单,只需要三步即可!!!

  1. 首先,我们需要声明一个数组用来存储QQ号,这里其实我们就是用数组来模拟队列。
  2. 其次,我们要运用双指针的思想,声明一个头指针和一个尾指针。头指针指向队列头部,尾指针指向队列尾部后一位。
  3. 然后,我们只需要一直执行第一个元素出队并打印,下一个元素出队并入队的操作,直至两个指针相遇即队列为空便可。

下面是整体的流程图:
在这里插入图片描述

代码

根据上文的分析,我们不难编写出以下代码:

package com.guqueyue.aHaAlgorithm.chapter_2_StackAndChainTable;/*** @Author: guqueyue* @Description: 解密QQ - 本质是以数组模拟队列* @Date: 2024/1/11**/
public class DecodeQQ {public static void main(String[] args) {// 加密过的qq号int[] qq = {6, 3, 1, 7, 5, 8, 9, 2, 4};// 创建一个长度为101的队列int[] queue = new int[101];// 初始化队列:头指针head指向队列头部,尾指针tail指向队列尾部后一位int head = 0, tail = 0;// 初始化队列:tail为尾指针,指向队列尾部后一位for (int num : qq) {queue[tail++] = num;}// 破解qq号while (head < tail) { // 队列不能为空// 打印队首并出队System.out.print(queue[head++] + " ");// 将队首的数字放到队尾queue[tail++] = queue[head++];}System.out.println();}
}

运行代码,可得:
在这里插入图片描述

队列

在上文中,我们看似用的是 数组双指针的方法,其实我们运用的是队列的思想。

当然,用链表也能实现栈,这里我们就不讲了。

队列,顾名思义,就是跟排队一样,先到的人先买票,后到的人后买票
在这里插入图片描述

也就是说,队列只有两种操作:

  1. 队首的人出队
  2. 新来的人入队

这里面有一个非常重要的核心概念 - FIFO(First In First Out) - 先进先出

与之对应的我们后面要讲到的栈,它是先进后出。队列和栈可以说是算法里面比较核心的两种数据结构了,不容小视。

封装

为了方便使用,减少重复性代码,我们可以专门封装一个队列类:

package com.guqueyue.aHaAlgorithm.entity;/*** @Author: guqueyue* @Description: 队列类 - 通过数组实现* @Date: 2024/1/11**/
public class Queue {public int[] data = new int[1001]; // 数组,用来储存内容public int head; // 队首public int tail; // 队尾@Overridepublic String toString() {String str = "";int head = this.head, tail = this.tail;while (head < tail) {str += data[head++] + " ";}str += "\n";return str;}
}

这里主要有三个核心:

  1. 用来存储元素的数组
  2. 队首指针
  3. 队尾指针
    在这里插入图片描述
    然后,跟原书不同的是:为了方便输出队列元素,我们还重写了队列类的toString()方法。

这样的话,我们使用队列,只需要创建一个队列对象。

出队只需要将队首指针+1,入队只需要根据队尾指针进行赋值操作,然后再将队尾指针+1即可。

如下代码,我们创建一个队列,将元素3入队,再出队为:

   Queue queue = new Queue(); // 创建队列queue.data[queue.tail++] = 3; // 将3入队queue.head++; // 再将3出队

升级

我们运用队列封装类,可以给上文的案例代码进行如下改装:

package com.guqueyue.aHaAlgorithm.chapter_2_StackAndChainTable;import com.guqueyue.aHaAlgorithm.entity.Queue;import java.util.Scanner;/*** @Author: guqueyue* @Description: 队列演示* @Date: 2024/1/11**/
public class QueueTest {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.print("你要输入几个数?:");int n = scanner.nextInt();// 初始化队列Queue queue = new Queue();System.out.printf("清输入%d个数,中间用空格隔开,再回车:", n);for (int i = 0; i < n; i++) {queue.data[queue.tail++] = scanner.nextInt();}System.out.print("解密后的qq号为:");while (queue.head < queue.tail) { // 队列不为空,则循环// 打印队首并出队System.out.print(queue.data[queue.head++] + " ");// 将队首移到队尾queue.data[queue.tail++] = queue.data[queue.head++];}System.out.println(); // 换行}
}

演示

运行代码,控制台输入,可得:

在这里插入图片描述

最后,放一段作者的吐槽:

队列的起源已经无法追溯。在还没有数字计算机之前,数学应用中就已经有对队列的记载了。
我们生活中队列的例子也比比皆是,比如排队买票,又或者吃饭时候用来排队等候的叫号机,又或者拨打银行客服选择人工服务时,每次都会被提示“客服人员正忙,请耐心等待”,因为客服人员太少了,拨打电话的客户需要按照打进的时间顺序进行等候等等。
这里表扬一下肯德基的宅急送,没有做广告的嫌疑啊,每次一打就通,基本不需要等待。
但是我每次打银行的客服(具体是哪家银行就不点名了)基本都要等待很长时间,总是告诉我“正在转接,请稍候”,嘟嘟嘟三声
后就变成“客服正忙,请耐心等待!”然后就给我放很难听的曲子。看来钱在谁那里谁就是老大啊……

这篇关于Java玩转《啊哈算法》解密QQ号之队列的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/670903

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2