栈和队列
-
栈:栈是一个非常常见的数据结构,特点是先机后出,即最先压入(push)栈的元素会第一个被弹出(pop)。在计算机中被广泛使用。例如,操作系统会给每个线程创建一个栈用来存储函数调用时各个函数的参数。
通常栈是一个不考虑排序的数据结构,我们需要的时间才能找到栈中的元素,TODO:考虑一下是否要删除,这块不动就不要误导
-
队列:和栈一样,队列也是非常重要的数据结构。它的特征是先进先出,即第一个入队的元素将会第一个出来。
栈和队列队列虽然是特点争锋相对的两类数据结构,但有意思的是它们却相互联系,来看看面试题。
面试题 7:两个栈实现一个队列
题目
用两个栈实现一个队列。队列申明如下,请实现它的两个函数appendTail
和deleteHead
,分别完成在队列尾部插入节点和在队列头部删除节点的功能。
template<typename T>
class Queue {
public:
Queue(void);
~Queue(void);
void appendTail(const T &node);
T deleteHead();
private:
stack<T> stack1;
stack<T> stack2;
};
分析
用两个栈实现队列的功能,粗一看不得其法,只能慢慢分析。
先模拟入队,入队时肯定需要一个数据结构来存放,姑且就选stack1吧。如果我们讲1、2、3依次入队,即在将1、2、3依次压入stack1中。此时stack1中的出栈顺序为3、2、1,如果此时出队,顺序必然也是3、2、1和队列先进先出的特性不符。
考虑到还有一个栈stack2未使用,而栈的特性是先入后出,刚好会将压入顺序反转,负负得正,在出队时,只要将stack1中的元素依次拷贝到stack2中。stack2的出栈顺序将符合出队顺序。
该题重要的解题思路就是:栈的压入顺序和弹出顺序相反。使用两个栈,就可以让压入顺序和弹出顺序一致。
解:Java
import java.util.Stack;
public class Queue<T> {
private Stack<T> mStackAppend;
private Stack<T> mStackDelete;
public Queue() {
mStackAppend = new Stack<>();
mStackDelete = new Stack<>();
}
public void appendTail(T node) {
mStackAppend.push(node);
}
public T deleteHead() {
if (mStackDelete.empty()) {
while (!mStackAppend.empty()) {
mStackDelete.push(mStackAppend.pop());
}
}
if (mStackDelete.empty()) {
return null;
}
return mStackDelete.pop();
}
}
测试代码:
public static void main(String args[]) {
Queue<Integer> queue = new Queue<>();
queue.appendTail(1);
queue.appendTail(2);
queue.appendTail(3);
System.out.println(queue.deleteHead());
System.out.println(queue.deleteHead());
System.out.println(queue.deleteHead());
}
解:C++
template<typename T>
class Queue {
public:
Queue(void){}
~Queue(void){}
void appendTail(const T &node) {
stack1.push(node);
}
T deleteHead() {
if (stack2.empty()) {
while (!stack1.empty()) {
T &data = stack1.top();
stack1.pop();
stack2.push(data);
}
}
if (stack2.empty()) {
throw std::exception();
}
T head = stack2.top();
stack2.pop();
return head;
}
private:
stack<T> stack1;
stack<T> stack2;
};
int main() {
Queue<int> queue;
queue.appendTail(1);
queue.appendTail(2);
queue.appendTail(3);
cout << queue.deleteHead()
<< queue.deleteHead()
<< queue.deleteHead() << endl;
return 0;
}