热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

std::map排序的原理

今天被同事问到一个问题,map中第三个参数的意思是什么,于是写了下面这个程序测试了一下。#include<map>#include<iostream>usingname
 

今天被同事问到一个问题,map中第三个参数的意思是什么,于是写了下面这个程序测试了一下。

#include 
#include
using namespace std;

typedef map icMap;
typedef map::iterator It;

class func
{
public:
func(){};
bool operator ()( const int i1, const int i2 )
{
return i1>i2;
}
};

typedef map icMapCmp;
typedef map::iterator It1;

int main(void)
{
icMap m;
m.insert(make_pair(1,'1'));
m.insert(make_pair(3,'3'));
m.insert(make_pair(2,'2'));

for (It it = m.begin();it!=m.end();++it)
{
cout<first<<"\t"<second<}

icMapCmp c;
c.insert(make_pair(1,'1'));
c.insert(make_pair(3,'3'));
c.insert(make_pair(2,'2'));
for (It1 it1 = c.begin();it1!=c.end();++it1)
{
cout<first<<"\t"<second<}

return 0;
}


 

第三个参数MSDN的解释如下:

Traits

The type that provides a function object that can compare two element values as sort keys to determine their relative order in the map. This argument is optional and the binary predicate less is the default value.

MSDN上说的已经很清楚了,缺省的是 std::less

看stl_map.h中看map的定义:

 template ,

            typename _Alloc = std::allocator > >

class map

缺省的compare确实是std::less,std::less。在stl_function.h中std::less的实现如下:

 template 
struct less : public binary_function<_Tp, _Tp, bool>
{
bool
operator()(const _Tp& __x, const _Tp& __y) const
{ return __x <__y; }
};


 

return __x <__y;原来如此。但是这仅仅是比较函数,比较了之后map又是如何处理的呢?好像还是没有找到根源。

那就继续追踪,map的构造函数:

      map()

      : _M_t(_Compare(), allocator_type()) { }

用_Compare()初始化了_M_t,那就继续追踪_M_t,追踪到了map内部的红黑树。

      typedef _Rb_tree,

                     key_compare, _Pair_alloc_type> _Rep_type;

 

      /// @if maint  The actual tree structure.  @endif

      _Rep_type _M_t;

最后到了insert_unique函数中:

 template           typename _Compare, typename _Alloc>
pair _Compare, _Alloc>::iterator, bool>
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
insert_unique(const _Val& __v)
{
_Link_type __x = _M_begin();
_Link_type __y = _M_end();
bool __comp = true;
while (__x != 0)
{
__y = __x;
__comp = _M_impl._M_key_compare(_KeyOfValue()(__v), _S_key(__x));
__x = __comp ? _S_left(__x) : _S_right(__x);
}
iterator __j = iterator(__y);
if (__comp)
if (__j == begin())
return pair(_M_insert(__x, __y, __v), true);
else
--__j;
if (_M_impl._M_key_compare(_S_key(__j._M_node), _KeyOfValue()(__v)))
return pair(_M_insert(__x, __y, __v), true);
return pair(__j, false);
}


 

函数前面的返回值类型定义有点复杂,其实就是返回pair的pair,然后根据要插入的值__v来比较,如果是真,就往左边找,否则就往右边找。

 template           typename _Compare, typename _Alloc>
typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
_M_insert(_Base_ptr __x, _Base_ptr __p, const _Val& __v)
{
bool __insert_left = (__x != 0 || __p == _M_end()
|| _M_impl._M_key_compare(_KeyOfValue()(__v),
_S_key(__p)));

_Link_type __z = _M_create_node(__v);

_Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
this->_M_impl._M_header);
++_M_impl._M_node_count;
return iterator(__z);
}


找到位置之后,创建节点,然后插入到二叉平衡树(也就是红黑树)中。

哈哈哈,_Rb_tree_insert_and_rebalance找不到代码。居然在STLPort里面找到了下面的代码。微笑

template           class _Compare, class _Alloc> __iterator__ 
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc> ::_M_insert(_Rb_tree_node_base* __x_, _Rb_tree_node_base* __y_, const _Value& __v,
_Rb_tree_node_base* __w_)
{
_Link_type __w = (_Link_type) __w_;
_Link_type __x = (_Link_type) __x_;
_Link_type __y = (_Link_type) __y_;
_Link_type __z;

if ( __y == this->_M_header._M_data ||
( __w == 0 && // If w != 0, the remainder fails to false
( __x != 0 || // If x != 0, the remainder succeeds to true
_M_key_compare( _KeyOfValue()(__v), _S_key(__y) ) )
)
) {

__z = _M_create_node(__v);
_S_left(__y) = __z; // also makes _M_leftmost() = __z
// when __y == _M_header
if (__y == this->_M_header._M_data) {
_M_root() = __z;
_M_rightmost() = __z;
}
else if (__y == _M_leftmost())
_M_leftmost() = __z; // maintain _M_leftmost() pointing to min node
}
else {
__z = _M_create_node(__v);
_S_right(__y) = __z;
if (__y == _M_rightmost())
_M_rightmost() = __z; // maintain _M_rightmost() pointing to max node
}
_S_parent(__z) = __y;
_S_left(__z) = 0;
_S_right(__z) = 0;
_Rb_global_inst::_Rebalance(__z, this->_M_header._M_data->_M_parent);
++_M_node_count;
return iterator(__z);
}


 

 

 

 


推荐阅读
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了brain的意思、读音、翻译、用法、发音、词组、同反义词等内容,以及脑新东方在线英语词典的相关信息。还包括了brain的词汇搭配、形容词和名词的用法,以及与brain相关的短语和词组。此外,还介绍了与brain相关的医学术语和智囊团等相关内容。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文讨论了在使用Git进行版本控制时,如何提供类似CVS中自动增加版本号的功能。作者介绍了Git中的其他版本表示方式,如git describe命令,并提供了使用这些表示方式来确定文件更新情况的示例。此外,文章还介绍了启用$Id:$功能的方法,并讨论了一些开发者在使用Git时的需求和使用场景。 ... [详细]
author-avatar
小爬虫
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有