栈和队列的比较
栈和队列都属于线性表,且在其上进行Insert和Delete操作所插入和移除的元素是预先设定的。在栈中,在一端插入,在同一端删除,位于该端点的元素称为栈顶元素;在队列中,在一端插入,在另一端删除,位于两端点的元素分别称为队列尾和队列头。
所以在栈的实现中,需要记录的变量是栈顶元素位置;而在队列的实现中,需要记录的变量有队列头和队列尾的位置。
用数组实现一个栈
都需要记录哪些信息?栈顶元素下标index,以及数组本身的指针p、总长度MAX_SIZE。
栈顶元素下标index与其对应的数组元素下标f(index)之间的映射关系是怎样的?随着栈的增长,栈顶元素下标依次为0,1,2...n-1,其中n表示栈的最大高度。我们需要制定一种映射规则f,方便我们通过index计算出f(index)。而最简单的规则就是f(index) = index。
#include<iostream>
template<typename Object>
class Stack
{
public:Stack(){init();}Stack(const Stack& rhs){init();index = rhs.index;for(int i = 0; i != index + 1; ++i)p[i] = rhs.p[i];}Stack(Stack&& rhs):p(rhs.p),index(rhs.index){rhs.p = nullptr;rhs.index = -1;}Stack& operator =(const Stack& rhs){Stack copy(rhs);std::swap(p, copy.p);std::swap(index, copy.index);return *this;}Stack& operator =(Stack&& rhs){std::swap(p, rhs.p);std::swap(index, rhs.index);return *this;}~Stack(){if(p)delete[] p;}void push(const Object& object){if(index == MAX_SIZE-1)std::cerr << "overflow" << std::endl;elsep[++index] = object;}void push(Object&& object){if(index == MAX_SIZE-1)std::cerr << "overflow" << std::endl;elsep[++index] = std::move(object);}void pop(){if(empty())std::cerr << "underflow" << std::endl;else--index;}Object& top(){return p[index];}const Object& top() const{return p[index];}bool empty() const{return index == -1;}
private:static constexpr int MAX_SIZE = 4;Object* p;int index;void init(){p = new Object[MAX_SIZE];index = -1;}
};
队列的数组实现
需要保存哪些变量? 队列头下标head、队列长度size(用来计算队列尾下标和判断上溢出、下溢出),数组p和总长度MAX_SIZE。
#include <iostream>
template<typename Object>
class Queue
{
public:Queue(){init();}Queue(const Queue& rhs){init();head = rhs.head;size = rhs.size;for(int i = head, idx; i != head + size; ++i){idx = index(i);p[idx] = rhs.p[idx];}}Queue(Queue&& rhs):head(rhs.head), size(rhs.size),p(rhs.p){rhs.head = -1;rhs.size = 0;rhs.p = nullptr;}Queue& operator =(const Queue& rhs){Queue copy(rhs);std::swap(head, copy.head);std::swap(size, copy.size);std::swap(p, copy.p);return *this;}Queue& operator =(Queue&& rhs){std::swap(head, rhs.head);std::swap(size, rhs.size);std::swap(p, rhs.p);return *this;}~Queue(){if(p)delete[] p;}void enqueue(const Object& object){if(full()){std::cout << "overflow" << std::endl;return;}p[index(head + size++)] = object;}void enqueue(Object&& object){if(full()){std::cout << "overflow" << std::endl;return;}p[index(head + size++)] = std::move(object);}Object tail(){if(empty()){std::cout << "underflow" << std::endl;return Object();}return p[index(head + size - 1)];}Object dequeue(){if(empty()){std::cout << "underflow" << std::endl;return Object{};}Object& object = p[index(head)];head = index(head + 1);--size;return object;}bool empty() const{return size == 0;}bool full() const {return size == MAX_SIZE;}int getSize() const {return size;}
private:static constexpr int MAX_SIZE = 4;Object* p;int head;int size;void init(){p = new Object[MAX_SIZE];head = size = 0;}inline int index(int i){if(i >= MAX_SIZE)i -= MAX_SIZE;return i;}
};void testQueue()
{using namespace std;struct Student{char name[10];int age;};Queue<Student> q;q.enqueue(Student{"Tom", 12});q.enqueue(Student{"Micheal", 13});q.enqueue(Student{"Anna", 14});q.enqueue(Student{"Lily", 10});q.enqueue(Student{"James", 19});q.enqueue(q.dequeue());q.enqueue(q.dequeue());q.enqueue(q.dequeue());q.enqueue(q.dequeue());while(!q.empty()){Student stu = q.dequeue();cout << "name:" << stu.name << " age:" << stu.age << endl;}/*outputoverflowname:Tom age:12name:Micheal age:13name:Anna age:14name:Lily age:10*/
}