C++的STL模板库中提供了3种容器类:vector,list,deque
对于这三种容器,在觉得好用的同时,经常会让我们困惑应该选择哪一种来实现我们的逻辑。
在少量数据操作的程序中随便哪一种用起来感觉差别并不是很大,
但是当数据达到一定数量后,会明显感觉性能上有很大差异。
本文就试图从介绍,以及性能比较两个方面来讨论这个问题。
vector - 会自动增长的数组
vector又称为向量数组,他是为了解决程序中定义的数组是
不能动态改变大小这个缺点而出现的。
一般程序实现是在类创建的时候同时创建一个定长数组,
随着数据不断被写入,一旦数组被填满,则重新开辟一块更大的内存区,
把原有的数据复制到新的内存区,抛弃原有的内存,如此反复。
由于程序自动管理数组的增长,对于我们程序员来说确实轻松了不少,
只管把数据往里面插就行了,当然把物理内存和虚拟内存插爆掉了
就是操作系统来找你麻烦了:-)
vector由于数组的增长只能向前,所以也只提供了后端插入和后端删除,
也就是push_back和pop_back。当然在前端和中间要操作数据也是可以的,
用insert和erase,但是前端和中间对数据进行操作必然会引起数据块的移动,
这对性能影响是非常大的。
对于所有数组来说,最大的优势就是随机访问的能力。
在vector中,提供了at和[]运算符这两个方法来进行随机访问。
由于每个数据大小相同,并且无间隔地排列在内存中,
所以要对某一个数据操作,只需要用一个表达式就能直接计算出地址:
address = base + index * datasize
同样,对vector进行内存开辟,初始化,清除都是不需要花大力气的,
从头到尾都只有一块内存。
不能动态改变大小这个缺点而出现的。
一般程序实现是在类创建的时候同时创建一个定长数组,
随着数据不断被写入,一旦数组被填满,则重新开辟一块更大的内存区,
把原有的数据复制到新的内存区,抛弃原有的内存,如此反复。
由于程序自动管理数组的增长,对于我们程序员来说确实轻松了不少,
只管把数据往里面插就行了,当然把物理内存和虚拟内存插爆掉了
就是操作系统来找你麻烦了:-)
vector由于数组的增长只能向前,所以也只提供了后端插入和后端删除,
也就是push_back和pop_back。当然在前端和中间要操作数据也是可以的,
用insert和erase,但是前端和中间对数据进行操作必然会引起数据块的移动,
这对性能影响是非常大的。
对于所有数组来说,最大的优势就是随机访问的能力。
在vector中,提供了at和[]运算符这两个方法来进行随机访问。
由于每个数据大小相同,并且无间隔地排列在内存中,
所以要对某一个数据操作,只需要用一个表达式就能直接计算出地址:
address = base + index * datasize
同样,对vector进行内存开辟,初始化,清除都是不需要花大力气的,
从头到尾都只有一块内存。
list - 擅长插入删除的链表
有黑必有白,世界万物都是成对出现的。
链表对于数组来说就是相反的存在。
数组本身是没有动态增长能力的(程序中也必须重新开辟内存来实现),
而链表强悍的就是动态增长和删除的能力。
但对于数组强悍的随机访问能力来说的话,链表却很弱。
list是一个双向链表的实现。
为了提供双向遍历的能力,list要比一般的数据单元多出两个指向前后的指针。
这也是没办法的,毕竟现在的PC内存结构就是一个大数组,
链表要在不同的环境中实现自己的功能就需要花更多空间。
list提供了push_back,push_front,pop_back,pop_front四个方法
来方便操作list的两端数据的增加和删除,不过少了vector的at和[]运算符的
随机访问数据的方法。并不是不能实现,而是list的设计者
并不想让list去做那些事情,因为他们会做得非常差劲。
对于list来说,清除容器内所有的元素是一件苦力活,
因为所有数据单元的内存都不连续,list只有一个一个遍历来删除。
链表对于数组来说就是相反的存在。
数组本身是没有动态增长能力的(程序中也必须重新开辟内存来实现),
而链表强悍的就是动态增长和删除的能力。
但对于数组强悍的随机访问能力来说的话,链表却很弱。
list是一个双向链表的实现。
为了提供双向遍历的能力,list要比一般的数据单元多出两个指向前后的指针。
这也是没办法的,毕竟现在的PC内存结构就是一个大数组,
链表要在不同的环境中实现自己的功能就需要花更多空间。
list提供了push_back,push_front,pop_back,pop_front四个方法
来方便操作list的两端数据的增加和删除,不过少了vector的at和[]运算符的
随机访问数据的方法。并不是不能实现,而是list的设计者
并不想让list去做那些事情,因为他们会做得非常差劲。
对于list来说,清除容器内所有的元素是一件苦力活,
因为所有数据单元的内存都不连续,list只有一个一个遍历来删除。
deque - 拥有vector和list两者优点的双端队列
黑与白,处于这两个极端之间的就是令人愉悦的彩色了。
deque作为vector和list的结合体,确实有着不凡的实力。
STL的deque的实现没有怎么去看过,不过根据我自己的猜测,
应该是把数组分段化,在分段的数组上添加指针来把所有段连在一起,
最终成为一个大的数组。
deque和list一样,提供了push_back,push_front,
pop_back,pop_front四个方法。可以想象,如果要对deque的两端进行操作,
也就是要对第一段和最后一段的定长数组进行重新分配内存区,
由于分过段的数组很小,重新分配的开销也就不会很大。
deque也和vector一样,提供了at和[]运算符的方法。
要计算出某个数据的地址的话,虽然要比vector麻烦一点,
但效率要比list高多了。
首先和list一样进行遍历,每次遍历的时候累积每段数组的大小,
当遍历到某个段,而且baseN <= index < baseN + baseN_length的时候,
通过address = baseN + baseN_index就能计算出地址
由于分过段的后链表的长度也不是很长,所以遍历对于
整体性能的影响就微乎其微了。
看起来deque很无敌吧,不过deque和希腊神话的阿吉里斯一样,
再怎么强大也是有自己的弱点的,之后的测试数据中就能看到了。
deque作为vector和list的结合体,确实有着不凡的实力。
STL的deque的实现没有怎么去看过,不过根据我自己的猜测,
应该是把数组分段化,在分段的数组上添加指针来把所有段连在一起,
最终成为一个大的数组。
deque和list一样,提供了push_back,push_front,
pop_back,pop_front四个方法。可以想象,如果要对deque的两端进行操作,
也就是要对第一段和最后一段的定长数组进行重新分配内存区,
由于分过段的数组很小,重新分配的开销也就不会很大。
deque也和vector一样,提供了at和[]运算符的方法。
要计算出某个数据的地址的话,虽然要比vector麻烦一点,
但效率要比list高多了。
首先和list一样进行遍历,每次遍历的时候累积每段数组的大小,
当遍历到某个段,而且baseN <= index < baseN + baseN_length的时候,
通过address = baseN + baseN_index就能计算出地址
由于分过段的后链表的长度也不是很长,所以遍历对于
整体性能的影响就微乎其微了。
看起来deque很无敌吧,不过deque和希腊神话的阿吉里斯一样,
再怎么强大也是有自己的弱点的,之后的测试数据中就能看到了。
性能竞技场
为了能更好地进行比较,我们让静态数组(程序中写死的)和
动态数组(程序中new出来的)也参加了部分竞技。
竞技项目:
动态数组(程序中new出来的)也参加了部分竞技。
竞技项目:
- 初始化:对于静态和动态数组,逐一赋值,对于容器,push_back插入
- 前向遍历:从0到n-1,每个数据自加1
- 后向遍历:从n-1到0,每个数据自减1
- 随机访问:在0到n-1中,随机抽取一定数量的数据进行读取
- 后端插入:用push_back在后端插入一定数量的数据
- 后端移除:用pop_back在后端移除一定数量的数据
- 前端插入:用push_front在前端插入一定数量的数据
- 前端移除:用pop_front在前端移除一定数量的数据
- 中间插入:用insert在中间插入一定数量的数据
- 中间移除:用erase在中间移除一定数量的数据
- 反初始化:对于静态和动态数组,ZeroMemory删除所有数据,对于容器,调用clear方法
规则:
- vector,list,deque都调用默认的构造函数来创建
- 数组和容器的数据项都是1,000,000个
- 前端和后端插入的数据项是10,000个
- 前端和后端删除的数据项是10,000个
- 随机访问的数据项是10,000个
- 数据类型采用int型
- 计时采用RDTSC高精度计时器来计时
- 随机访问的数据的位置序列在测试前随机生成,所有数组和容器都采用这个序列
- 测试采用Debug版(Release版会对代码进行优化,可能会对测试产生一定的影响)
- 测试3次,取平均值
测试机配置:
Intel(R) Core(TM)2 CPU T7400 2.16GHz 2.16GHz
2.00GB内存
测试结果:(单位 秒)
Intel(R) Core(TM)2 CPU T7400 2.16GHz 2.16GHz
2.00GB内存
测试结果:(单位 秒)
| 测试项目 | 静态数组 | 动态数组 | vector | list | deque | 备注 |
| 初始化 | 0.00551 | 0.00461 | 0.207 | 1.30 | 0.352 | list每个数据项都有附加数据,速度稍慢了一些 |
| 前向遍历 | 0.00381 | 0.00549 | 0.0796 | 0.0756 | 0.0713 | |
| 后向遍历 | 0.00422 | 0.00478 | 0.885 | 0.879 | 0.690 | |
| 随机访问 | 0.000334 | 0.000342 | 0.00119 | 148 | 0.0115 | list把时间都耗在了找寻相应数据上 |
| 后端插入 | N/A | N/A | 0.00192 | 0.0128 | 0.00260 | |
| 后端移除 | N/A | N/A | 0.00131 | 0.0293 | 0.00194 | |
| 前端插入 | N/A | N/A | 10.2 | 0.0128 | 0.00547 | vector对前端操作很苦手啊 |
| 前端移除 | N/A | N/A | 10.3 | 0.0297 | 0.00135 | 同上 |
| 中间插入 | N/A | N/A | 195 | 187 | 764 | 看似万能的deque的最大弱点,因为复杂的结构导致中间数据操作带来的复杂性大大增加,体现在操作时间是其他两个的几倍 |
| 中间移除 | N/A | N/A | 195 | 209 | 753 | 同上 |
| 反初始化 | 0.00139 | 0.00290 | 0.0000106 | 0.693 | 0.305 | vector貌似是直接抛弃内存的,其他两个就没那么简单了 |
性能总结与使用建议
| 测试项目 | 静态数组 | 动态数组 | vector | list | deque |
| 初始化 | ★★★★★ | ★★★★★ | ★★★★☆ | ★★★☆☆ | ★★★★☆ |
| 前向遍历 | ★★★★★ | ★★★★★ | ★★★★☆ | ★★★★☆ | ★★★★☆ |
| 后向遍历 | ★★★★★ | ★★★★★ | ★★★★☆ | ★★★★☆ | ★★★★☆ |
| 随机访问 | ★★★★★ | ★★★★★ | ★★★★☆ | ★☆☆☆☆ | ★★★☆☆ |
| 后端插入 | N/A | N/A | ★★★★★ | ★★★★☆ | ★★★★★ |
| 后端移除 | N/A | N/A | ★★★★★ | ★★★★☆ | ★★★★★ |
| 前端插入 | N/A | N/A | ★★☆☆☆ | ★★★★☆ | ★★★★★ |
| 前端移除 | N/A | N/A | ★★☆☆☆ | ★★★★☆ | ★★★★★ |
| 中间插入 | N/A | N/A | ★★☆☆☆ | ★★☆☆☆ | ★☆☆☆☆ |
| 中间移除 | N/A | N/A | ★★☆☆☆ | ★★☆☆☆ | ★☆☆☆☆ |
| 反初始化 | ★★★★★ | ★★★★★ | ★★★★★ | ★★★★☆ | ★★★★☆ |
一些使用上的建议:
Level 1 - 仅仅作为Map使用:采用静态数组
Level 2 - 保存定长数据,使用时也是全部遍历:采用动态数组(长度一开始就固定的话静态数组也行)
Level 3 - 保存不定长数组,需要动态增加的能力,侧重于寻找数据的速度:采用vector
Level 3 - 保存不定长数组,需要动态增加的能力,侧重于增加删除数据的速度:采用list
Level 4 - 对数据有复杂操作,即需要前后增删数据的能力,又要良好的数据访问速度:采用deque
Level 5 - 对数据中间的增删操作比较多:采用list,建议在排序的基础上,批量进行增删可以对运行效率提供最大的保证
Level 6 - 上述中找不到适合的:组合STL容器或者自己建立特殊的数据结构来实现
测试程序清单
>>>main.cpp<<<
| 0001 | #include <string> |
| 0002 | #include <iostream> |
| 0003 | #include <iomanip> |
| 0004 | #include <vector> |
| 0005 | #include <list> |
| 0006 | #include <set> |
| 0007 | #include <map> |
| 0008 | #include <deque> |
| 0009 | #include <algorithm> |
| 0010 | #include <windows.h> |
| 0011 | |
| 0012 | using namespace std; |
| 0013 | |
| 0014 | inline unsigned __int64 GetTick() |
| 0015 | { |
| 0016 | __asm RDTSC |
| 0017 | } |
| 0018 | |
| 0019 | // 定数の定義 |
| 0020 | const int ARRAY_SIZE = 1000 * 1000 * 1; |
| 0021 | const int INSERT_NUM = 1000 * 10; |
| 0022 | const int DELETE_NUM = INSERT_NUM; |
| 0023 | const int READ_RANDOM_NUM = 1000 * 10; |
| 0024 | const int VALUE_OFFSET = 0; |
| 0025 | typedef int TARGET_TYPE; |
| 0026 | typedef void (*FUNC)(); |
| 0027 | |
| 0028 | |
| 0029 | // グローバル変数の定義 |
| 0030 | __int64 g_second; |
| 0031 | int g_rand_list[READ_RANDOM_NUM]; |
| 0032 | TARGET_TYPE g_static_array[ARRAY_SIZE]; |
| 0033 | TARGET_TYPE* g_dynamic_array; |
| 0034 | TARGET_TYPE stub; |
| 0035 | std::vector <TARGET_TYPE> g_vector; |
| 0036 | std::list <TARGET_TYPE> g_list; |
| 0037 | std::deque <TARGET_TYPE> g_deque; |
| 0038 | |
| 0039 | |
| 0040 | // 関数定義 |
| 0041 | __int64 GetPerSecondTick(); |
| 0042 | double GetSecond(__int64 beginTick); |
| 0043 | void init(); |
| 0044 | void uninit(); |
| 0045 | void start(); |
| 0046 | void clear(); |
| 0047 | void check(); |
| 0048 | void calctime(FUNC f, string msg); |
| 0049 | void DebugOut(string str); |
| 0050 | void AddOneBySelf(TARGET_TYPE& tt); |
| 0051 | void SubOneBySelf(TARGET_TYPE& tt); |
| 0052 | |
| 0053 | |
| 0054 | void StaticArrayCheck(); |
| 0055 | void DynamicArrayCheck(); |
| 0056 | void VectorCheck(); |
| 0057 | void ListCheck(); |
| 0058 | void DequeCheck(); |
| 0059 | |
| 0060 | |
| 0061 | void StaticArrayInit(); |
| 0062 | void DynamicArrayInit(); |
| 0063 | void VectorInit(); |
| 0064 | void ListInit(); |
| 0065 | void DequeInit(); |
| 0066 | |
| 0067 | |
| 0068 | void StaticArrayUninit(); |
| 0069 | void DynamicArrayUninit(); |
| 0070 | void VectorUninit(); |
| 0071 | void ListUninit(); |
| 0072 | void DequeUninit(); |
| 0073 | |
| 0074 | |
| 0075 | void StaticArrayForEach(); |
| 0076 | void DynamicArrayForEach(); |
| 0077 | void VectorForEach(); |
| 0078 | void ListForEach(); |
| 0079 | void DequeForEach(); |
| 0080 | |
| 0081 | |
| 0082 | void StaticArrayForEachRight(); |
| 0083 | void DynamicArrayForEachRight(); |
| 0084 | void VectorForEachRight(); |
| 0085 | void ListForEachRight(); |
| 0086 | void DequeForEachRight(); |
| 0087 | |
| 0088 | |
| 0089 | void StaticArrayForEachRandom(); |
| 0090 | void DynamicArrayForEachRandom(); |
| 0091 | void VectorForEachRandom(); |
| 0092 | void ListForEachRandom(); |
| 0093 | void DequeForEachRandom(); |
| 0094 | |
| 0095 | |
| 0096 | void VectorInsertAtBack(); |
| 0097 | void ListInsertAtBack(); |
| 0098 | void DequeInsertAtBack(); |
| 0099 | |
| 0100 | |
| 0101 | void VectorDeleteAtBack(); |
| 0102 | void ListDeleteAtBack(); |
| 0103 | void DequeDeleteAtBack(); |
| 0104 | |
| 0105 | |
| 0106 | void VectorInsertAtFront(); |
| 0107 | void ListInsertAtFront(); |
| 0108 | void DequeInsertAtFront(); |
| 0109 | |
| 0110 | |
| 0111 | void VectorDeleteAtFront(); |
| 0112 | void ListDeleteAtFront(); |
| 0113 | void DequeDeleteAtFront(); |
| 0114 | |
| 0115 | |
| 0116 | |
| 0117 | void VectorInsertAtMiddle(); |
| 0118 | void ListInsertAtMiddle(); |
| 0119 | void DequeInsertAtMiddle(); |
| 0120 | |
| 0121 | |
| 0122 | void VectorDeleteAtMiddle(); |
| 0123 | void ListDeleteAtMiddle(); |
| 0124 | void DequeDeleteAtMiddle(); |
| 0125 | |
| 0126 | |
| 0127 | void init() |
| 0128 | { |
| 0129 | g_second = GetPerSecondTick(); |
| 0130 | g_dynamic_array = new TARGET_TYPE[ARRAY_SIZE]; |
| 0131 | srand((int)GetTick()); |
| 0132 | for (int i = 0; i < READ_RANDOM_NUM; i++) |
| 0133 | { |
| 0134 | g_rand_list[i] = MulDiv(ARRAY_SIZE - 1, rand(), RAND_MAX); |
| 0135 | } |
| 0136 | |
| 0137 | calctime(StaticArrayInit, "StaticArrayInit: "); |
| 0138 | calctime(DynamicArrayInit, "DynamicArrayInit: "); |
| 0139 | calctime(VectorInit, "VectorInit: "); |
| 0140 | calctime(ListInit, "ListInit: "); |
| 0141 | calctime(DequeInit, "DequeInit: "); |
| 0142 | cout << endl; |
| 0143 | } |
| 0144 | |
| 0145 | void uninit() |
| 0146 | { |
| 0147 | calctime(StaticArrayUninit, "StaticArrayUninit: "); |
| 0148 | calctime(DynamicArrayUninit, "DynamicArrayUninit: "); |
| 0149 | calctime(VectorUninit, "VectorUninit: "); |
| 0150 | calctime(ListUninit, "ListUninit: "); |
| 0151 | calctime(DequeUninit, "DequeUninit: "); |
| 0152 | cout << endl; |
| 0153 | } |
| 0154 | |
| 0155 | void check() |
| 0156 | { |
| 0157 | StaticArrayCheck(); |
| 0158 | DynamicArrayCheck(); |
| 0159 | VectorCheck(); |
| 0160 | ListCheck(); |
| 0161 | DequeCheck(); |
| 0162 | } |
| 0163 | |
| 0164 | void start() |
| 0165 | { |
| 0166 | calctime(StaticArrayForEach, "StaticArrayForEach: "); |
| 0167 | calctime(DynamicArrayForEach, "DynamicArrayForEach: "); |
| 0168 | calctime(VectorForEach, "VectorForEach: "); |
| 0169 | calctime(ListForEach, "ListForEach: "); |
| 0170 | calctime(DequeForEach, "DequeForEach: "); |
| 0171 | cout << endl; |
| 0172 | |
| 0173 | calctime(StaticArrayForEachRight, "StaticArrayForEachRight: "); |
| 0174 | calctime(DynamicArrayForEachRight, "DynamicArrayForEachRight: "); |
| 0175 | calctime(VectorForEachRight, "VectorForEachRight: "); |
| 0176 | calctime(ListForEachRight, "ListForEachRight: "); |
| 0177 | calctime(DequeForEachRight, "DequeForEachRight: "); |
| 0178 | cout << endl; |
| 0179 | |
| 0180 | calctime(StaticArrayForEachRandom, "StaticArrayForEachRandom: "); |
| 0181 | calctime(DynamicArrayForEachRandom, "DynamicArrayForEachRandom: "); |
| 0182 | calctime(VectorForEachRandom, "VectorForEachRandom: "); |
| 0183 | calctime(ListForEachRandom, "ListForEachRandom: "); |
| 0184 | calctime(DequeForEachRandom, "DequeForEachRandom: "); |
| 0185 | cout << endl; |
| 0186 | |
| 0187 | |
| 0188 | calctime(NULL, ""); |
| 0189 | calctime(NULL, ""); |
| 0190 | calctime(VectorInsertAtBack, "VectorInsertAtBack: "); |
| 0191 | calctime(ListInsertAtBack, "ListInsertAtBack: "); |
| 0192 | calctime(DequeInsertAtBack, "DequeInsertAtBack: "); |
| 0193 | cout << endl; |
| 0194 | |
| 0195 | |
| 0196 | calctime(NULL, ""); |
| 0197 | calctime(NULL, ""); |
| 0198 | calctime(VectorDeleteAtBack, "VectorDeleteAtBack: "); |
| 0199 | calctime(ListDeleteAtBack, "ListDeleteAtBack: "); |
| 0200 | calctime(DequeDeleteAtBack, "DequeDeleteAtBack: "); |
| 0201 | cout << endl; |
| 0202 | |
| 0203 | |
| 0204 | |
| 0205 | calctime(NULL, ""); |
| 0206 | calctime(NULL, ""); |
| 0207 | calctime(VectorInsertAtFront, "VectorInsertAtFront: "); |
| 0208 | calctime(ListInsertAtFront, "ListInsertAtFront: "); |
| 0209 | calctime(DequeInsertAtFront, "DequeInsertAtFront: "); |
| 0210 | cout << endl; |
| 0211 | |
| 0212 | |
| 0213 | calctime(NULL, ""); |
| 0214 | calctime(NULL, ""); |
| 0215 | calctime(VectorDeleteAtFront, "VectorDeleteAtFront: "); |
| 0216 | calctime(ListDeleteAtFront, "ListDeleteAtFront: "); |
| 0217 | calctime(DequeDeleteAtFront, "DequeDeleteAtFront: "); |
| 0218 | cout << endl; |
| 0219 | |
| 0220 | |
| 0221 | |
| 0222 | calctime(NULL, ""); |
| 0223 | calctime(NULL, ""); |
| 0224 | calctime(VectorInsertAtMiddle, "VectorInsertAtMiddle: "); |
| 0225 | calctime(ListInsertAtMiddle, "ListInsertAtMiddle: "); |
| 0226 | calctime(DequeInsertAtMiddle, "DequeInsertAtMiddle: "); |
| 0227 | cout << endl; |
| 0228 | |
| 0229 | |
| 0230 | calctime(NULL, ""); |
| 0231 | calctime(NULL, ""); |
| 0232 | calctime(VectorDeleteAtMiddle, "VectorDeleteAtMiddle: "); |
| 0233 | calctime(ListDeleteAtMiddle, "ListDeleteAtMiddle: "); |
| 0234 | calctime(DequeDeleteAtMiddle, "DequeDeleteAtMiddle: "); |
| 0235 | cout << endl; |
| 0236 | } |
| 0237 | |
| 0238 | |
| 0239 | void clear() |
| 0240 | { |
| 0241 | delete g_dynamic_array; |
| 0242 | } |
| 0243 | |
| 0244 | |
| 0245 | |
| 0246 | |
| 0247 | |
| 0248 | void StaticArrayInit() |
| 0249 | { |
| 0250 | for (int i = 0; i < ARRAY_SIZE; i++) g_static_array[i] = i; |
| 0251 | } |
| 0252 | |
| 0253 | void DynamicArrayInit() |
| 0254 | { |
| 0255 | for (int i = 0; i < ARRAY_SIZE; i++) g_dynamic_array[i] = i; |
| 0256 | } |
| 0257 | |
| 0258 | void VectorInit() |
| 0259 | { |
| 0260 | for (int i = 0; i < ARRAY_SIZE; i++) g_vector.push_back(i); |
| 0261 | } |
| 0262 | |
| 0263 | void ListInit() |
| 0264 | { |
| 0265 | for (int i = 0; i < ARRAY_SIZE; i++) g_list.push_back(i); |
| 0266 | } |
| 0267 | |
| 0268 | void DequeInit() |
| 0269 | { |
| 0270 | for (int i = 0; i < ARRAY_SIZE; i++) g_deque.push_back(i); |
| 0271 | } |
| 0272 | |
| 0273 | |
| 0274 | |
| 0275 | |
| 0276 | |
| 0277 | void StaticArrayUninit() |
| 0278 | { |
| 0279 | ZeroMemory(g_static_array, ARRAY_SIZE * sizeof(TARGET_TYPE)); |
| 0280 | } |
| 0281 | |
| 0282 | void DynamicArrayUninit() |
| 0283 | { |
| 0284 | ZeroMemory(g_dynamic_array, ARRAY_SIZE * sizeof(TARGET_TYPE)); |
| 0285 | } |
| 0286 | |
| 0287 | void VectorUninit() |
| 0288 | { |
| 0289 | g_vector.clear(); |
| 0290 | } |
| 0291 | |
| 0292 | void ListUninit() |
| 0293 | { |
| 0294 | g_list.clear(); |
| 0295 | } |
| 0296 | |
| 0297 | void DequeUninit() |
| 0298 | { |
| 0299 | g_deque.clear(); |
| 0300 | } |
| 0301 | |
| 0302 | void StaticArrayForEach() |
| 0303 | { |
| 0304 | for (int i = 0; i < ARRAY_SIZE; i++) ++g_static_array[i]; |
| 0305 | } |
| 0306 | |
| 0307 | void DynamicArrayForEach() |
| 0308 | { |
| 0309 | for (int i = 0; i < ARRAY_SIZE; i++) ++g_dynamic_array[i]; |
| 0310 | } |
| 0311 | |
| 0312 | void VectorForEach() |
| 0313 | { |
| 0314 | for_each(g_vector.begin(), g_vector.end(), AddOneBySelf); |
| 0315 | } |
| 0316 | |
| 0317 | void ListForEach() |
| 0318 | { |
| 0319 | for_each(g_list.begin(), g_list.end(), AddOneBySelf); |
| 0320 | } |
| 0321 | |
| 0322 | void DequeForEach() |
| 0323 | { |
| 0324 | for_each(g_deque.begin(), g_deque.end(), AddOneBySelf); |
| 0325 | } |
| 0326 | |
| 0327 | void StaticArrayForEachRight() |
| 0328 | { |
| 0329 | for (int i = ARRAY_SIZE; i > 0; i--) --g_static_array[i - 1]; |
| 0330 | } |
| 0331 | |
| 0332 | void DynamicArrayForEachRight() |
| 0333 | { |
| 0334 | for (int i = ARRAY_SIZE; i > 0; i--) --g_dynamic_array[i - 1]; |
| 0335 | } |
| 0336 | |
| 0337 | void VectorForEachRight() |
| 0338 | { |
| 0339 | for_each(g_vector.rbegin(), g_vector.rend(), SubOneBySelf); |
| 0340 | } |
| 0341 | |
| 0342 | void ListForEachRight() |
| 0343 | { |
| 0344 | for_each(g_list.rbegin(), g_list.rend(), SubOneBySelf); |
| 0345 | } |
| 0346 | |
| 0347 | void DequeForEachRight() |
| 0348 | { |
| 0349 | for_each(g_deque.rbegin(), g_deque.rend(), SubOneBySelf); |
| 0350 | } |
| 0351 | |
| 0352 | |
| 0353 | void StaticArrayForEachRandom() |
| 0354 | { |
| 0355 | for (int i = 0; i < READ_RANDOM_NUM; i++) stub = g_static_array[g_rand_list[i]]; |
| 0356 | } |
| 0357 | |
| 0358 | void DynamicArrayForEachRandom() |
| 0359 | { |
| 0360 | for (int i = 0; i < READ_RANDOM_NUM; i++) stub = g_dynamic_array[g_rand_list[i]]; |
| 0361 | } |
| 0362 | |
| 0363 | void VectorForEachRandom() |
| 0364 | { |
| 0365 | for (int i = 0; i < READ_RANDOM_NUM; i++) stub = g_vector[g_rand_list[i]]; |
| 0366 | } |
| 0367 | |
| 0368 | void ListForEachRandom() |
| 0369 | { |
| 0370 | list<TARGET_TYPE>::iterator iter; |
| 0371 | |
| 0372 | for (int i = 0; i < READ_RANDOM_NUM; i++) |
| 0373 | { |
| 0374 | iter = g_list.begin(); |
| 0375 | for (int j = 0; j < g_rand_list[i]; j++) ++iter; |
| 0376 | stub = (*iter); |
| 0377 | } |
| 0378 | } |
| 0379 | |
| 0380 | void DequeForEachRandom() |
| 0381 | { |
| 0382 | for (int i = 0; i < READ_RANDOM_NUM; i++) stub = g_deque[g_rand_list[i]]; |
| 0383 | } |
| 0384 | |
| 0385 | |
| 0386 | |
| 0387 | void StaticArrayCheck() |
| 0388 | { |
| 0389 | for (int i = 0; i < ARRAY_SIZE; i++) |
| 0390 | { |
| 0391 | if (g_static_array[i] != (i + VALUE_OFFSET)) |
| 0392 | { |
| 0393 | cerr << "StaticArrayCheck NG:" << i << " = " << g_static_array[i] << endl; |
| 0394 | return; |
| 0395 | } |
| 0396 | } |
| 0397 | } |
| 0398 | |
| 0399 | void DynamicArrayCheck() |
| 0400 | { |
| 0401 | for (int i = 0; i < ARRAY_SIZE; i++) |
| 0402 | { |
| 0403 | if (g_dynamic_array[i] != (i + VALUE_OFFSET)) |
| 0404 | { |
| 0405 | cerr << "DynamicArrayCheck NG:" << i << " = " << g_dynamic_array[i] << endl; |
| 0406 | return; |
| 0407 | } |
| 0408 | } |
| 0409 | } |
| 0410 | |
| 0411 | void VectorCheck() |
| 0412 | { |
| 0413 | vector<TARGET_TYPE>::iterator iter; |
| 0414 | int i = 0; |
| 0415 | |
| 0416 | for (iter = g_vector.begin(); iter != g_vector.end(); ++iter, ++i) |
| 0417 | { |
| 0418 | if ((*iter) != (i + VALUE_OFFSET)) |
| 0419 | { |
| 0420 | cerr << "VectorCheck NG:" << i << " = " << (*iter) << endl; |
| 0421 | return; |
| 0422 | } |
| 0423 | } |
| 0424 | } |
| 0425 | |
| 0426 | void ListCheck() |
| 0427 | { |
| 0428 | list<TARGET_TYPE>::iterator iter; |
| 0429 | int i = 0; |
| 0430 | |
| 0431 | for (iter = g_list.begin(); iter != g_list.end(); ++iter, ++i) |
| 0432 | { |
| 0433 | if ((*iter) != (i + VALUE_OFFSET)) |
| 0434 | { |
| 0435 | cerr << "ListCheck NG:" << i << " = " << (*iter) << endl; |
| 0436 | return; |
| 0437 | } |
| 0438 | } |
| 0439 | } |
| 0440 | |
| 0441 | void DequeCheck() |
| 0442 | { |
| 0443 | deque<TARGET_TYPE>::iterator iter; |
| 0444 | int i = 0; |
| 0445 | |
| 0446 | for (iter = g_deque.begin(); iter != g_deque.end(); ++iter, ++i) |
| 0447 | { |
| 0448 | if ((*iter) != (i + VALUE_OFFSET)) |
| 0449 | { |
| 0450 | cerr << "DequeCheck NG:" << i << " = " << (*iter) << endl; |
| 0451 | return; |
| 0452 | } |
| 0453 | } |
| 0454 | } |
| 0455 | |
| 0456 | |
| 0457 | |
| 0458 | void VectorInsertAtBack() |
| 0459 | { |
| 0460 | for (int i = 0; i < INSERT_NUM; i++) g_vector.push_back((TARGET_TYPE)0); |
| 0461 | } |
| 0462 | |
| 0463 | void ListInsertAtBack() |
| 0464 | { |
| 0465 | for (int i = 0; i < INSERT_NUM; i++) g_list.push_back((TARGET_TYPE)0); |
| 0466 | } |
| 0467 | |
| 0468 | void DequeInsertAtBack() |
| 0469 | { |
| 0470 | for (int i = 0; i < INSERT_NUM; i++) g_deque.push_back((TARGET_TYPE)0); |
| 0471 | } |
| 0472 | |
| 0473 | void VectorDeleteAtBack() |
| 0474 | { |
| 0475 | for (int i = 0; i < DELETE_NUM; i++) g_vector.pop_back(); |
| 0476 | } |
| 0477 | |
| 0478 | void ListDeleteAtBack() |
| 0479 | { |
| 0480 | for (int i = 0; i < DELETE_NUM; i++) g_list.pop_back(); |
| 0481 | } |
| 0482 | |
| 0483 | void DequeDeleteAtBack() |
| 0484 | { |
| 0485 | for (int i = 0; i < DELETE_NUM; i++) g_deque.pop_back(); |
| 0486 | } |
| 0487 | |
| 0488 | |
| 0489 | |
| 0490 | |
| 0491 | void VectorInsertAtFront() |
| 0492 | { |
| 0493 | for (int i = 0; i < INSERT_NUM; i++) g_vector.insert(g_vector.begin(), (TARGET_TYPE)0); |
| 0494 | } |
| 0495 | |
| 0496 | void ListInsertAtFront() |
| 0497 | { |
| 0498 | for (int i = 0; i < INSERT_NUM; i++) g_list.push_front((TARGET_TYPE)0); |
| 0499 | } |
| 0500 | |
| 0501 | void DequeInsertAtFront() |
| 0502 | { |
| 0503 | for (int i = 0; i < INSERT_NUM; i++) g_deque.push_front((TARGET_TYPE)0); |
| 0504 | } |
| 0505 | |
| 0506 | |
| 0507 | |
| 0508 | void VectorDeleteAtFront() |
| 0509 | { |
| 0510 | for (int i = 0; i < DELETE_NUM; i++) g_vector.erase(g_vector.begin()); |
| 0511 | } |
| 0512 | |
| 0513 | void ListDeleteAtFront() |
| 0514 | { |
| 0515 | for (int i = 0; i < DELETE_NUM; i++) g_list.pop_front(); |
| 0516 | } |
| 0517 | |
| 0518 | void DequeDeleteAtFront() |
| 0519 | { |
| 0520 | for (int i = 0; i < DELETE_NUM; i++) g_deque.pop_front(); |
| 0521 | } |
| 0522 | |
| 0523 | |
| 0524 | void VectorInsertAtMiddle() |
| 0525 | { |
| 0526 | vector<TARGET_TYPE>::iterator iter; |
| 0527 | for (int i = 0; i < INSERT_NUM; i++) |
| 0528 | { |
| 0529 | iter = g_vector.begin(); |
| 0530 | for (unsigned int j = 0; j < g_vector.size() / 2; j++) ++iter; |
| 0531 | g_vector.insert(iter, (TARGET_TYPE)0); |
| 0532 | } |
| 0533 | } |
| 0534 | |
| 0535 | void ListInsertAtMiddle() |
| 0536 | { |
| 0537 | list<TARGET_TYPE>::iterator iter; |
| 0538 | for (int i = 0; i < INSERT_NUM; i++) |
| 0539 | { |
| 0540 | iter = g_list.begin(); |
| 0541 | for (unsigned int j = 0; j < g_list.size() / 2; j++) ++iter; |
| 0542 | g_list.insert(iter, (TARGET_TYPE)0); |
| 0543 | } |
| 0544 | } |
| 0545 | |
| 0546 | void DequeInsertAtMiddle() |
| 0547 | { |
| 0548 | deque<TARGET_TYPE>::iterator iter; |
| 0549 | for (int i = 0; i < INSERT_NUM; i++) |
| 0550 | { |
| 0551 | iter = g_deque.begin(); |
| 0552 | for (unsigned int j = 0; j < g_deque.size() / 2; j++) ++iter; |
| 0553 | g_deque.insert(iter, (TARGET_TYPE)0); |
| 0554 | } |
| 0555 | } |
| 0556 | |
| 0557 | |
| 0558 | void VectorDeleteAtMiddle() |
| 0559 | { |
| 0560 | vector<TARGET_TYPE>::iterator iter; |
| 0561 | for (int i = 0; i < DELETE_NUM; i++) |
| 0562 | { |
| 0563 | iter = g_vector.begin(); |
| 0564 | for (unsigned int j = 0; j < g_vector.size() / 2; j++) ++iter; |
| 0565 | g_vector.erase(iter); |
| 0566 | } |
| 0567 | } |
| 0568 | |
| 0569 | void ListDeleteAtMiddle() |
| 0570 | { |
| 0571 | list<TARGET_TYPE>::iterator iter; |
| 0572 | for (int i = 0; i < DELETE_NUM; i++) |
| 0573 | { |
| 0574 | iter = g_list.begin(); |
| 0575 | for (unsigned int j = 0; j < g_list.size() / 2; j++) ++iter; |
| 0576 | g_list.erase(iter); |
| 0577 | } |
| 0578 | } |
| 0579 | |
| 0580 | void DequeDeleteAtMiddle() |
| 0581 | { |
| 0582 | deque<TARGET_TYPE>::iterator iter; |
| 0583 | for (int i = 0; i < DELETE_NUM; i++) |
| 0584 | { |
| 0585 | iter = g_deque.begin(); |
| 0586 | for (unsigned int j = 0; j < g_deque.size() / 2; j++) ++iter; |
| 0587 | g_deque.erase(iter); |
| 0588 | } |
| 0589 | } |
| 0590 | |
| 0591 | |
| 0592 | |
| 0593 | |
| 0594 | void calctime(FUNC f, string msg) |
| 0595 | { |
| 0596 | __int64 t1; |
| 0597 | |
| 0598 | if (f != NULL) |
| 0599 | { |
| 0600 | t1 = GetTick(); |
| 0601 | (*f)(); |
| 0602 | // cerr << msg << GetSecond(t1) << endl; |
| 0603 | cout << GetSecond(t1) << ", "; |
| 0604 | } |
| 0605 | else |
| 0606 | { |
| 0607 | // cerr << msg << "N/A" << endl; |
| 0608 | cout << "N/A, "; |
| 0609 | } |
| 0610 | } |
| 0611 | |
| 0612 | __int64 GetPerSecondTick() |
| 0613 | { |
| 0614 | __int64 t1; |
| 0615 | |
| 0616 | t1 = GetTick(); |
| 0617 | Sleep(1000); |
| 0618 | return (GetTick() - t1); |
| 0619 | } |
| 0620 | |
| 0621 | double GetSecond(__int64 beginTick) |
| 0622 | { |
| 0623 | return (double)(GetTick() - beginTick) / (double)g_second; |
| 0624 | } |
| 0625 | |
| 0626 | void AddOneBySelf(TARGET_TYPE& tt) |
| 0627 | { |
| 0628 | ++tt; |
| 0629 | } |
| 0630 | |
| 0631 | void SubOneBySelf(TARGET_TYPE& tt) |
| 0632 | { |
| 0633 | --tt; |
| 0634 | } |
| 0635 | |
| 0636 | void DebugOut(string str) |
| 0637 | { |
| 0638 | cerr << str << endl; |
| 0639 | } |
| 0640 | |
| 0641 | |
| 0642 | int main(char** argv, int argc) |
| 0643 | { |
| 0644 | // 初期化 |
| 0645 | init(); |
| 0646 | |
| 0647 | // 実行開始 |
| 0648 | start(); |
| 0649 | |
| 0650 | // チェック |
| 0651 | check(); |
| 0652 | |
| 0653 | // 資源回収 |
| 0654 | uninit(); |
| 0655 | |
| 0656 | // クリア |
| 0657 | clear(); |
| 0658 | |
| 0659 | return 0; |
| 0660 | } |
| 0661 |
本文对比了C++ STL中的vector、list和deque三种容器在不同操作下的性能表现,包括初始化、遍历、随机访问等,并给出了实际使用建议。
1564

被折叠的 条评论
为什么被折叠?



