区别deque vector 和数组

Leetcode更新到155题了,这个easy的题acceptance却不高,我好奇的点开了它。

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

  • push(x) -- Push element x onto stack.
  • pop() -- Removes the element on top of the stack.
  • top() -- Get the top element.
  • getMin() -- Retrieve the minimum element in the stack.

果然easy嘛,そして:

class MinStack {
    struct node
    {
        int value;
        node * next;
        node(int v, node * n=0):value(v),next(n){}
    };
    node * h;
    node * min;

public:
    MinStack():h(0), min(0){}
    void push(int x) {
        h = new node (x, h);
        if(!min || min->value >= x)
            min = new node (x, min);
    }

    void pop() {
        if(h)
        {
            node * p;
            if(h->value == min->value)
            {
                p = min;
                min = min->next;
                delete p;
            }
            p = h;
            h = h->next;
            delete p;
        }
    }

    int top() {
        if(h)
            return h->value;
        throw;
    }

    int getMin() {
        if(min)
            return min->value;
        throw;
    }
};

据说通用的STL容器非常多虑,多线程神马的都考虑了进去,静态链接也会把从来不调用的函数加进去,因此我习惯于手动实现容器。XX怎么回事:memory limited error!N个next指针居然就不耐了也太傲娇了!

那么不用链式结构了,改用数组吧。就用vector试试。

class MinStack {
    vector<int> h;
    vector<int> min;

public:
    void push(int x) {
        h.push_back(x);
        if (min.empty() || min.back() >= x)
            min.push_back(x);
    }

    void pop() {
        if (h.back() == min.back())
            min.pop_back();
        h.pop_back();
    }

    int top() {
        return h.back();
    }

    int getMin() {
        return min.back();
    }
};    

XX,又是mle!最后看到别人用deque,做法大同小异,就抄了过来。好在STL里的函数名称比较统一,vector和deque的抽插都叫做push_back和pop_back,改下定义就好啦:

class MinStack {
    deque<int> h;
    deque<int> min;

public:
    void push(int x) {
        h.push_back(x);
        if(min.empty() || min.back() >= x)
            min.push_back(x);
    }

    void pop() {
        if(h.back() == min.back())
            min.pop_back();
        h.pop_back();
    }

    int top() {
        return h.back();
    }

    int getMin() {
        return min.back();
    }
};

查了下资料,又涨知识了!deque采用数组和链表的这种策略,初始先分配一块连续内存,不够了再分配一块,然后这些先后分配的内存通过指针“通通连起来”,逻辑上就是连续的空间了。这种东西早就想写一个,没想到STL已经提供了,而且STL中的stack和queue等容器底下正是它!perfect!

现在比较下数组、vector和deque:

1:原理:

数组:连续且固定的空间;

vector:连续但不固定的空间,原空间不够了将会调用allocator进行realloc,然后通过uninitialized_copy复制旧内容。

deque:连续的链式空间,空间不够则分配新的空间,每个内存块呈链式(不是新鲜事吧?从前学数据结构,有这样实现过string,学操作系统,其中文件管理也有用链式方法的)。

2:增长方向:

数组:长不大

vector:逻辑上是ForwardIncremental的

deque:显然是双向的了。

3:性能:

用下面这段简单的代码测试下,因为我用的是上上个五年计划的时候出的Thinkpad X61,N=100000000,sizeof(x

) = 12B差不多是极限了。

用int测试时,输出4  6;

用struct测试时,deque的循环输出7,vector在插入过程中直接bad_alloc,原因是找不到足够大的连续内存了。

#include <cstdlib>
#include <ctime>
#include <deque>
#include <vector>
#include <iostream>
using namespace std;

struct s
{
    int v;
    int a[2];
    s(int i):v(i){}
    ~s()
    {
        //make it a non-trivial destructor;
    }
};

main()
{
    typedef s T;
    int const N = 100000000;
    int i;
    double start;
    deque<T> d;
    vector<T> v;
    start = time(0);
    for(i=0; i<N; i++)
        d.push_back(T(i));
    for(i=0; i<N; i++)
        d.pop_back();
    cout <<time(0) - start<<endl;
    start = time(0);
    for(i=0; i<N; i++)
        v.push_back(T(i));
    for(i=0; i<N; i++)
        v.pop_back();
    cout <<time(0) - start<<endl;
}

当然并非以后就弃vector不用了,如果每次访问的内存地址比较跳跃,deque的效率必然就不行了,因为要跳到另一个块上,it++当然不行,至少需要访问两次内存了。果然存在即有理。

时间: 2024-12-17 15:53:11

区别deque vector 和数组的相关文章

vector代替数组

vector代替数组 1.声明一个int向量以替代一维的数组:vector <int> a;(等于声明了一个int数组a[],大小没有指定,可以动态的向里面添加删除). 2.用vector代替二维数组.其实只要声明一个一维数组向量即可,而一个数组的名字其实代表的是它的首地址,所以只要声明一个地址的向量即可,即:vector <int *> a.同理想用向量代替三维数组也是一样,vector <int**>a;再往上面依此类推. 下面是另外一种vector代替二维数组的方

[转]STL中vector转数组(实际是数组的指针)

感谢:http://topic.csdn.net/t/20050429/20/3976956.html 感谢:http://yzyanchao.blogbus.com/logs/47796444.html 不过那边是转载自<effective stl>. std::vector很方便,但有时调用的函数的参数规定是数组,需要将vector转为数组,另外开辟一个空间,将vector一项项复制过去代价过大,可用下面的方法. 给定一个 vector<int>   v;         表达

vector与数组的习惯用法

vector类为内置数组提供了一种替代表示,与string类一样 vector 类是随标准 C++引入的标准库的一部分 ,为了使用vector 我们必须包含相关的头文件  : #include <vector> 使用vector有两种不同的形式,即所谓的数组习惯和 STL习惯. 一.数组习惯用法 1. 定义一个已知长度的 vector : vector< int > ivec( 10 );  //类似数组定义int ia[ 10 ]; 可以通过ivec[索引号] 来访问元素 使用 

C++ Vector 动态数组

Vectors 包含着一系列连续存储的元素,其行为和数组类似.访问Vector中的任意元素或从末尾添加元素都可以在常量级时间复杂度内完成,而查找特定值的元素所处的位置或是在Vector中插入元素则是线性时间复杂度. Constructors 构造函数 Operators 对vector进行赋值或比较 assign() 对Vector中的元素赋值 at() 返回指定位置的元素 back() 返回最末一个元素 begin() 返回第一个元素的迭代器 capacity() 返回vector所能容纳的元

C++ 中对vector&lt;T*&gt; 数组的查找和排序

//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <vector> #include <algorithm> using namespace std; //-----------------------------------

C++中的快速排序(使用vector和数组的不同)

1.快速排序是最最基本的排序算法之一,时间复杂度是O(nlog2(n)) 基本思想:分治法+递归 假设key为该序列的第一个元素,从后往前遍历,找到第一个小于key值的元素,将该元素赋值给左边的起始值,再从前往后遍历,找到第一个大于key值的元素,将其赋值给刚才右边第一个小于key值的值,当low<high,则不断递归,知道有序为止. 在用数组int num[]和C++的vector传递地址时,vector需要传引用,否则,没法得到正确地址,因为vector本质上是一个类对象,因此传值会得不到正

a和&amp;a的区别、二维数组的本质及多维数组

1 a和&a的区别 int a[10] = {1,2};//其他初始化为0 a代表数组首元素的地址,不是整个数组的地址 &a表示整个数组的地址 &a,a代表的数据类型不一样 &a数组类型int[10] a 数组首元素的类型 2 数组指针的用法 int i=0;//循环变量 int a [5] = {3, 4, 5, 6, 2}; //直接定义一个数组指针 int (*p)[5] = &a; for (i=0; i<5; i++) { printf("

scanf函数和cin的区别、类的数组、C++排序函数

给定n个字符串,将这n个字符串按照字典序进行排列,此处用排列函数是C++的库函数sort,产生如下两个疑问,望大佬解答 #include <iostream> #include <algorithm> #include <string> #include <vector> using namespace std; /* ********************************************** Q1:为什么定义类的数组,无法用sort函数排

八连通(vector动态数组法)

题目和一般的八连通一样,但行数和列数未定,相乘对于1e6,直接开a[1e6][1e6]的数组肯定会爆内存.用二维的动态vector就能很好的解决这个问题 #include<bits/stdc++.h> using namespace std; int dx[10]={-1,0,1,-1,1,-1,0,1}; int dy[10]={1,1,1,0,0,-1,-1,-1}; int n,m; void dfs(vector< vector < bool > >&a