码迷,mamicode.com
首页 > 其他好文 > 详细

专题5-数据结构

时间:2017-07-12 21:23:29      阅读:293      评论:0      收藏:0      [点我收藏+]

标签:顺序   调用   tmp   class   width   war   instant   有一个   pac   

专题5-数据结构

C++ Primer P329好好研读,stack,queue,priority_queue都是顺序容器适配器adaptor。接受一种已有的容器类型,使其行为看起来像另一种事物一样)

适配器的底层容器(array和forward_list都不行)
stack 默认基于deque实现,除array和forward_list以外的容器都可以
queue 默认基于deque实现,可以构造于list和deque之上,但是不能基于vector进行构造
priority_queue 默认基于vector实现,最大堆max-heap,可以基于vetor和deque,但是不能基于list(需要随机访问能力)

1、基础知识

1.1、stack栈

栈操作
s.pop() 删除栈顶元素 O(1)
s.push() 压入元素 O(1)
s.top() 返回首元素,但是不删除 O(1)

1.2、队列queue:

C++ primer P330

queue模板类的定义在<queue>头文件中。记住队列没有top()函数。

与stack模板类很相似,queue模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque类型。

定义queue对象的示例代码如下:

queue<int> q1; queue<double> q2;

queue的基本操作有: 

q.push(x) 入队,将x接到队列的末端 时间复杂度是O(1)
q.pop() 出队,弹出队列的第一个元素,注意,并不会返回被弹出元素的值 时间复杂度是O(1)
q.front() 访问队首元素,即最早被压入队列的元素 时间复杂度是O(1)
q.back() 访问队尾元素,即最后被压入队列的元素 时间复杂度是O(1)
q.empty() 判断队列空  
q.size() 访问队列中的元素个数  

队列经常用于BFS,之前总结过BFS要利用queue + unordered_map实现,还有就是二叉树的层次遍历。

 

1.3、priority_queue

 主要操作是:pop(),top(),push()。

     priority_queue利用一个最大堆完成,最大堆是一个以vector表现的完全二叉树,所以缺省情况下它的底部容器是vector。,queue以底部容器完成其所有的工作,具有这种“修改某物接口,形成另一种风貌”之性质者,称为adapter(适配器)。

    priority_queue 对于基本类型的使用方法相对简单。他的模板声明带有三个参数,priority_queue<Type, Container, Functional>,Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。
Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list。STL里面默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。

    如果要用到小顶堆,则一般要把模板的三个参数都带进去。STL里面定义了一个仿函数 greater<>,对于基本类型可以用这个仿函数声明小顶堆。

#include <iostream>
#include <queue>
using namespace std;
int main(){
    priority_queue<int, vector<int>, greater<int> > q;    
    for( int i= 0; i< 10; ++i ) q.push( rand() );
    while( !q.empty() ){
        cout << q.top() << endl;
        q.pop();
    }    
    getchar();
    return 0;
}

 

**对于自定义类型,则必须自己重载 operator< 或者自己写仿函数**

1)重载 operator<(自己联想一下每次弹出最小元素的queue形式,{3,2,1}所以必须是返回a.x> b.x;)sort默认是小于排序,从大到小排序,所以重载的时候需要operator<。

 

bool operator>( Node left, Node right ){
    if( left.x== right.x ) 
return left.y> right.y; return left.x> right.x; }

   

技术分享
#include <iostream>
#include <queue>

using namespace std;

struct Node{
    int x, y;
    Node( int a= 0, int b= 0 ):
        x(a), y(b) {}
};

bool operator<( Node a, Node b ){
    if( a.x== b.x ) return a.y> b.y;
    return a.x> b.x; 
}

int main(){
    priority_queue<Node> q;
    
    for( int i= 0; i< 10; ++i )
    q.push( Node( rand(), rand() ) );
    
    while( !q.empty() ){
        cout << q.top().x <<   << q.top().y << endl;
        q.pop();
    }
    
    getchar();
    return 0;
}
重载operator<形式代码示例

 

2)自己写仿函数

       自定义类型重载 operator< 后,声明对象时就可以只带一个模板参数。但此时不能像基本类型这样声明priority_queue<Node, vector<Node>, greater<Node> >;原因是 greater<Node> 没有定义,如果想用这种方法定义
则可以按如下方式:

      记住调用的时候格式为:priority_queue<Node, vector<Node>, cmp> q;

struct cmp{
    bool operator() ( Node a, Node b ){
        if( a.x== b.x ) {
             return a.y> b.y;
         }
        return a.x> b.x; 
    }
};

 

技术分享
#include <iostream>
#include <queue>

using namespace std;

struct Node{
    int x, y;
    Node( int a= 0, int b= 0 ):
        x(a), y(b) {}
};

struct cmp{
    bool operator() ( Node a, Node b ){
        if( a.x== b.x ) return a.y> b.y;
        
        return a.x> b.x; }
};

int main(){
    priority_queue<Node, vector<Node>, cmp> q;
    
    for( int i= 0; i< 10; ++i )
    q.push( Node( rand(), rand() ) );
    
    while( !q.empty() ){
        cout << q.top().x <<   << q.top().y << endl;
        q.pop();
    }
    
    getchar();
    return 0;
}
自己写仿函数形式

 

2、leetcode题目实战

2.1 155. Min Stack

https://leetcode.com/problems/min-stack/#/description

思路:使用两个栈,一个栈存正常数据,另一个栈记录每个元素对应的最小值是多少,这题细节,压入MinStack的时候,一定要使用if_else,minStack为空的时候要单独考虑,top()操作是返回stack中的数据。

技术分享
class MinStack {
public:
    /** initialize your data structure here. */
    stack<int> s;
    stack<int> minStack;
    MinStack() {
        
    }
    
    void push(int x) {
        s.push(x);
        if(minStack.empty()){
            minStack.push(x);
        }
        else{//总是忘记加上else,只有非空的时候才能这样
            minStack.push(min(x,minStack.top()));
        }
    }
    
    void pop() {
        if(!s.empty()){
            s.pop();
        }
        if(!minStack.empty()){
            minStack.pop();
        } 
        return;
    }
    
    int top() {//这里的top返回的是当前元素,不是需要返回最小值        
        if(!s.empty()){
            return s.top();
        }
        return 0;
    }
    
    int getMin() {
        if(!minStack.empty()){
            return minStack.top();
        }
        return 0;       
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */
MinStack

 

2.2 232. Implement Queue using Stacks

 https://leetcode.com/problems/implement-queue-using-stacks/#/description

思路:这题自己思路不清晰,要理顺。使用两个栈oldStack和newStack,其中newStack总是存储目前压入的元素,在pop和front操作前,如果oldStack中有元素,就直接弹出oldStack的元素,只有oldStack为空的时候,才将newStack中的元素弹出压入到oldStack中。

技术分享
class MyQueue {
public:
    /** Initialize your data structure here. */
    stack<int> newStack,oldStack;//newStack总是存储最新压入的元素
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        newStack.push(x);
        
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        if(oldStack.empty()){
            while(!newStack.empty()){
                oldStack.push(newStack.top());
                newStack.pop();
            }
        }        
        int tmp = oldStack.top();
        oldStack.pop();
        return tmp;
    }
    
    /** Get the front element. */
    int peek() {
        if(oldStack.empty()){
            while(!newStack.empty()){
                oldStack.push(newStack.top());
                newStack.pop();
            }
        } 
        
        return oldStack.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {        
        return newStack.empty() && oldStack.empty();
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * bool param_4 = obj.empty();
 */
Implement Queue using Stacks

 

2.3 225. Implement Stack using Queues

https://leetcode.com/problems/implement-stack-using-queues/#/description

思路:这题有一个非常简单巧妙无敌的方法,除了push操作其他操作都和queue正常操作一样,使用一个队列就可以实现,将新元素压入queue,然后弹出一个front,再压入到queue中,这样就可以按照stack的顺序保存元素了。

技术分享

 

 4是需要压入的元素,{1,2,3}是已经压入的元素,然后将123弹出压入重新压入queue,就形成了{1‘,2‘,3’,4};

技术分享
class MyStack {
public:
    /** Initialize your data structure here. */
    queue<int> q;
    MyStack() {
       
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        q.push(x);
        for(int i = 0;i < q.size() - 1;++i){
            q.push(q.front());
            q.pop();
        }       
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int tmp = q.front();
        q.pop();
        return tmp;
    }
    
    /** Get the top element. */
    int top() {        
        return q.front();
        
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return q.empty();
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * bool param_4 = obj.empty();
 */
Implement Stack using Queues

 

专题5-数据结构

标签:顺序   调用   tmp   class   width   war   instant   有一个   pac   

原文地址:http://www.cnblogs.com/dingxiaoqiang/p/7157445.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!