Jun 14

关于vector的效率 不指定

felix021 @ 2009-6-14 03:22 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(8636) | Via 本站原创 | |
看过《STL之父访谈录》,了解了STL之父对效率的极度迷信,因而我对STL容器的效率也是很迷信的。

但是某一次和feli聊到vector的效率问题,他说,有时候在比赛的时候用vector会TLE,换成自己写的单链表就AC了。

可惜当时是在永和门口争论的,无法验证,后来某天想到这个问题,于是验证之:

1. vector和数组的效率对比:

对一个含有100,000,000个元素的int数组进行循环10遍的写入,测试结果(使用linux下的time命令统计)为:

Array:
real  0m3.801s
user  0m3.136s
sys  0m0.568s

Vector:
real  0m4.210s
user  0m3.548s
sys  0m0.520s

可以看出,vector和Array相比,至少在acm程序中,效率损失几乎是可以忽略的。
还需要声明一点,这里的vector是在运行时动态申请的空间,而array则是预分配的。

测试程序后附。


2. 单链表的效率和STL的list效率对比:

添加10,000,000个元素,测试结果为:

单链表:
real  0m0.836s
user  0m0.620s
sys  0m0.204s

list<int>:
real  0m1.202s
user  0m1.024s
sys  0m0.168s

可以看出来,完全没必要和vector对比的,接近两个数量级的差距阿。

单链表比STL的list快并不是因为STL效率损失,而是因为STL的list是一个双向链表,可能还有更多的底层细节(具体我就不了解了)。


---------------------

所以很显然的,vector比手写的单链表快。快很多。非常多。至于原因,我觉得主要有2:

1。链表是基于指针访问的,不仅需要更多的访存,而且cache命中率会比较低。
而vector的存储空间是连续的,在连续访问的情况下,命中率会高很多。

2。链表的内存是动态申请的,每一次都使用new/malloc从系统维护的堆中进行申请,效率很低。
当然,STL的list使用了优秀的allocator,但是效率仍然和vector无法比拟,所以说明第一条才是关键。

结论:在大多数情况下,我们可以迷信STL之父对效率的迷信。


--------------------

下附测试代码:

#include<iostream>
#include<vector>
using namespace std;

const int maxn = 100000000;

int d[maxn];
vector<int> e;

int main(){
    int i, j;
    if(1){ //  1是测试数组,0是测试vector
        printf("Array: \n");
        for(j = 0; j < 10; ++j){
            for (i = 0; i < maxn; ++i){
                d[i] = 0;
            }
        }
    }else{
        e.resize(maxn);
        printf("Vector: \n");
        vector<int>::iterator p;
        for(j = 0; j < 10; ++j){
            for(p = e.begin(); p != e.end(); ++p){
                *p = 2;
            }
        }
    }
    return 0;
}


#include <iostream>
#include <list>
using namespace std;

struct node_t{
    int data;
    node_t * next;
};
struct linklist{
    node_t *root;
    linklist(){ root = NULL; }
    void insert(int t){
        node_t *p = new node_t;
        p->data = t;
        p->next = root;
        root = p;
    }
    void iterate(){
        node_t *p = root;
        while(p != NULL){
            p->data = 2;
            p = p->next;
        }
    }
    /*  其实注释掉这一段是很挫的事情,但是因为只是测试使用一次,所以留给OS来做吧,这样程序会快点 :D
    ~linklist(){
        node_t *p = root;
        while(root != NULL){
            p = root;
            root = p->next;
            delete p;
        }
    }
    */
};

const int maxn = 10000000;

int main(){
    if(1){ // 1测试单链表,2测试list<int>
        linklist t;
        int i;
        for (i = 0; i < maxn; ++i){
            t.insert(i);
        }
        //t.iterate();  //如果遍历的话,还要慢些
    }else{
        list<int> t;
        int i;
        for (i = 0; i < maxn; ++i){
            t.push_back(i);
        }
        /* //如果遍历的话,还要慢些
        for (list<int>::iterator p = t.begin(); p != t.end(); ++p){
            *p = 2;
        }
        */
    }
    return 0;
}




欢迎扫码关注:




转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]