数据结构——队列,栈

队列

有时候,我们会遇到一些数字密码游戏,比如,给出一串数字: 4,6,8,3,5,2,2,6,0,解密规则是这样的,首先将第1个数删除,紧接着将第2个数字放到这串数的末尾,再将第3个数删除并将第4个数放到这串数的末尾,再将第5个数删除……如此往复,直到最后一个数也删除。按照刚才删除的顺序,将这些删除的数连在一起就是我们需要得到的目标数字。OK,这时候,拿出纸和笔,或者用一些小便签或者小卡片,将这9个数字分别写下来,开始模拟解密过程~

其实解密的过程就像是将这些数进行排队,每次从最前面拿两个,第1个扔掉,第2个放到末尾,如果不出意外的话,你能得到的目标数字串是:4,8,5,2,0,3,6,2,6。

在算法的世界里,没错,它就是队列,那么我们怎么用代码形式来实现它呢?

首先需要一个容器来存放这些数字,这里我们使用ArrayList,因为它的大小可以随着我们的需要而动态的增加,定义如下:

 1             ArrayList Quenum = new ArrayList();
 2             Quenum.Add(4);
 3             Quenum.Add(6);
 4             Quenum.Add(8);
 5             Quenum.Add(3);
 6             Quenum.Add(5);
 7             Quenum.Add(2);
 8             Quenum.Add(2);
 9             Quenum.Add(6);
10             Quenum.Add(0);
View Code

接下来就是模拟解密的过程了。解密的第一步是将第一个数删除,删除一个数最简单的方法是将所有后面的数都往前挪动一位,将前面的数覆盖,比如排队买票的时候,前方买好票的人离开,后面所有人就向前走一步,当然,这么做很耗费时间。

既然是队列,就有队首和队尾。这里引入队首变量head,和队尾变量tail,由于队列的原则是先进先出,因此,如果要删除一个数的话,只需要head++就可以了。而新增一个数也很简单,只需要在队尾加上即可,也就是tail++,按照这个思路,我们可以写出如下代码,代码并不复杂:

 1         public static void Queue(ArrayList num)
 2         {
 3             int head = 0;
 4             int tail = num.Count - 1;
 5             while (head < tail)
 6             {
 7                 Console.Write("{0} ", num[head]);
 8                 head++;
 9                 num.Add(num[head]);
10                 tail++;
11                 head++;
12             }
13             Console.Write("{0}", num[tail]);
14         }
View Code

运行得到测试结果:

这串数字有什么含义呢?哈哈,这是QQ群:代码之家--NET的QQ号,有兴趣的朋友们可以考虑加入哦~由于群刚建立不久,目前还没什么人呢~期待大家的到来~

题外话说完了,继续回到话题,什么是队列呢?队列是一种特殊的线性结构,它只允许在队列首部(head)进行删除操作,称为“出队”,而在队列尾部(tail)进行插入操作,称为“入队”。当队列中没有元素时(head==tail),称为空队列。队列是学习广度优先搜索及队列优化的Bellman-Ford最短算法的核心数据结构。

刚刚说到的队列是一种先进先出的数据结构,还有一种是后进先出的数据结构,叫做栈。栈限定为只能在一端进行插入和删除操作。生活中也有很多栈的例子,比如我们在吃桶装薯片的时候,要想吃掉最后一片,就必须先把前面的薯片全部吃完(假设不考虑透明“抽屉”的存在),还有平时我们能见到的弹枪,最后装入的子弹会被第一个打出去。栈的实现也很简单,上面我们用解密qq号的问题来阐述了队列,这里我们继续趣味问题之旅。

这里的例子我们用回文,回文字符串是正读反读都相同的字符序列,比如“上海自来水来自海上”,英文单词里也有不少回文单词,比如:dad, eye, madam...但是像ahah这就不算一个回文了,OK,接下来我们要如何通过栈来判断一串字符串是不是回文呢?

从回文的规则我们可以知道,如果一个字符串是回文的话,那么它必须是中间对称的,因此,我们需要求出一个中点mid,假设传入的是string类型的str,那么,中点代码即是:

1             int mid = str.Length / 2 - 1;
View Code

定义出原始的字符串,以及需要入栈操作的字符串:

1             char[] originalString = str.ToCharArray();
2             char[] stackString = new char[str.Length];
View Code

将mid之前的字符依次入栈:

1             for (int i = 0; i <= mid; i++)
2             {
3                 stackString[top] = originalString[i];
4                 top++;
5             }
View Code

紧接着就是对mid前后的字符进行对比了:

 1             for (int i = next; i < str.Length; i++)
 2             {
 3                 top--;
 4                 char x = originalString[i];
 5                 char c = stackString[top];
 6 
 7                 if (originalString[i] != stackString[top])
 8                 {
 9                     break;
10                 }
11 
12             }
13             if (top == 0)
14             {
15                 Console.WriteLine("{0} is Palin number.", str);
16             }
17             else
18             {
19                 Console.WriteLine("{0} is not Palin number.", str);
20             }
View Code

因此,全部的代码如下:

 1         public static void Stack(string str)
 2         {
 3             char[] originalString = str.ToCharArray();
 4             char[] stackString = new char[str.Length];
 5             int top = 0;
 6             int next;
 7             int mid = str.Length / 2 - 1;
 8             for (int i = 0; i <= mid; i++)
 9             {
10                 stackString[top] = originalString[i];
11                 top++;
12             }
13 
14             if (mid % 2 == 0)
15             {
16                 next = mid + 1;
17             }
18             else
19             {
20                 next = mid + 2;
21             }
22 
23             for (int i = next; i < str.Length; i++)
24             {
25                 top--;
26                 char x = originalString[i];
27                 char c = stackString[top];
28 
29                 if (originalString[i] != stackString[top])
30                 {
31                     break;
32                 }
33 
34             }
35             if (top == 0)
36             {
37                 Console.WriteLine("{0} is Palin number.", str);
38             }
39             else
40             {
41                 Console.WriteLine("{0} is not Palin number.", str);
42             }
43         }
View Code

当然,简单点的话,也可以这么做:

 1         private static bool PalinNumber<T>(T value)
 2         {
 3             string str;
 4             str = value.ToString();
 5             char x, y;
 6             bool flag = true;
 7             for (int i = 0; i < str.Length / 2; i++)
 8             {
 9                 x = str[i];
10                 y = str[str.Length - 1 - i];
11                 if (x != y)
12                 {
13                     flag = false;
14                 }
15             }
16             return flag;
17         }
18 
19         public static void Stack<T>(T value)
20         {
21             if (PalinNumber<T>(value))
22             {
23                 Console.WriteLine("{0} is Palin number.", value);
24             }
25             else
26             {
27                 Console.WriteLine("{0} is not Palin number", value);
28             }
29         }
View Code

很多人会更乐意使用下面的方法,虽然这里第一种方法略显繁杂,但更好地体现了栈的使用方式。栈也可以用来进行验证括号的匹配,这里就不多赘述了。

简单的两个趣味题阐述简单的队列与栈的概念,也藉由此对队列和栈有一个大致的了解。

posted @ 2015-09-11 11:56  Ribbon  阅读(1094)  评论(0编辑  收藏  举报