啊哈!算法(第二章)C#实现

第 1 节 解密 QQ 号——队列
 
新学期开始了,小哈是小哼的新同桌(小哈是个小美女哦~),小哼向小哈询问 QQ 号,小哈当然不会直接告诉小哼啦,原因嘛你懂的。
所以小哈给了小哼一串加密过的数字,同时小哈也告诉了小哼解密规则。
规则是这样的:首先将第 1 个数删除,紧接着将第 2 个数放到这串数的末尾,再将第 3 个数删除并将第 4 个数放到这串数的末尾,再将第 5 个数删除……
直到剩下最后一个数,将最后一个数也删除。按照刚才删除的顺序,把这些删除的数连在一起就是小哈的 QQ 啦。
现在你来帮帮小哼吧。小哈给小哼加密过的一串数是“6 3 1 7 5 8 9 2 4”。
 
 1 internal struct queue
 2 {
 3     public int[] data;
 4     public int head;
 5     public int tail;
 6 }
 7 
 8 static void Main(string[] args)
 9 {
10     queue q = new queue();
11     q.data = new int[100];
12     q.head = 1;
13     q.tail = 1;
14 
15     for (int i = 1; i <= 9; i++)
16     {
17         q.data[i] = Convert.ToInt32(Console.ReadLine());
18         q.tail++;
19     }
20 
21     while(q.head < q.tail)
22     {
23         Console.Write(q.data[q.head]);
24         q.head++;
25 
26         q.data[q.tail] = q.data[q.head];
27         q.head++;
28         q.tail++;
29     }
30 }
解密的第一步是将第一个数删除,你可以想一下如何在数组中删除一个数呢。
最简单的方法是将所有后面的数都往前面挪动一位,将前面的数覆盖。
就好比我们在排队买票,最前面的人买好离开了,后面所有的人就需要全部向前面走一步,补上之前的空位,但是这样的做法很耗费时间。
 

在这里,我将引入两个整型变量head 和tail。

head 用来记录队列的队首(即第一位),tail 用来记录队列的队尾(即最后一位)的下一个位置。

你可能会问:为什么tail 不直接记录队尾,却要记录队尾的下一个位置呢?

这是因为当队列中只剩下一个元素时,队首和队尾重合会带来一些麻烦。

我们这里规定队首和队尾重合时,队列为空。

现在有9 个数,9 个数全部放入队列之后head=1;tail=10;此时head 和tail 之间的数就是目前队列中“有效”的数。

如果要删除一个数的话,就将head++就OK 了,这样仍然可以保持head 和tail 之间的数为目前队列中“有效”的数。

这样做虽然浪费了一个空间,却节省了大量的时间,这是非常划算的。

新增加一个数也很简单,把需要增加的数放到队尾即q[tail]之后再tail++就OK 啦。

我们来小结一下,在队首删除一个数的操作是head++;。

 在队尾增加一个数(假设这个数是x)的操作是q[tail]=x;tail++;。

 整个解密过程,请看下面这个霸气外漏的图。

 最后的输出就是6 1 5 9 4 7 2 8 3

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

 
第2 节 解密回文——栈
 
队列是先进先出,而栈相反,先进后出
拿书中的例子来讲,我们将1,2,3号球,放进竹筒里,效果应该是这样的
 
3
2
1
 
 
 
这个时要取出1号球,就要先将3,2依此取出后,才能够得到1
 
于是我们就可以利用栈来解决一个小小的问题,就是回文字符串
 
回文字符串就是指 正读反读均相同的字符序列,如“席主席”、“记书记”、“aha”和“ahaha”均是回文
 
就拿xyzyx举例
 
先从字符串中间开始,我们让前半部分,放入栈中
x y      
 
 
然后越过中心点z,对后半部分的字符串进行判断,利用栈的特点,第一个出来的是y,而刚好中心点后的字符也是y,依此类推进行判断
 1 static void PalindromeString()
 2 {
 3     Write("请输入一串字符:");
 4     string str = ReadLine();
 5     char[] cstr = str.ToCharArray();
 6 
 7     //设置栈
 8     char[] stack = new char[101];
 9 
10     //得到字符串的长度
11     int len = str.Length;
12     //得到字符串中间点
13     int mid = len/2;
14     //初始化栈顶
15     int top = 0;
16 
17     //将字符串前半段入栈
18     for (int i = 0; i < mid; i++)
19     {
20         stack[top] = cstr[i];
21         top++;
22     }
23 
24     //如果字符长度是偶数,就不需要+1到中间点
25     int next = (len%2) == 0 ? mid : (mid+1);
26 
27     //接着往下判断
28     for (int i = next; i < len; i++)
29     {
30         //减一原因就是,数组长度-1位
31         --top;
32         //判断是否回文,利用栈的特点先进后出
33         if(str[i] != stack[top]) break;
34     }
35 
36     WriteLine(top==0?"yes":"no");
37 }

猜你喜欢

转载自www.cnblogs.com/ancm/p/12049107.html