《啊哈!算法》第二章 - 第一节 - 解密QQ号(Java实现)

《啊哈!算法》第二章 - 第一节- 解密QQ号(Java实现)

解密QQ号——队列

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

在这里插入图片描述
可以发现解密QQ号的过程就像是给数字 “ 排队 ”,我们每次从数字的最前面拿走两个数字,第 1 个扔掉,第 2 个放到数字的尾部。具体过程是这样的:

刚开始这串数是 “ 6 3 1 7 5 8 9 2 4
第 1 次:删除 6 并将 3 放到数字末尾,这串数更新为 “ 1 7 5 8 9 2 4 3 ”;
第 2 次:删除 1 并将 7 放到数字末尾,即更新为 “ 5 8 9 2 4 3 7 ”;
第 3 次:删除 5 并将 8 放到数字末尾,即更新为 “ 9 2 4 3 7 8 ”;
第 4 次:删除 9 并将 2 放到数字末尾,即更新为 “ 4 3 7 8 2 ”;
第 5 次:删除 4 并将 3 放到数字末尾,即更新为 “ 7 8 2 3 ”;
第 6 次:删除 7 并将 8 放到数字末尾,即更新为 “ 2 3 8 ”;
第 7 次:删除 2 并将 3 放到数字末尾,即更新为 “ 8 3 ”;
第 8 次:删除 8 并将 3 放到数字末尾,即更新为 “ 3 ”;
第 9 次:删除 3
因此被删除的数字的顺序是 “ 6 1 5 9 4 7 2 8 3 ”,这就是小哈的 QQ号码了

解密的规则和过程搞清楚了,现在我们就用代码来实现一下吧!

题目给了我们一串数字,因此我们需要用数组来存储这些数字,定义一个长度为100的数组,并初始化数组,即:

	System.out.println("请输入需要解密的QQ号的数字个数:");
	int n = sc1.nextInt();
	Scanner sc1 = new Scanner(System.in);
	System.out.println("请输入需要解密的QQ号:");
	Scanner sc1 = new Scanner(System.in);
	int a[] = new int[100];
	for(int i = 0;i < n; i++){ // 初始化数组
		a[i] = sc2.nextInt();
	}

之后可以开始模拟解密了,解密的第一步是需要删除数字,数组里删除数字最简单的方法是将所有后面的数都往前面挪动一位,将前面的数覆盖。就好比我们在排队买票,前面的人买好离开了,后面所有的人就需要全部向前面走一步,补上之前的空位,但是这样的做法很耗费时间。
在这里插入图片描述
不过这给了我们一个很好的思路——排队,我们可以把这串数字看做一个队列,然后定义两个整型变量 head 和 tail ,分别指向队列的队首(即第一位)和队尾(即最后一位)的下一个位置。

你可能会问:为什么 tail 不直接记录队尾,却要记录队尾的下一个位置呢?
这是因为当队列中只剩下一个元素时,队首和队尾重合会带来一些麻烦。我们这里规定队首和队尾重合时,队列为空

我在这里简单的补充一下队列的概念:

队列是一种特殊的线性结构,它只允许在队列的首部(head)进行删除操作,这称为 “ 出队”;而在队列的尾部(tail)进行插入操作,这称为 “入队”。
当队列中没有元素时(即 head==tail),称为空队列。
在我们的日常生活中有很多情况都符合队列的特性。比如我们之前提到过的买票,每个排队买票的窗口就是一个队列。在这个队列当中,新来的人总是站在队列的后面,来得越早的人越靠前,也就越早能买到票,就是先来的人先服务。
我们称之为 “ 先进先出 ”(First In First Out,简称:FIFO)原则。

在这里插入图片描述
在这里插入图片描述
补充完毕!继续前行!

小哈给小哼的加密的QQ号有 9 个数,我们将这9 个数全部放入队列之后,

head = 0;
tail = 9; (9 个数放入数组中,数组的下标是0~8,因此 tail = 8+1 = 9)

此时 head 和 tail 之间的数就是目前队列中 “ 有效 ” 的数。如果要删除一个数的话,就将 head++ 就 OK 了,这样仍然可以保持 head 和 tail 之间的数为目前队列中 “ 有效 ” 的数。这样做虽然浪费了一个空间,却节省了大量的时间,这是非常划算的。新增加一个数也很简单,把需要增加的数放到队尾即 q[tail] 之后再 tail++ 就 OK 啦!
注意:用空间换时间也是算法的一个思想

小总结:

队首删除一个数的操作:head++
队尾增加一个数(假设这个数是 x)的操作: q[tail] = x;
								   tail++; 

在这里插入图片描述

在这里插入图片描述
整个解密过程如下图:
在这里插入图片描述
完整代码如下:

import java.util.Scanner;
public class T1 {
	public static void main(String[] args) {
		// QQ号解密
		// 输入要解密的QQ号的数字个数及要解密的QQ号
		System.out.print("请输入要解密的QQ号的数字个数:");
		Scanner sc1 = new Scanner(System.in);
		int n = sc1.nextInt();
		System.out.println("请输入要解密的QQ号:");
		// 因为我们选择的删除数据的方式是直接head++往后走,
		// 同时tail++继续向后创建新的空间,因此我们需要的数组的空间要比QQ号的个数多
		// 故我们创建数组q时多给一点空间
		// 这样做虽然浪费了空间,但是节省了大量的时间,也是算法的一种思想“用空间换时间”
		int q[] = new int[101]; 
		Scanner sc2 = new Scanner(System.in);
		for(int i = 0; i < n; i++) { // 循环读入QQ号
			q[i] = sc2.nextInt();
		}
		
		// 定义两个整型变量作为头指针和尾指针标记数组下标
		
		int head = 0; // 头指针,数组下标=0
		
		// 尾指针,指向队尾的下一个位置,在这里等于QQ号的数字个数,
		// 因为数组的下标是从0开始的,所以第9个数字的下标为8,
		// 因此队尾的下一个位置的下标为9,即QQ号的数字个数
		int tail = n; 
		
		// 不知道需要循环多少次或者循环的次数不能立刻算出来,就使用while循环
		// 当删除最后一个数字的时候,头指针和尾指针指向的是同一个数字,即可结束循环
		while(head < tail) { 
			System.out.print(q[head]+" "); // 打印队首元素
			head++; // 将队首元素出队,即头指针指向下一个元素,
			
			// 根据题目可知,队首元素的下一个元素需要放到队尾,
			// 即将队首元素出队后,head指向的元素需要放到队尾,
			// 故将元素值赋给尾指针指向的空间
			q[tail] = q[head];
			
			// 赋值完毕后,尾指针向后走
			tail++;
			// 头指针也向后走
			head++;
			// 此时完成了第一个解密过程
			// 即将第一个数删除,第二个数放到数字的末尾
			// 这时head指向的是第三个数,在下一次循环的开始被删除
			// 之后开启下一轮解密过程,直至循环结束,完成所有的解密过程
		}
	}
}

运行结果如下:
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爪喵喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值