容器(vector)、数组、new创建的动态数组,你到底用哪一个(执行效率分析)

来源:互联网 发布:新手学java看什么书 编辑:程序博客网 时间:2024/04/29 23:35

1.问题的提出

        在没有了解vector之前,动态数组一般都是又new创建的。在了解vector后发现vector竟是那样方便好用,但方便的同时却是以牺牲执行效率为代价的。网上对vector和array的评价和吐槽,也是喜忧参半,各有不同啊。在面临选择的时候,我们到底用哪一种呢,我们可能都犹豫过?下面对该问题进行理论分析和实际测试验证。

2.理论分析

 

2.1预备知识-程序的内存分配

       一个由C/C++编译的程序占用的内存分为以下几个部分
       1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。是一种线性结构,其操作方式类似于数据结构中的栈,操作速度较快。但程序员是无法控制。
       2 、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,是一种链式结构,分配方式倒是类似于链表,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
        3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 
        4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放
        5、程序代码区—存放函数体的二进制代码。

        其中栈和堆构成了动态数据区:


├———————┤低端内存区域 
│ …… │ 
├———————┤ 
│ 动态数据区 │ 
├———————┤ 
│ …… │ 
├———————┤ 
│ 代码区 │ 
├———————┤ 
│ 静态数据区 │ 
├———————┤ 
│ …… │ 
├———————┤高端内存区域 

       以上堆和栈的分析参考博客1,关于堆和栈的区别与联系更详细的分析,请点击博客1

2.2数组、动态数组和vector的讨论如下:

       回到本文的主题,数组是底层数据类型,存放在栈中,其内存的分配和释放完全由系统自动完成,效率最高;动态数组是程序员由new运算符创建的,存放在堆中,需由delete运算符人工释放,否则会内存泄露;vector,存放在堆中,由STL库中程序负责内存的分配和释放,使用方便。

        关于vector的分析,参考STL源码剖析(P119-vector的内存管理)和C++primer(第四版9.4vector容器的自增长),vector的构造和内存管理如图1所示。如果容器中已经没有空间容纳新的元素,此时,由于元素必须连续存储以便索引访问,所以不能在内存中随便找个地方存储这个新元素。于是,vector 必须重新分配存储空间,用来存放原来的元素以及新添加的元素:存放在旧存储空间中的元素被复制到新存储空间里,接着插入新元素,最后撤销旧的存储空间。这是vector效率低的主要原因。

        注意所谓的动态自增加,并不是在原空间之后接续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。因此,对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。注意size和capacity的区别,size指容器当前拥有的元素个数,capacity指容器在必须分配新存储空间之前可以存储的元素总数,capacity总是大于或等于size的。


                                                  图1(来自STL源码剖析,图4-2)

3.数组、动态数组、vector的测试

       对vector、预先reverse的vector、数组、new创建的动态数组测试代码如下:

       vector的测试代码:

DWORD start=GetTickCount();int t=100;int n=200000;while (t){vector<int> a,b;for (int i=0;i<n;i++)a.push_back(i);t--;}cout<<"Runing time of program:"<<GetTickCount()-start<<endl;

        预先reverse的vector的测试代码:

 start=GetTickCount(); t=100; n=200000; while (t) { vector<int> a,b; b.reserve(n+1); for (int i=0;i<n;i++) b.push_back(i); t--; } cout<<"Runing time of program:"<<GetTickCount()-start<<endl;


        数组的测试代码:

 start=GetTickCount(); t=100; n=200000; while (t) { int  a[200000]; for (int i=0;i<n;i++)a[i]=i; t--; } cout<<"Runing time of program:"<<GetTickCount()-start<<endl;


         new创建的动态数组:

 start=GetTickCount(); t=100; n=200000; while (t) { int  *p=new int[n+1]; for (int i=0;i<n;i++) p[i]=i; delete []p;     t--; } cout<<"Runing time of program:"<<GetTickCount()-start<<endl;


       运行结果为:

       运行结果从上到下依次为,vector,预先reverse的vector、数组和动态数组的以上代码的执行时间(单位ms),从中可以看出,数组的执行效率是vector的10倍左右。执行效率不在同一个数量级,虽然容器操作简单方便。其效率排序依次是数组>动态数组>预先reverse的vector>vector。总之,数组和容器各有千秋,若硬件速度够快,对时间要求不那么高,用容器方便,也未尝不可。关键看你,看中什么,是效率还是方便。

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 牙掉了咽肚子里怎么办 假牙咽到肚子里怎么办 牙咽肚子里了怎么办 假牙吃肚子里了怎么办 陶瓷牙咽肚子里怎么办 做飞机耳朵疼难忍怎么办 肚子痛又拉不出来怎么办 胃胀气打嗝想吐怎么办 胃胀吐酸水恶心怎么办 一岁宝宝胃胀气怎么办 3岁宝宝腹胀呕吐怎么办 胃胀气想吐怎么办快速 胃胀然后吐了怎么办 1岁宝宝胃胀气怎么办 孩子胃胀气还吐怎么办 肚子里进了凉气怎么办 肠胃涨气肚子变大怎么办 感觉肚子胀胀的怎么办 肚子胀撑的难受怎么办 肚子着凉了很疼怎么办 来月经肚子疼怎么办最快的方法 孕妇上大便有血怎么办 做完爱小腹坠痛怎么办 月经不来肚子胀怎么办 月经期间肚子疼的厉害怎么办 大姨吗来了肚子疼该怎么办 孕妇7个月拉肚子怎么办 胃疼肚子也疼怎么办 6个月孕妇肚子疼怎么办 孕妇4个月肚子疼怎么办 孕妇5个月拉肚子怎么办 4个月孕妇拉肚子怎么办 怀孕5个月拉肚子怎么办 肠胃老是胀气很不舒服怎么办 肚子里有气排不出来怎么办 小兔子不吃兔粮怎么办 泰迪肚子一直叫怎么办 狗狗肚子响该怎么办 狗狗肚子一直响怎么办 一刮风空调就响怎么办 胃里有气往上顶怎么办