数据结构以学带练day10——STL知识、栈和队列知识、栈和队列互相实现

408 阅读5分钟

STL版本

  1. HP STL 其他版本的C++ STL,一般是以HP STL为蓝本实现出来的,HP STL是C++ STL的第一个实现版本,而且开放源代码。
  2. P.J.Plauger STL 由P.J.Plauger参照HP STL实现出来的,被Visual C++编译器所采用,不是开源的。
  3. SGI STL 由Silicon Graphics Computer Systems公司参照HP STL实现,被Linux的C++编译器GCC所采用,SGI STL是开源软件,源码可读性甚高。

栈与队列

  • 队列是先进先出,栈是先进后出image.png

  • C++中stack(栈)是容器改编的。stack不提供迭代器来遍历stack空间,只有特定的方法 top push pop empty等等。
  • 我们使用的stack是属于SGI STL。SGI STL栈如果没有指定底层实现的话,默认是用双端队列deque实现的。当然,栈的底层实现可以是vector,deque,list 都是可以的, 主要就是数组和链表的底层实现。
  • 我们也可以指定vector为栈的底层实现,初始化语句如下:
std::stack<int, std::vector<int> > third;  // 使用vector为底层容器的栈
  • 堆栈的语法:为了创建堆栈,我们必须在代码中包含<stack>头文件。

与堆栈相关的功能有: 

  • empty() – 判断是否是空栈 – Time Complexity : O(1) 
  • size() – 返回栈的大小 – Time Complexity : O(1) 
  • top() – 返回对堆栈中最顶层元素的一个引用。 – Time Complexity : O(1) 
  • push(g) – 在栈顶添加元素'g'。 – Time Complexity : O(1) 
  • pop() – 删除堆栈中最顶层的元素 – Time Complexity : O(1)

队列

  • 队列中先进先出的数据结构,同样不允许有遍历行为,不提供迭代器SGI STL中队列一样是以deque为缺省情况下的底部结构。
  • 也可以指定list 为起底层实现,初始化queue的语句如下:
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
  • STL 队列也不被归类为容器,而被归类为container adapter( 容器适配器)。

  • 单向队列queue相关函数: |Method| Definition | | :----: | :----: | | queue::empty() | 返回队列是否为空。| | queue::size() | 返回队列的大小。 | | queue::swap() | 交换两个队列的内容,但队列必须是同一类型,尽管大小可能不同| | queue::emplace() | 在队列容器中插入一个新元素,新元素被添加到队列的末端。| | queue::front() | 返回对队列中第一个元素的引用。| | queue::back() | 返回对队列中最后一个元素的引用。 | | queue::push(g)  | 将元素'g'添加到队列的末端。| | queue::pop()  | 删除队列的第一个元素。|

  • 双向队列deque函数:

    • push_front()队列头插入
    • push_back()队列尾部插入
    • pop_front()队列头删除
    • pop_back()队列尾部删除

题目

232. 用栈实现队列

image.png

思路和题解

设定两个栈,一个栈stin用于存进的元素,之后再把这个栈的所有元素存入另一个栈stout,之后对stout里面元素的操作则和对队列的元素操作顺序一致了。详细见下图:

232.用栈实现队列版本2.gif

  • 注意点:本题要注意的是什么时候从stin里面把元素放入stout里面。判断条件一定是stout里面为空了,才把stin的元素全部导入stout里面,否则元素顺序就把打乱了。
  • 在push数据的时候,只要数据放进输入栈stin就好,但在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入) ,再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
class MyQueue {
public:
    //定义两个栈
    stack<int> stin;
    stack<int> stout;
    MyQueue() {
        
    }
    
    void push(int x) {
        stin.push(x);//栈加元素的函数
    }
    
    int pop() {
        //判断stout是否为空,是空的就把stin里的全部放入stout
        if(stout.empty()){
            while(stin.empty()!=true){
                //加完一个删一个
                stout.push(stin.top());
                stin.pop();
            }
        }
        //得到stout的第一个元素
        int result = stout.top();
        //再把stout的第一个元素删除
        stout.pop();
        return result;
    }
    
    int peek() {
        int res = this->pop(); // 直接使用上面pop函数,但是这个pop函数会删除stout的第一个元素
        stout.push(res); // 所以再添加回去,因为peek函数是不删除元素的
        return res;
    }
    
    bool empty() {
        if(stout.empty() && stin.empty()) return true;
        return false;
    }
};

225. 用队列实现栈

image.png

使用一个队列实现

class MyStack {
public:
    //定义一个双端队列
    deque<int> d;
    MyStack() {

    }
    
    void push(int x) {
        d.push_back(x);//从后加入队列
    }
    
    int pop() {
        int result = d.back(); //返回队列最后一个元素
        d.pop_back();//删除队列最后一个元素
        return result;
    }
    
    int top() {
        int result = this->pop();//调用上面的pop函数,因为top功能不删除元素
        d.push_back(result);//所以再把元素加回去
        return result;
    }
    
    bool empty() {
        if(d.empty()){return true;}
        return false;
    }
};

使用两个队列实现(复杂)

用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出que1最后面的元素(即模拟了栈的后进先出),再把其他元素从que2导回que1

class MyStack {
public:
    queue<int> que1;
    queue<int> que2; // 辅助队列,用来备份
    /** Initialize your data structure here. */
    MyStack() {

    }

    /** Push element x onto stack. */
    void push(int x) {
        que1.push(x);
    }

    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int size = que1.size();
        size--;//留下最后一个元素
        while (size--) { // 将que1 导入que2,但要留下最后一个元素
            que2.push(que1.front());
            que1.pop();
        }

        int result = que1.front(); // 留下的最后一个元素就是要返回的值
        que1.pop();
        que1 = que2;            // 再将que2赋值给que1
        // 清空que2
        while (!que2.empty()) { 
            que2.pop();
        }
        return result;
    }

    /** Get the top element. */
    int top() {
        return que1.back();
    }

    /** Returns whether the stack is empty. */
    bool empty() {
        return que1.empty();
    }
};