C++的STL库,vector sort排序时间复杂度 及常见容器比较

2023-11-16

http://www.cnblogs.com/sthv/p/5511921.html


http://www.169it.com/article/3215620760.html

http://www.cnblogs.com/sharpfeng/archive/2012/09/18/2691096.html

在C++的STL库中,要实现排序可以 通过将所有元素保存到vector中,然后通过sort算法来排序,也可以通过multimap实现在插入元素的时候进行排序。在通过 vector+sort进行排序时,所有元素需要先存入vector容器中,sort在排序时又需要将元素全部取出来再进行排序。multimap底层实 现为红黑树,因此元素在插入的过程中就实现了排序。那么到底哪一种排序速度更快呢?

   下面有一个测试程序:

   

#include <vector>
#include <set>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
using  namespace  std;
double  time () {
   struct  timeval tv;
   if  (gettimeofday(&tv, NULL) != 0)  return  0.0;
   return  tv.tv_sec + tv.tv_usec / 1000000.0;
}
struct  Score {
   string name;
   double  score;
   bool  operator <( const  Score& right)  const  {
     return  score < right.score;
   }
};
int  main( int  argc,  char ** argv) {
   vector<Score> src;
   for  ( int  i = 0; i < 10000000; i++) {
     int  num =  rand ();
     char  buf[32];
     sprintf (buf,  "%d" , num);
     Score score = { buf, num };
     src.push_back(score);
   }
   {
     double  stime =  time ();
     vector<Score> res;
     for  (vector<Score>::const_iterator it = src.begin();
          it != src.end(); ++it) {
       res.push_back(*it);
     }
     sort(res.begin(), res.end());
     double  etime =  time ();
     printf ( "vector: %f\n" , etime - stime);
   }
   {
     double  stime =  time ();
     multiset<Score> res;
     for  (vector<Score>::const_iterator it = src.begin();
          it != src.end(); ++it) {
       res.insert(*it);
     }
     double  etime =  time ();
     printf ( "multiset: %f\n" , etime - stime);
   }
   return  0;
}

程序运行结果为:

          time
vector   4.776060
multiset 10.761023

在这个测试中,vector+sort排序比multiset(multimap实现基于multiset)快多了。快速排序是目前已知的所有排序算法中最快的排序算法,因此它比基于堆排序的multiset快。

 在这个测试结果出来之前,大多数人都会毫无疑问地认为multiset排序要更快。这也是有原因的,快速排序速度虽然快,但是在实际的运行过程中,它需 要大量地拷贝元素,其拷贝操作的时间复杂度为o(NlogN),而基于红黑树的multiset在排序的过程中则避免了元素的拷贝。如果元素的内存占用空 间比较大,那么multiset排序的速度将比vector+sort快。为了测试这个结果,将上面测试程序中的结构体改为:

struct  Score {
   string name1;
   string name2;
   string name3;
   string name4;
   double  score;
   bool  operator <( const  Score& right)  const  {
     return  score < right.score;
   }
};

然后重新编译运行测试程序,测试结果为:

          time
vector   12.955739
multiset 11.368364

这个测试结果和我们的预期一致。

  总之,我们在使用STL的排序算法时,需要根据不同的元素构造来进行合适的选择,如果都是比较简单的元素,那么适合选择vector+sort来进行排 序,对于由字符串构成的占用了比较大的空间的复杂元素,应该使用multiset。如果排序的元素的总个数比较少,那么选择任意一种都可以。

 

 

 

 

list支持快速的插入和删除,但是查找费时;

 

vector支持快速的查找,但是插入费时。

 

map查找的时间复杂度是对数的,这几乎是最快的,hash也是对数的。 
如果我自己写,我也会用二叉检索树,它在大部分情况下可以保证对数复杂度,最坏情况是常数复杂度,而std::map在任何情况下都可以保证对数复杂度,原因是它保证存诸结构是完全二叉检索树,但这会在存诸上牺牲一些时间。

 

STL   中的   map   内部是平衡二叉树,所以平衡二叉树的性质都具备。查找数据的时间也是对数时间。vector,在分配内存上一般要比   new   高效的多。

 

为什么说   hash_map   是对数级的?在不碰撞的情况下,hash_map是所有数据结构中查找最快的,它是常数级的。 
如果对问题设计了足够好的hash算法,保证碰撞率很低,hash_map的查找效率无可置疑。 
另外,STL的map,它的查找是对数级的,是除hash_map外最高的了,你可以说“也许还有改进余地”,但对于99.9999%的程序员,设计一个比STL   map好的map,我执悲观态度。 
STL的map有平衡策略(比如红黑树什么的),所以不会退化,不需要考虑数据本身的分布问题。只不过,如果数据本身是排好序的,用vector或heap会明显的快些,因为它们的访问比较简单。

 

 

 

我 想没必要怀疑stl::map的查找效率,影响效率最主要的因素是什么?算法,在查找问题上,有什么算法比RB_tree更好吗?至少现在还没有。不否 认你可以通过自己写代码,设计一个符合你需要的BR—TREE,比stl::map简捷那么一点,但最多也就每次迭代中少一行指令而已,处理十万个数据多 执行十万行指令,这对你重要吗?如果你不是在设计OS像LINUX,没人会关注这十万行指令花的时间。 
rb-tree的时间花在了插入和删除上,如果你不是对插入和删除效率要求很高,你没有理由不选择基于rb-tree的stl::map。

 

 

 

大多数程序员写不出比std::map更好的map,这是当然的。然而并不是std::map的所有特性都出现在我们的程序中,自己编写的可以更适合自己的程序,的确会比std::map更快一些。

 

 

 

关于hash_map,它与map的实现机制是不一样的,map内部一般用树来实现,其查找操作是O(logN)的,这个没有争议,我就不多说了。 
hash_map 的查找,内部是通过一个从key到value的运算函数来实现的,这个函数“只接受key作为参数”,也就是说,hash_map的查找 算法与数据量无关,所以认为它是O(1)级的。来这里的应该都是达人,可以参看《数据结构》。当然,事实总不这样完美,再引一段前面我自已说的话,进一步 说明,以免误会:

 

----------------------------------------- 
在不碰撞的情况下,hash_map是所有数据结构中查找最快的,它是常数级的。 
------------------------------------------ 
注意我的前提:“在不碰撞的情况下”,其实换句话说,就是要有足够好的hash函数,它要能使key到value的映射足够均匀,否则,在最坏的情况下,它的计算量就退化到O(N)级,变成和链表一样。 
如果说   hash_map   是所有容器中最慢的,也只能说:“最拙劣的hash函数”会使hash_map成为查找最慢的容器。但这样说意义不大,因为,最凑巧的排列能使冒泡排序成为最快的排序算法。

 

BS: "对于大型容器而言,hash_map能够提供比map快5至10倍的元素查找速度是很常见的,尤其是在查找速度特别重要的地方.另一方面,如果hash_map选择了病态的散列函数,他也可能比map慢得多. "

 

ANSIC++在1998年之后就没再有重大改变,并且决定不再向C++标准库中做任何重大的变更,正是这个原因,hash   table(包括hash_map)并没有被列入标准之中,虽然它理应在C++标准之中占有一席之地。 
虽然,现在的大多数编译平台支持hash   table,但从可移植性方面考虑,还是不用hash   table的好。

 

 

 

hehe俺也来凑凑热闹。 
1.有的时候vector可以替代map 
比如key是整数,就可以以key的跨度作为长度来定义vector。 
数据规模很大的时候,差异是惊人的。当然,空间浪费往往也惊人。 
2.hash是很难的东西 
没有高效低碰撞的算法,hash_xxx没有意义。 
而对不同的类型,数据集,不可能有优良的神仙算法。必须因场合而宜。 
俺有的解决方法是GP,可不是饭型,是遗传编程,收效不错。

 

 

 

你的百万级的数据放到vector不大合适。因为vector需要连续的内存空间,显然在初始化这个容器的时候会花费很大的容量。 
使用map,你想好了要为其建立一个主键吗?如果没有这样的需求,为什么不考虑deque或者list? 
map默认使用的是deque作为容器。其实map不是容器,拿它与容器比较意义不大。因为你可以配置它的底层容器类型。

 

 

 

如果内存不是考虑的问题。用vector比map好。map每插入一个数据,都要排序一次。所以速度反不及先安插所有元素,再进行排序。

 

用 binary_search对已序区间搜索,如果是随机存取iterator,则是对数复杂度。可见,在不考虑内存问题的情况下,vector比map 好。

 

 

 

如果你需要在数据中间进行插入,list 是最好的选择,vector   的插入效率会让你痛苦得想死。

 

 

 

涉及到查找的话用map比较好,因为map的内部数据结构用rb-tree实现,而用vector你只能用线性查找,效率很低。

 

stl还提供了 hash容器,理论上查找是飞快~~~。做有序插入的话vector是噩梦,map则保证肯定是按key排序的,list要自己做些事情。

 

 

 

HASH类型的查找肯定快,是映射关系嘛,但是插入和删除却慢,要做移动操作, LIST类型的使链式关系,插入非常快,但是查找却费时,需要遍历~~ , 还是用LIST类型的吧,虽然查找慢点,

 

先快速排序,然后二分查找,效率也不低


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++的STL库,vector sort排序时间复杂度 及常见容器比较 的相关文章

  • EF Core Group By 翻译支持条件总和

    听说 EF Core 2 1 将支持翻译小组 我感到非常兴奋 我下载了预览版并开始测试它 但发现我在很多地方仍然没有得到翻译分组 在下面的代码片段中 对 TotalFlagCases 的查询将阻止翻译分组工作 无论如何 我可以重写这个以便我
  • 通过 CMIS (dotCMIS) 连接到 SP2010:异常未经授权

    我正在使用 dotCMIS 并且想要简单连接到我的 SP2010 服务器 我尝试用 C 来做到这一点 如下所示http chemistry apache org dotnet getting started with dotcmis htm
  • “构建”构建我的项目,“构建解决方案”则不构建

    我刚刚开始使用VS2010 我有一个较大的解决方案 已从 VS2008 成功迁移 我已将一个名为 Test 的控制台应用程序项目添加到解决方案中 选择构建 gt 构建解决方案不编译新项目 选择构建 gt 构建测试确实构建了项目 在失败的情况
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • 在 Windows 窗体中保存带有 Alpha 通道的单色位图会保存不同(错误)的颜色

    在 C NET 2 0 Windows 窗体 Visual Studio Express 2010 中 我保存由相同颜色组成的图像 Bitmap bitmap new Bitmap width height PixelFormat Form
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new
  • 如何防止用户控件表单在 C# 中处理键盘输入(箭头键)

    我的用户控件包含其他可以选择的控件 我想实现使用箭头键导航子控件的方法 问题是家长控制拦截箭头键并使用它来滚动其视图什么是我想避免的事情 我想自己解决控制内容的导航问题 我如何控制由箭头键引起的标准行为 提前致谢 MTH 这通常是通过重写

随机推荐

  • 这十个步骤让你的 App 避规ios 4.3被拒问题

    4 3 垃圾应用 请不要为同一个 App 创建多个套装 ID 如果您的 App 针对特定位置 运动队 大学等存在不同版本 请考虑提交单个 App 并提供 App 内购买以提供差异功能 同时 请避免继续在已有大量类似 App 的类别下进行开发
  • kubectl应用

    文章目录 kubectl用法概述 kubectl输出格式 kubectl操作示例 kubectl用法概述 kubectl命令语法 kubectl command TYPE NAME flags 其中 command TYPE NAME fl
  • 如何计算内存大小

    对电子产品 存储介质厂家来说 是按进率1000来计量的 即1000B 1KB 1000KB 1MB 1000MB 1GB 也就是为什么硬盘分区后 会造成缩水 比如80G硬盘实际等于76G 的原因 因为系统是按1024进率来进行分区的 注 我
  • 多文件编程

    文章目录 什么是多文件编程 lt gt 与 多文件编程方法 变量重复定义与头文件重复包含 变量重复定义 头文件重复包含 为什么要避免重复包含 如何解决 1 ifndef 2 pragma once 小总结 什么是多文件编程 多文件编程 指的
  • vite postcss

    PostCSS PostCSS是一款使用JavaScript插件对CSS实现转换的工具 PostCSS拥有非常强大的插件 典型的比如autoprefixer cssnext css modules等 PostCSS插件的处理方式类似CSS预
  • CSS:基本选择器中的ID选择器和class选择器的区别

    ID选择器 通过标签的id名称来选择标签 id 类选择器 class选择器 选择一个类别 className 区别 1 ID 选择器的是以井号 开头来定义的 类 选择器是以点 来定义的 2 ID 选择器在 HTML 中是可以通过 id 属性
  • 2_Nginx 语法

    文章目录 一些说明 配置静态资源服务器 常用指令 一些说明 指令 指令块 指令以分号结尾 一条指令可以有一个或多个参数 参数之间以空格分隔 例如 server name 指令块可以有名字或者没有名字 include 允许组合多个配置文件 以
  • 面经(一)广州保伦电子有限公司校招宣讲面经

    前言 本章主要讲述我曾参加广州保伦有限公司的学校宣讲并笔试的经历 一 经历概述 宣讲前 在得知该公司会来我们学校进行宣讲时 我看到有招聘Java开发职位 就马上决定参加该公司的宣讲 因为我们学校是最后一次宣讲的地方 自己心里也知道人肯定是招
  • Design Compiler (七)——环境、设计规则和面积约束

    本文如果有错 欢迎留言更正 此外 转载请标明出处 http www cnblogs com IClearner 作者 IC learner 本文的主要内容是讲解 约束针对的是逻辑综合下的约束 而实战部分则是在DC的拓扑模式下进行 环境属性的
  • image not loaded  try to open it externally to fix format problem

    image not loaded try to open it externally to fix format problem 图片没有加载 请从外部打开图片以解决格式问题 由于项目是直接复制过来的 图片从外部打开显示为空 直接全部替换重
  • 编码规范(三)----静态分析工具PMD

    一 简介 1 1 什么是静态代码分析 静态代码分析是指无需运行被测代码 仅通过分析或检查源程序的语法 结构 过程 接口等来检查程序的正确性 找出代码隐藏的错误和缺陷 如参数不匹配 有歧义的嵌套语句 错误的递归 非法计算 可能出现的空指针引用
  • 形象的理解TCP协议为什么要“三次握手”

    我们先来看看专业的解读是怎么简单描述 三次握手 的 以下图片来自百度百科 如果你看完一脸懵圈 不妨想想三次握手的目的 那就是确保客户端和服务器能够正常通讯 当然 本文只是从非专业的角度解释为何TCP建立连接的三次握手就能保证正常通讯 为何不
  • Java创建对象数组出现空指针报错

    public static void main String args teacher d new teacher 2 System out println d 0 其中创建的数组d的内存状态为空 输出数组d其中一个元素是null 即使随便
  • 你了解模糊测试(fuzz testing)吗?

    模糊测试 fuzz testing 是一类安全性测试的方法 说起安全性测试 大部分人头脑中浮现出的可能是一个标准的 黑客 场景 某个不修边幅 脸色苍白的年轻人 坐在黑暗的房间中 正在熟练地使用各种工具尝试进入某个系统 这种由安全人员 模拟黑
  • 图像&视频编辑工具箱MMEditing使用示例:图像超分辨率(super-resolution)

    MMEditing的介绍及安装参考 https blog csdn net fengbingchun article details 126331541 这里给出图像超分的测试代码 论文 Learning Continuous Image
  • go 流媒体服务搭建-01

    这里写自定义目录标题 go 流媒体服务搭建 01 go 流媒体服务搭建 01 新建go 项目 配置go 版本1 19 新增main go package main func main 新增go mod 文件 go mod init mym7
  • C语言之路---三大结构

    目录 1 选择结构 1 1 if else语句 1 2 switch case 语句 1 3 条件运算符 2 循环结构 2 1 whi
  • 直接修改数据库表数据

    直接修改数据库表中的数据 1 写SQL语句 select from 表名 for update 如下图所示 写好SQL后点击执行按钮或者直接按F8 2 执行完SQL后选择行上的按钮 让行信息变成可编辑状态 如下图所示 3 可按增加或者删除一
  • lambda qt 参数 槽函数_Qt界面开发(3)

    参考 QT界面开发 哔哩哔哩 干杯 bilibili www bilibili com 接 juliar Qt界面开发 1 juliar Qt界面开发 2 一 带参数的信号 前面关于信号signal 我们了解到 signals是Qt扩展的关
  • C++的STL库,vector sort排序时间复杂度 及常见容器比较

    http www cnblogs com sthv p 5511921 html http www 169it com article 3215620760 html http www cnblogs com sharpfeng archi