栈和队列
栈和队列的数据操作范围仅限于逻辑上特定的某端,栈先进后出,队列先进先出。
一、栈
1.栈的ADT接口
操作接口 | 功能 | 返回类型 |
---|---|---|
size() | 报告栈的规模 | int |
empty() | 判断栈是否为空 | bool |
push(e) | 将e插至栈顶 | void |
pop() | 删除栈顶对象 | T |
top() | 引用栈顶对象 | T& |
2.Stack模板类
#include "../Vector/Vector.h" //以向量为基类,公有派生出栈模板类
template <typename T> class Stack:public Vector<T>
{
public://size()、empty()及其他的开放接口,可以直接沿用
void push (T const& e){ //入栈:相当于将新元素作为向量的末元素插入
insert(size(),e);
}
T pop(){ //出栈:等效于删除向量的末元素
return remove(size()-1);
}
T& top(){ //取顶:直接返回向量的末元素
return (*this)[size()-1];
}
};
3.进制转换问题
进制转换的原理:将一个10进制的数X转换成n位h进制的数:
X = ( b n − 1 b n − 2 … b 2 b 1 b 0 ) h X = b n − 1 ∗ h n − 1 + b n − 2 ∗ h n − 2 + … + b 2 ∗ h 2 + b 1 ∗ h 1 + b 0 ∗ h 0 X 0 = X ÷ h = b n − 1 ∗ h n − 2 + b n − 2 ∗ h n − 3 + … + b 2 ∗ h 1 + b 1 ∗ h 0 ⋯ ⋯ b 0 X 1 = X 0 ÷ h = b n − 1 ∗ h n − 3 + b n − 2 ∗ h n − 4 + … + b 2 ∗ h 0 ⋯ ⋯ b 1 ⋮ X n − 1 = X n − 2 ÷ h = 0 ⋯ ⋯ b n − 1 \begin{array}{l} X = {\left( {{b_{n - 1}}{b_{n - 2}} \ldots {b_2}{b_1}{b_0}} \right)_h}\\ X = {b_{n - 1}}*{h^{n - 1}} + {b_{n - 2}}*{h^{n - 2}} + \ldots + {b_2}*{h^2} + {b_1}*{h^1} + {b_0}*{h^0}\\ {X_0} = X \div h = {b_{n - 1}}*{h^{n - 2}} + {b_{n - 2}}*{h^{n - 3}} + \ldots + {b_2}*{h^1} + {b_1}*{h^0} \cdots \cdots {b_0}\\ {X_1} = {X_0} \div h = {b_{n - 1}}*{h^{n - 3}} + {b_{n - 2}}*{h^{n - 4}} + \ldots + {b_2}*{h^0} \cdots \cdots {b_1}\\ \vdots \\ {X_{n - 1}} = {X_{n - 2}} \div h = 0 \cdots \cdots {b_{n - 1}} \end{array} X=(bn−1bn−2…b2b1b0)hX=bn−1∗hn−1+bn−2∗hn−2+…+b2∗h2+b1∗h1+b0∗h0X0=X÷h=bn−1∗hn−2+bn−2∗hn−3+…+b2∗h1+b1∗h0⋯⋯b0X1=X0÷h=bn−1∗hn−3+bn−2∗hn−4+…+b2∗h0⋯⋯b1⋮Xn−1=Xn−2÷h=0⋯⋯bn−1
对十进制数X,不断除h取余,将余数(低位到高位)压入栈中,直到商为0,再依次将高位到低位从栈中取出。
迭代实现代码:
void convert(stack<char>& S, __int64 n, int base){//十进制数n到base进制数的转换
static char digit[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
while(n!=0){
int remainder = (int)(n%base);
S.push(digit[remainder]);
n/=base;
}
}//新进制下由高到低的各数位,自顶向下保存在栈中
二、队列
队列中约定,新对象只能由队尾插入其中,只能从对头一端删除已有的元素。
1.队列中的ADT接口
操作接口 | 功能 | 返回类型 |
---|---|---|
size() | 报告队列的规模(元素总数) | int |
empty() | 判断队列是否为空 | bool |
enqueue(e) | 将e插入队尾 | void |
dequeue() | 删除队首对象 | T |
front() | 引用队首对象 | T& |
2.Queue模板类
代码如下(示例):
#include "../List/List.h" //以List为基类,公有派生出栈模板类
template <typename T> class Stack:public List<T>
{
public://size()、empty()及其他的开放接口,可以直接沿用
void enqueue (T const& e){ //入队:尾部插入
insertAsLast(e);
}
T dequeue(){ //出队:首部删除
return remove(first());
}
T& front(){ //队首
return first()->data;
}
};
3.用栈来实现队列
用两个栈来实现队列的入队和出队,原理如下:
①将Stack1作为要使用的队,判断Stack2是否为空,若不为空,则先将Stack2元素压入Stack1中,再将入队元素压入(pop)进Stack1中,自然地,入队元素位于Stack1栈的栈顶。
②出队时,若Stack2为空,则将Stack1中的元素一一弹出并压入Stack2中,直到Stack1中元素为空,这时候Stack2的栈顶对象就是队列的队首对象。如果Stack2不为空时,则直接弹出Stack2的栈顶对象
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
assert((!stack1.empty())||(!stack2.empty()));//确保两个栈中至少有一个有元素
if(stack2.empty())
while(!stack1.empty())
{
int tmp = stack1.top();
stack2.push(tmp);
stack1.pop();
}
int ret = stack2.top();
stack2.pop();
return ret;
}
private:
stack<int> stack1;
stack<int> stack2;
};
总结
栈和队列都含有一个能够删除集合中的特定元素的方法。
参考文献
[1]: https://www.zhihu.com/question/20993504.
[2]:https://cloud.tencent.com/developer/article/1643318.
[3]:邓俊辉.数据结构(C++语言版).北京:清华大学出版社,2010年8月第一版,ISBN:978-7-302-33064-6.