话说大学的时候老师说妹子比工作重要~,工作可以再换,妹子这个。。。所以。。。这两个月也就一直忙着Fall in love,嗨,慢慢调整心态吧,
这篇就选一个简单的数据结构聊一聊,话说有很多数据结构都在玩组合拳,比如说:块状链表,块状数组,当然还有本篇的双端队列,是的,它就是
栈和队列的组合体。
一:概念
我们知道普通队列是限制级的一端进,另一端出的FIFO形式,栈是一端进出的LIFO形式,而双端队列就没有这样的限制级,也就是我们可以在
队列两端进行插入或者删除操作。
二:编码
1:定义结构体
通常情况下,队列的内部都是采用数组来实现,而且带有两个指针head和tail来指向数组的区间段,为了充分利用数组空间,我们也会用%来实
现逻辑上的循环数组,如下图。
1 public class MyQueue
2 {
3 public int head;
4
5 public int tail;
6
7 public int maxSize;
8
9 public int size;
10
11 public T[] list;
12
13 public MyQueue()
14 {
15 head = tail = size = 0;
16 maxSize = 3;
17 list = new T[maxSize];
18 }
19 }这里有一个注意的细节就是“size字段“,它是为了方便统计队列是否为满或者队列是否为空。
2:队尾入队
刚才也说了,双端队列是可以在队列的两端进行插入和删除的,要注意的是我们用head和tail指针的时候,tail指针是指向元素的下一个位置,
而head指针是指向当前元素,所以我们可以从tail端push数据的时候只要”顺时针“下移一个位置即可。
1 /// <summary>
2 /// 队尾入队
3 /// </summary>
4 /// <param name="t"></param>
5 /// <returns></returns>
6 public bool Push_Tail(T t)
7 {
8 //判断队列是否已满
9 if (myQueue.size == myQueue.list.Length)
10 return false;
11
12 myQueue.list[myQueue.tail] = t;
13
14 //顺时针旋转
15 myQueue.tail = (myQueue.tail + 1) % myQueue.maxSize;
16
17 myQueue.size++;
18
19 return true;
20 }3:队尾出队
和队尾入队一样,我们只要将tail指针”逆时针“下移一个位置,当然有一个细节需要注意,就是tail指针有存在负值的情况,毕竟我们是做”–操作“的,
所以需要tail+maxSize,即:myQueue.tail = (–myQueue.tail + myQueue.maxSize) % myQueue.maxSize;
1 /// <summary>
2 /// 队尾出队
3 /// </summary>
4 /// <param name="edges"></param>
5 /// <param name="t"></param>
6 public T Pop_Tail()
7 {
8 //判断队列是否已空
9 if (myQueue.size == 0)
10 return default(T);
11
12 //逆时针旋转(防止负数)
13 myQueue.tail = (--myQueue.tail + myQueue.maxSize) % myQueue.maxSize;
14
15 var temp = myQueue.list[myQueue.tail];
16
17 //赋予空值
18 myQueue.list[myQueue.tail] = default(T);
19
20 myQueue.size--;
21
22 return temp;
23 }4:队首入队
从head端来说,我们push数据的时候是head指针“逆时针”旋转,要注意的是同样要防止负数的产生,并且head指针是指向当前元素。
1 /// <summary>
2 /// 队首入队
3 /// </summary>
4 /// <param name="t"></param>
5 /// <returns></returns>
6 public bool Push_Head(T t)
7 {
8 //判断队列是否已满
9 if (myQueue.size == myQueue.list.Length)
10 return false;
11
12 //逆时针旋转(防止负数产生)
13 myQueue.head = (--myQueue.head + myQueue.maxSize) % myQueue.maxSize;
14
15 //赋予元素
16 myQueue.list[myQueue.head] = t;
17
18 myQueue.size++;
19
20 return true;
21 }5:队首出队
说到这个方法,我想大家应该都懂了双端队列的大概流程了,这个方法我也不用赘叙了。
1 /// <summary>
2 /// 队首出队
3 /// </summary>
4 /// <param name="edges"></param>
5 /// <param name="t"></param>
6 public T Pop_Head()
7 {
8 //判断队列是否已空
9 if (myQueue.size == 0)
10 return default(T);
11
12 //获取队首元素
13 var temp = myQueue.list[myQueue.head];
14
15 //原来单位的值赋默认值
16 myQueue.list[myQueue.head] = default(T);
17
18 //顺时针旋转
19 myQueue.head = (myQueue.head + 1) % myQueue.maxSize;
20
21 myQueue.size--;
22
23 return temp;
24 }从上面的四个方法可以看出:
当我们只使用Push_Tail和Pop_Tail的话,那它就是栈。
当我们只使用Push_Tail和Pop_Head的话,那它就是队列。
最后是全部代码:
1 using System.Net;
2 using System;
3 using System.IO;
4 using System.Collections.Generic;
5 using System.Text;
6 using System.Drawing;
7 using System.Drawing.Imaging;
8
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 DoubleQueue<int> queue = new DoubleQueue<int>();
14
15 queue.Push_Tail(10);
16 queue.Push_Tail(20);
17 queue.Push_Tail(30);
18
19 queue.Pop_Tail();
20 queue.Pop_Tail();
21 queue.Pop_Tail();
22
23 queue.Push_Tail(10);
24 queue.Push_Head(20);
25 queue.Push_Head(30);
26 queue.Push_Head(30);
27
28 queue.Pop_Tail();
29 queue.Pop_Tail();
30 queue.Pop_Head();
31
32 queue.Push_Head(40);
33 queue.Push_Tail(50);
34 queue.Push_Tail(60);
35 }
36 }
37
38 /// <summary>
39 /// 双端队列
40 /// </summary>
41 public class DoubleQueue<T>
42 {
43 public class MyQueue
44 {
45 public int head;
46
47 public int tail;
48
49 public int maxSize;
50
51 public int size;
52
53 public T[] list;
54
55 public MyQueue()
56 {
57 head = tail = size = 0;
58 maxSize = 3;
59 list = new T[maxSize];
60 }
61 }
62
63 MyQueue myQueue = new MyQueue();
64
65 /// <summary>
66 /// 队尾入队
67 /// </summary>
68 /// <param name="t"></param>
69 /// <returns></returns>
70 public bool Push_Tail(T t)
71 {
72 //判断队列是否已满
73 if (myQueue.size == myQueue.list.Length)
74 return false;
75
76 myQueue.list[myQueue.tail] = t;
77
78 //顺时针旋转
79 myQueue.tail = (myQueue.tail + 1) % myQueue.maxSize;
80
81 myQueue.size++;
82
83 return true;
84 }
85
86 /// <summary>
87 /// 队尾出队
88 /// </summary>
89 /// <param name="edges"></param>
90 /// <param name="t"></param>
91 public T Pop_Tail()
92 {
93 //判断队列是否已空
94 if (myQueue.size == 0)
95 return default(T);
96
97 //逆时针旋转(防止负数)
98 myQueue.tail = (--myQueue.tail + myQueue.maxSize) % myQueue.maxSize;
99
100 var temp = myQueue.list[myQueue.tail];
101
102 //赋予空值
103 myQueue.list[myQueue.tail] = default(T);
104
105 myQueue.size--;
106
107 return temp;
108 }
109
110 /// <summary>
111 /// 队首入队
112 /// </summary>
113 /// <param name="t"></param>
114 /// <returns></returns>
115 public bool Push_Head(T t)
116 {
117 //判断队列是否已满
118 if (myQueue.size == myQueue.list.Length)
119 return false;
120
121 //逆时针旋转(防止负数产生)
122 myQueue.head = (--myQueue.head + myQueue.maxSize) % myQueue.maxSize;
123
124 //赋予元素
125 myQueue.list[myQueue.head] = t;
126
127 myQueue.size++;
128
129 return true;
130 }
131
132 /// <summary>
133 /// 队首出队
134 /// </summary>
135 /// <param name="edges"></param>
136 /// <param name="t"></param>
137 public T Pop_Head()
138 {
139 //判断队列是否已空
140 if (myQueue.size == 0)
141 return default(T);
142
143 //获取队首元素
144 var temp = myQueue.list[myQueue.head];
145
146 //原来单位的值赋默认值
147 myQueue.list[myQueue.head] = default(T);
148
149 //顺时针旋转
150 myQueue.head = (myQueue.head + 1) % myQueue.maxSize;
151
152 myQueue.size--;
153
154 return temp;
155 }
156 }