棧(stack)和隊列(queue)都是動態集合,且在其上能進行delete操作所移除的元素是預先設定的。在棧中刪除的是最近插入的元素;在隊列中則是存在最久的元素。這兩者實現的分別是後進先出(last in, first out)和先進先出(first in, first out)的策略。
數組表示
利用數組表示一個簡單的棧和隊列確實是一個不錯的選擇,能夠理解棧和隊列對數據的操作即可。下面給出棧的數組表示;
struct Stack{
int size;
const static int N;
int dat[N];
int top;
Stack(){
top = 0;
size = 0;
}
bool isEmpty(){
return size == 0;
}
void push(int v){
top++;
dat[top] = v;
size --;
}
int pop(){
if(isEmpty())
;//error("underflow");
else {
top--;
size--;
return dat[top+1];
}
}
};
如果利用一個數組表示兩個棧,並且當兩個棧中的元素個數和小於n的時候都不會溢出。這樣的數據結構可以將兩個棧的棧底分別設置在數組的兩端。然後兩個棧的top向中間靠攏。即可達到共享一個數組實現兩個棧的目的。代碼如下:
struct DoubleStack {
const static int N = 1000;
int dat[N];
int top1, top2;
int size1, size2;
DoubleStack(){
top1 = top2 = size1 = size2 = 0;
}
//flag == true -> stack1 ;flag==false -> stack2
bool isEmpty(bool flag) {
if(flag)
return size1 == 0;
else
return size2 == 0;
}
bool isFlow() {
return top1 + 1 == top2;
}
//flag == true -> stack1 ;flag==false -> stack2
void push(bool flag, int v) {
if(isFlow())
return ;// error("overFlow");
if(flag) {
top1++;
dat[top1] = v;
size1++;
} else {
top2--;
dat[top2] = v;
size2++;
}
}
//flag == true -> stack1 ;flag==false -> stack2
int pop(bool flag) {
if(isEmpty(flag))
return -1;//error("underFlow");
if(flag) {
size1--;
top1--;
return dat[top1 + 1];
} else {
top2++;
size2--;
return dat[top2 - 1];
}
}
};
隊列(數組表示)
隊列也可以利用數組表示,設置兩個數組下標表示隊首和隊尾,對其進行插入到隊尾和彈出隊首元素等操作。下面代碼tail指向的是隊尾元素的後面一個位置;
struct Queue{
int size;
const static int N = 1000;
int dat[N];
int tail, front;
bool isEmpty(){
return tail == front;
}
bool isFlow(){
return tail + 1 == front;
}
Queue(){
size = 0;
tail = front = 1;
}
void enQueue(int v){
if(isFlow())
return ;// error("overFlow");
dat[tail] = v;
if(tail == N)
tail = 1;
else tail += 1;
size++;
}
int deQueue(){
if(isEmpty())
return -1;//error("underFlow");
int x = dat[front];
if(front == N)
front = 1;
else front += 1;
size --;
return x;
}
int getSize() {
return size;
}
};
利用數組實現雙端隊列,就是可以隊首和隊尾都能進行插入刪除操作的結構。
struct Deque{
int size;
const static int N = 1000;
int dat[N];
int front, tail;
Deque(){
size = 0;
front = tail = 1;
}
bool isEmpty(){
return tail == front;
}
bool isFlow(){
return tail + 1 == front;
}
void push_back(int v){
if(isFlow())
return ;// error("overFlow");
dat[tail] = v;
if(tail == N)
tail = 1;
else tail += 1;
size++;
}
int pop_back(){
if(isEmpty())
return -1;//error("underFlow");
if(tail == 1)
tail = N;
else tail -= 1;
int x = dat[tail];
size --;
return x;
}
void push_front(int v) {
if(isFlow())
return ;// error("overFlow");
if(front == 1)
front = N;
else front -= 1;
dat[front] = v;
size++;
}
int pop_front(){
if(isEmpty())
return -1;//error("underFlow");
int x = dat[front];
if(front == N)
front = 1;
else front += 1;
size --;
return x;
}
int getSize()
{
return size;
}
};
利用兩個隊列實現棧或者兩個棧實現隊列
1. 利用兩個隊列實現棧: 因爲棧是LIFO, 而隊列是FIFO。 假設有兩個隊列q1、q2。將元素放入q1,當需要取最後進入的元素的時候可以q1中的前size-1個數取出放入q2.然後最夠一個元素返回即爲最後進入‘棧’的元素。可以利用隊列數組就是q1和q2對應Q[0]、Q[1]。這是可免去將元素有取出放回到q1中的操作。最後每一次取出一個棧的元素的操作爲O(size - 1) 。
2. 利用兩個棧實現隊列。這個也是相同的道理,我們將元素壓入其中某個棧中,想要取出最先進入結構的元素需要將棧中的前size-1個元素取出放入另一個棧,然後彈出棧中剩下的最後一個元素就是最先進入結構中的元素。同樣可以利用滾動棧數組免去一些操作,最後時間複雜度爲O(size - 1)。
PS:這個複雜度是建立在棧和隊列插入和彈出的複雜度爲O(1)的前提下。