专题5-数据结构

专题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

时间: 2024-08-01 22:43:00

专题5-数据结构的相关文章

UESTC 电子科大专题训练 数据结构 D

UESTC 1584 题意:平面坐标上有n个怪物,每个怪物有一个rank值,代表x坐标和y坐标都不大于它本身的怪物数(不包括本身) 思路:对x y坐标从小到大排序,x优先排序,用数状数组计算y坐标小于它的数量 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #i

UESTC 电子科大专题训练 数据结构 A

UESTC 1591 题意:求区间极值之差 思路:线段树裸题,不带更新 ACA代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "ma

UESTC 电子科大专题训练 数据结构 J

UESTC 1599 题意:中文题..不写了 思路:优先对列,小的优先 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map

UESTC 电子科大专题训练 数据结构 N

UESTC 1586 题意:中文题 思路:拆点并查集裸题 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map"

UESTC 电子科大专题训练 数据结构 L

UESTC 1594 题意:中文题 思路:和poj食物链的题几乎一样,拆点或者带权并查集做,这种分类不多的比较倾向与拆点做 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "se

UESTC 电子科大专题训练 数据结构 C

UESTC 1597t 题意:中文题 思路:将每个点展开为 x*lazy1+lazy2, lazy1标记乘了多少 lazy2标记加了多少,每次区间乘的时候即 sum*c=(x*lazy1+lazy2)*c=x*lazy1*c+lazy2*c,区间加的时候为sum+c=(x*lazy1+lazy2)+c=x*lazy1+lazy2+c,每次对lazy标记的时候乘要同时对lazy1和lazy2进行标记 AC代码: #include "iostream" #include "str

UESTC 电子科大专题训练 数据结构-E

UESTC 1583 题意:中文题 思路:预处理将要变成的序列映射成1 2 3...n,数状数组每次求每个数前比它本身大的数,因为最后要变成1 2 3 ....n的序列,所以每个数字(映射后的)应该要交换到它值的位置上(也就是1的位置是1,2的位置是2,n的位置是n),如果当前数字(映射后的)前面有比它大的数,那必然要通过交换,将比他大的数交换到它后面去 AC代码: #include "iostream" #include "string.h" #include &

Redis 专题一: 数据结构

简单的动态字符串 redis没有直接使用C语言传统的字符串表示,而自己构建了一个动态字符串SDS,当redis需要的不仅仅是一个字符串字面量,而是一个可以被秀噶ide字符串值时,redis就会使用sds来表示字符串值,比如在redis的数据库里,包含字符串值的键值对在底层都是由SDS实现的. redis > set name "bugall" ok 1.键值对的键是一个字符串对象,对象的底层实现是一个保存着字符串"name"的SDS 2.键值对的值也是一个字符

数据结构C语言实现介绍

刚刚结束的大二上学期学习了数据机构C语言版这门课,在接下来的一个月中准备把课程的代码和知识点总结一下,就有了这个专题:数据结构C语言实现,在这里我将用C语言实现最基本的数据结构以及一些基本的算法,以下是我这个专题的内容: 1. 数据结构及算法简介: 主要介绍数据结构及算法的基础知识,一些基本的概念和术语,以及算法的定义.算法的特性.算法的时间复杂度和空间复杂度 2.顺序表的定义及算法实现: 主要介绍顺序表的定义及特点,实现顺序表的存储结构以及基本操作 3.单链表的定义及算法实现:  主要介绍单链

《数据结构与算法之美》——冒泡排序、插入排序、选择排序

排序,是每一本数据结构的书都绕不开的重要部分. 排序的算法也是琳琅满目.五花八门. 每一个算法的背后都是智慧的结晶,思想精华的沉淀. 个人觉得排序算法没有绝对的孰优孰劣,用对了场景,就是最有的排序算法. 当然,撇开这些业务场景,排序算法本身有一些自己的衡量指标,比如我们经常提到的复杂度分析. 我们如何分析一个算法? 排序算法的执行效率 1.最好.最坏和平均情况的时间复杂度 2.时间复杂度的系数.常数和低阶 一般来说,在数据规模n很大的时候,可以忽略这些,但是如果我们需要排序的数据规模在几百.几千