一、数据结构:hash_map原理 

hash_map基于hash table(哈希表)。哈希表最大的长处,就是把数据的存储和查找消耗的时间大大减少,差点儿能够看成是常数时间;而代价不过消耗比較多的内存。然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。另外,编码比較easy也是它的特点之中的一个。 



其基本原理是:使用一个下标范围比較大的数组来存储元素。能够设计一个函数(哈希函数,也叫做散列函数)。使得每个元素的keyword都与一个函数值(即数组下标。hash值)相相应,于是用这个数组单元来存储这个元素;也能够简单的理解为。依照keyword为每个元素“分类”,然后将这个元素存储在相应“类”所相应的地方。称为桶。

可是,不可以保证每一个元素的keyword与函数值是一一相应的。因此极有可能出现对于不同的元素,却计算出了同样的函数值。这样就产生了“冲突”,换句话说,就是把不同的元素分在了同样的“类”之中。 总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。 



hash_map。首先分配一大片内存,形成很多桶。是利用hash函数,对key进行映射到不同区域(桶)进行保存。

其插入过程是: 



   1. 得到key 

   2. 通过hash函数得到hash值 

   3. 得到桶号(一般都为hash值对桶数求模) 

   4. 存放key和value在桶内。 



其取值过程是: 



   1. 得到key 

   2. 通过hash函数得到hash值 

   3. 得到桶号(一般都为hash值对桶数求模) 

   4. 比較桶的内部元素是否与key相等,若都不相等,则没有找到。 

   5. 取出相等的记录的value。

hash_map中直接地址用hash函数生成,解决冲突,用比較函数解决。这里能够看出,假设每一个桶内部仅仅有一个元素,那么查找的时候仅仅有一次比較。当很多桶内没有值时。很多查询就会更快了(指查不到的时候). 



由此可见,要实现哈希表, 和用户相关的是:hash函数(hashcode)和比較函数(equals)。

假定哈希函数将元素正确分布在各桶之间,可为基本操作(get
和 put)提供稳定的性能。

迭代集合视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)的和成比例。

所以,假设迭代性能非常重要。则不要将初始容量设置得太高(或将载入因子设置得太低)。

HashMap 的实例有两个參数影响其性能:初始容量 和载入因子容量 是哈希表中桶的数量,初始容量仅仅是哈希表在创建时的容量。

载入因子 是哈希表在其容量自己主动添加之前能够达到多满的一种尺度。当哈希表中的条目数超出了载入因子与当前容量的乘积时,通过调用
rehash 方法将容量翻倍。 通常,默认载入因子 (.75) 在时间和空间成本上寻求一种折衷。载入因子过高尽管降低了空间开销,但同一时候也添加了查询成本(在大多数 HashMap 类的操作中,包含 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其载入因子,以便最大限度地降低 rehash 操作次数。假设初始容量大于最大条目数除以载入因子,则不会发生 rehash 操作。
假设非常多映射关系要存储在 HashMap 实例中,则相对于按需运行自己主动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。

注意,此实现不是同步的。

假设多个线程同一时候訪问此映射。而当中至少一个线程从结构上改动了该映射,则它必须 保持外部同步。

(结构上的改动是指加入或删除一个或多个映射关系的操作。仅改变与实例已经包括的键关联的值不是结构上的改动。)这一般通过对自然封装该映射的对象进行同步操作来完毕。假设不存在这种对象,则应该使用
Collections.synchronizedMap 方法来“包装”该映射。

最好在创建时完毕这一操作。以防止对映射进行意外的不同步訪问。例如以下所看到的: Map m = Collections.synchronizedMap(new HashMap(...));

今天在使用STL中的hash_map模板遇到使用PTCHAR作为Key时无法对字符串进行正确比較的问题。在网上查找对应的文章可惜没有找到,但找到了http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailHashMaphttp://www.cppblog.com/guojingjia2006/archive/2008/01/12/41037.aspx两篇文章对解决我的问题帮了大忙,特将其内容贴出。

hash_map类在头文件hash_map中,和全部其他的C++标准库一样,头文件没有扩展名。

例如以下声明:

#include <hash_map>

          using namespace std;

          using namespace stdext;

hash_map是一个聚合类,它继承自_Hash类,包含一个vector,一个list和一个pair,当中vector用于保存桶。list用于进行冲突处理。pair用于保存key->value结构,简要地伪码例如以下:

class hash_map<class _Tkey, class _Tval>

          {

          private:

               typedef pair<_Tkey, _Tval> hash_pair;

               typedef list<hash_pair>    hash_list;

               typedef vector<hash_list>  hash_table;

          };

当然,这仅仅是一个简单模型,C++标准库的泛型模版一向以嵌套复杂而闻名。初学时看类库,无疑天书啊。微软的hash_map类还聚合了hash_compare仿函数类,hash_compare类里有聚合了less仿函数类。乱七八糟的。

以下说说用法:

一、简单变量作为索引:整形、实性、指针型

     事实上指针型也就是整形,算法一样。

可是hash_map会对char*, const char*, wchar_t*, const wchar_t*做特殊处理。

     这样的情况最简单。以下代码是整形演示样例:

            hash_map<int, int> IntHash;

            IntHash[1] = 123;

            IntHash[2] = 456;

int val = IntHash[1];

            int val = IntHash[2];

     实型和指针型使用方法和整形一样,原理例如以下:

     1、使用简单类型作索引声明hash_map的时候,不须要声明模版的后两个參数(最后一个參数指名hash_map节点的存储方式,默觉得pair,我觉得这就挺好。不是必需改动)。使用默认值就好。

2、对于除过字符串的其他简单类型,hash_map使用模版函数 size_t hash_value(const _Kty& _Keyval) 计算hash值,计算方法是经典的掩码异或法,自己主动溢出得到索引hash值。

微软的project师或许开了一个玩笑,这个掩码被定义为0xdeadbeef(死牛肉,抑或是某个程序猿的绰号)。

3、对于字符串指针作索引的时候,使用定类型函数inline size_t hash_value(const char *_Str)或inline size_t hash_value(const wchar_t *_Str)计算hash值。计算方法是取出每个字符求和。自己主动溢出得到hash值。

对于字符串型的hash索引。要注意须要自己定义less仿函数。

     由于我们有理由觉得。人们使用hash表进行高速查找的预期成本要比在hash表中插入的预期成本低得多。所以插入可以比查找昂贵些;基于这个如果,hash_map在有冲突时,插入链表是进行排序插入的。这样在进行查询冲突解决的时候就行更快捷的找到须要的索引。

     可是,基于泛型编程的原则,hash_map也有理由觉得每一种类型都支持使用"<"来判别两个类型值的大小,这样的设计恰好让字符串类型无所适从,众所周知。两个字符串指针的大小并不代表字符串值的大小。

见例如以下代码:

          hash_map<const char*, int> CharHash;

          CharHash["a"] = 123;

          CharHash["b"] = 456;

char szInput[64] = "";

          scanf("%s", szInput);

int val = CharHash[szInput];

终于的结果就是不管输入不论什么字符串,都无法找到相应的整数值。由于输入的字符串指针是szInput指针。和"a"或"b"字符串常量指针的大小是绝对不会同样。解决方法例如以下:

     首先写一个仿函数CharLess。继承自仿函数基类binary_function(当然也能够不继承。这样写仅仅是符合标准,并且写起来比較方便,不用被类似于指针的指针和指针的引用搞晕。

struct CharLess : public binary_function<const char*, const char*, bool>

          {

          public:

               result_type operator()(const first_argument_type& _Left, const second_argument_type& _Right) const

               {

                    return(stricmp(_Left, _Right) < 0 ?

true : false);

               }

          };

非常好,有了这个仿函数,就能够正确的使用字符串指针型hash_map了。例如以下:

hash_map<const char*, int, hash_compare<const char*, CharLess> > CharHash;

          CharHash["a"] = 123;

          CharHash["b"] = 456;

char szInput[64] = "";

          scanf("%s", szInput);

int val = CharHash[szInput];

      

     如今就能够正常工作了。至此,简单类型的用法介绍完成。

二、用户自己定义类型:比方对象类型,结构体。

这样的情况比价复杂。我们先说简单的,对于C++标准库的string类。

庆幸的是。微软为basic_string(string类的基类)提供了hash方法,这使得使用string对象做索引简单了很多。

值得注意(也值得郁闷)的是。尽管支持string的hash,string类却没有重载比較运算符。所以标准的hash_compare仿函数依然无法工作。

我们继续重写less仿函数。

struct string_less : public binary_function<const string, const string, bool>

          { 

          public: 

               result_type operator()(const first_argument_type& _Left, const second_argument_type& _Right) const 

               { 

                    return(_Left.compare(_Right) < 0 ? true : fase); 

               } 

          };

            

     好了,我们能够书写例如以下代码:

            

          hash_map<string, int, hash_compare<string, string_less> > StringHash;

          StringHash["a"] = 123;

          StringHash["b"] = 456;

string strKey = "a";

int val = CharHash[strKey];

      

     这样就能够了。

      

     对于另外的一个经常使用的字符串类CString(我觉得微软的CString比标准库的string设计要洒脱一些)更加复杂一些。非常显然,标准库里不包括对于CString的支持,但CString却重载了比較运算符(郁闷)。我们必须重写hash_compare仿函数。值得一提的是。在Virtual Stdio 2003中。CString不再是MFC的成员。而成为ATL的成员,使用#include <atlstr.h>就能够使用。

我没有採用重写hash_compare仿函数的策略,而不过继承了它。在模版库中的继承是没有性能损耗的,并且能让我偷一点懒。 

     首先重写一个hash_value函数:

      

          inline size_t CString_hash_value(const CString& str) 

          { 

               size_t value = _HASH_SEED; 

               size_t size  = str.GetLength(); 

               if (size > 0) { 

                    size_t temp = (size / 16) + 1; 

                    size -= temp; 

                    for (size_t idx = 0; idx <= size; idx += temp) { 

                         value += (size_t)str[(int)idx]; 

                    } 

               } 

               return(value); 

          }

      

     其次重写hash_compare仿函数:

      

          class CString_hash_compare : public hash_compare<CString> 

          { 

          public: 

               size_t operator()(const CString& _Key) const 

               { 

                    return((size_t)CString_hash_value(_Key));

               }

   

               bool operator()(const CString& _Keyval1, const CString& _Keyval2) const 

               { 

                    return (comp(_Keyval1, _Keyval2)); 

               } 

          };

            

     上面的重载忽略了基类对于less仿函数的引入,由于CString具备比較运算符,我们能够使用默认的less仿函数,在这里映射为comp。

好了。我们能够声明新的hash_map对象例如以下:

hash_map<CString, int, CString_hash_compare> CStringHash;

其余的操作一样一样的。

下来就说说对于自己定义对象的用法:首先定义

      

          struct IHashable 

          { 

               virtual unsigned long hash_value() const = 0; 

               virtual bool operator < (const IHashable& val) const = 0; 

               virtual IHashable& operator = (const IHashable& val) = 0; 

          };

      

     让我们自写的类都派生自这里,有一个标准,接下来定义我们的类:

      

          class CTest : public IHashable 

          { 

          public: 

               int m_value; 

               CString m_message; 

          public: 

               CTest() : m_value(0) 

               { 

               }

            

               CTest(const CTest& obj) 

               { 

                    m_value = obj.m_value; 

                    m_message = obj.m_message; 

               } 

          public: 

               virtual IHashable& operator = (const IHashable& val) 

               { 

                    m_value   = ((CTest&)val).m_value; 

                    m_message = ((CTest&)val).m_message; 

                    return(*this); 

               }

            

               virtual unsigned long hash_value() const

               {

                    // 这里使用类中的m_value域计算hash值。也能够使用更复杂的函数计算全部域总的hash值

                    return(m_value ^ 0xdeadbeef  

               }

            

               virtual bool operator < (const IHashable& val) const 

               { 

                    return(m_value < ((CTest&)val).m_value); 

               } 

          };

      

     用这个类的对象做为hash索引准备工作例如以下。由于接口中规定了比較运算符,所以这里能够使用标准的less仿函数。所以这里忽略:

      

          template<class _Tkey> 

          class MyHashCompare : public hash_compare<_Tkey> 

          { 

          public: 

               size_t operator()(const _Tkey& _Key) const 

               { 

                    return(_Key.hash_value()); 

               }

            

               bool operator()(const _Tkey& _Keyval1, const _Tkey& _Keyval2) const 

               { 

                    return (comp(_Keyval1, _Keyval2)); 

               } 

          };

            

     下来就这样写:

      

          CTest test; 

          test.m_value = 123; 

          test.m_message = "This is a test";

      

          MyHash[test] = 2005;

            

          int val = MyHash[test];

      

     能够看到正确的数字被返回。

三、关于hash_map的思考:

      

     1、性能分析:採用了内联代码和模版技术的hash_map在效率上应该是很优秀的,但我们还须要注意例如以下几点:

      

     * 经过查看代码。字符串索引会比简单类型索引速度慢,自己定义类型索引的性能则和我们选择hash的内容有非常大关系,简单为主。这是使用hash_map的基本原则。 

     * 能够通过重写hash_compair仿函数。更改里面关于桶数量的定义。假设取值合适,也能够得到更优的性能。

假设桶数量大于10。则牢记它应该是一个质数。 

     * 在自己定义类型是。重载的等号(或者拷贝构造)有可能成为性能瓶颈。使用对象指针最为索引将是一个好的想法。但这就必须重写less仿函数,理由同使用字符串指针作为索引。

hash_map类在头文件hash_map中,和全部其他的C++标准库一样。头文件没有扩展名。例如以下声明:

  1. #include <hash_map>
  2. using namespace std;
  3. using namespace stdext;

hash_map是一个聚合类。它继承自_Hash类,包含一个vector,一个list和一个pair,当中vector用于保存桶,list用于进行冲突处理。pair用于保存key->value结构。简要地伪码例如以下:

  1. class hash_map<class _Tkey, class _Tval>
  2. {
  3. private:
  4. typedef pair<_Tkey, _Tval> hash_pair;
  5. typedef list<hash_pair>    hash_list;
  6. typedef vector<hash_list>  hash_table;
  7. };

当然。这仅仅是一个简单模型。C++标准库的泛型模版一向以嵌套复杂而闻名,初学时看类库,无疑天书啊。微软的hash_map类还聚合了hash_compare仿函数类,hash_compare类里又聚合了less仿函数类,乱七八糟的。

以下说说用法:

一、简单变量作为索引:整形、实性、指针型

     事实上指针型也就是整形,算法一样。可是hash_map会对char*, const char*, wchar_t*, const wchar_t*做特殊处理。

     这样的情况最简单。以下代码是整形演示样例:

  1. hash_map<int, int> IntHash;
  2. IntHash[1] = 123;
  3. IntHash[2] = 456;
  4. int val = IntHash[1];
  5. int val = IntHash[2];

实型和指针型使用方法和整形一样,原理例如以下:

     1、使用简单类型作索引声明hash_map的时候。不须要声明模版的后两个參数(最后一个參数指名hash_map节点的存储方式。默觉得pair。我觉得这就挺好。不是必需改动)。使用默认值就好。

     2、对于除过字符串的其他简单类型,hash_map使用模版函数 size_t hash_value(const _Kty& _Keyval) 计算hash值,计算方法是经典的掩码异或法,自己主动溢出得到索引hash值。微软的project师或许开了一个玩笑。这个掩码被定义为0xdeadbeef(死牛肉。抑或是某个程序猿的绰号)。

     3、对于字符串指针作索引的时候。使用定类型函数inline size_t hash_value(const char *_Str)或inline size_t hash_value(const wchar_t *_Str)计算hash值。计算方法是取出每个字符求和,自己主动溢出得到hash值。对于字符串型的hash索引,要注意须要自己定义less仿函数。

由于我们有理由觉得,人们使用hash表进行高速查找的预期成本要比在hash表中插入的预期成本低得多,所以插入可以比查找昂贵些;基于这个如果,hash_map在有冲突时,插入链表是进行排序插入的,这样在进行查询冲突解决的时候就行更快捷的找到须要的索引。

     可是,基于泛型编程的原则,hash_map也有理由觉得每一种类型都支持使用"<"来判别两个类型值的大小,这样的设计恰好让字符串类型无所适从,众所周知。两个字符串指针的大小并不代表字符串值的大小。

见例如以下代码:

  1. hash_map<const char*, int> CharHash;
  2. CharHash["a"] = 123;
  3. CharHash["b"] = 456;
  4. char szInput[64] = "";
  5. scanf("%s", szInput);
  6. int val = CharHash[szInput];

终于的结果就是不管输入不论什么字符串,都无法找到相应的整数值。由于输入的字符串指针是szInput指针。和"a"或"b"字符串常量指针的大小是绝对不会同样。

解决方法例如以下:

     首先写一个仿函数CharLess。继承自仿函数基类binary_function(当然也能够不继承,这样写仅仅是符合标准,并且写起来比較方便,不用被类似于指针的指针和指针的引用搞晕。

  1. struct CharLess : public binary_function<const char*, const char*, bool>
  2. {
  3. public:
  4. result_type operator()(const first_argument_type& _Left, const second_argument_type& _Right) const
  5. {
  6. return(stricmp(_Left, _Right) < 0 ? true : false);
  7. }
  8. };

非常好,有了这个仿函数。就能够正确的使用字符串指针型hash_map了。例如以下:

  1. hash_map<const char*, int, hash_compare<const char*, CharLess> > CharHash;
  2. CharHash["a"] = 123;
  3. CharHash["b"] = 456;
  4. char szInput[64] = "";
  5. scanf("%s", szInput);
  6. int val = CharHash[szInput];

如今就能够正常工作了。

至此。简单类型的用法介绍完成。

二、用户自己定义类型:比方对象类型。结构体。

这样的情况比价复杂,我们先说简单的,对于C++标准库的string类。

庆幸的是,微软为basic_string(string类的基类)提供了hash方法,这使得使用string对象做索引简单了很多。值得注意(也值得郁闷)的是。尽管支持string的hash,string类却没有重载比較运算符,所以标准的hash_compare仿函数依然无法工作。我们继续重写less仿函数。

          

[cpp] view
plain
copy

  1. struct string_less : public binary_function<const string, const string, bool>
  2. {
  3. public:
  4. result_type operator()(const first_argument_type& _Left, const second_argument_type& _Right) const
  5. {
  6. return(_Left.compare(_Right) < 0 ? true : fase);
  7. }
  8. };

好了,我们能够书写例如以下代码:

  1. hash_map<string, int, hash_compare<string, string_less> > StringHash;
  2. StringHash["a"] = 123;
  3. StringHash["b"] = 456;
  4. string strKey = "a";
  5. int val = CharHash[strKey];

这样就能够了。

      

     对于另外的一个经常使用的字符串类CString(我觉得微软的CString比标准库的string设计要洒脱一些)更加复杂一些。非常显然。标准库里不包括对于CString的支持。但CString却重载了比較运算符(郁闷)。我们必须重写hash_compare仿函数。值得一提的是。在Virtual Stdio 2003中,CString不再是MFC的成员,而成为ATL的成员。使用#include <atlstr.h>就能够使用。我没有採用重写hash_compare仿函数的策略,而不过继承了它,在模版库中的继承是没有性能损耗的,并且能让我偷一点懒。

     首先重写一个hash_value函数:

  1. inline size_t CString_hash_value(const CString& str)
  2. {
  3. size_t value = _HASH_SEED;
  4. size_t size  = str.GetLength();
  5. if (size > 0) {
  6. size_t temp = (size / 16) + 1;
  7. size -= temp;
  8. for (size_t idx = 0; idx <= size; idx += temp) {
  9. value += (size_t)str[(int)idx];
  10. }
  11. }
  12. return(value);
  13. }

其次重写hash_compare仿函数:

  1. class CString_hash_compare : public hash_compare<CString>
  2. {
  3. public:
  4. size_t operator()(const CString& _Key) const
  5. {
  6. return((size_t)CString_hash_value(_Key));
  7. }
  8. bool operator()(const CString& _Keyval1, const CString& _Keyval2) const
  9. {
  10. return (comp(_Keyval1, _Keyval2));
  11. }
  12. };

上面的重载忽略了基类对于less仿函数的引入。由于CString具备比較运算符。我们能够使用默认的less仿函数。在这里映射为comp。好了,我们能够声明新的hash_map对象例如以下:

  1. hash_map<CString, int, CString_hash_compare> CStringHash;

其余的操作一样一样的。

下来就说说对于自己定义对象的用法:首先定义

  1. struct IHashable
  2. virtual unsigned long hash_value() const = 0;
  3. virtual bool operator < (const IHashable& val) const = 0;
  4. virtual IHashable& operator = (const IHashable& val) = 0;
  5. ;

让我们自写的类都派生自这里,有一个标准,接下来定义我们的类:

  1. class CTest : public IHashable
  2. {
  3. public:
  4. int m_value;
  5. CString m_message;
  6. public:
  7. CTest() : m_value(0) {}
  8. CTest(const CTest& obj)
  9. {
  10. m_value = obj.m_value;
  11. m_message = obj.m_message;
  12. }
  13. public:
  14. virtual IHashable& operator = (const IHashable& val) {
  15. m_value   = ((CTest&)val).m_value;
  16. m_message = ((CTest&)val).m_message;
  17. return(*this);
  18. }
  19. virtual unsigned long hash_value() const {
  20. // 这里使用类中的m_value域计算hash值,也能够使用更复杂的函数计算全部域总的hash值
  21. return(m_value ^ 0xdeadbeef
  22. }
  23. virtual bool operator < (const IHashable& val) const {
  24. return(m_value < ((CTest&)val).m_value);
  25. }
  26. };

用这个类的对象做为hash索引准备工作例如以下,由于接口中规定了比較运算符,所以这里能够使用标准的less仿函数。所以这里忽略:

  1. template<class _Tkey>
  2. class MyHashCompare : public hash_compare<_Tkey>
  3. {
  4. public:
  5. size_t operator()(const _Tkey& _Key) const {
  6. return(_Key.hash_value());
  7. }
  8. bool operator()(const _Tkey& _Keyval1, const _Tkey& _Keyval2) const {
  9. return (comp(_Keyval1, _Keyval2));
  10. }
  11. };

下来就这样写:

  1. CTest test;
  2. test.m_value = 123;
  3. test.m_message = "This is a test";
  4. MyHash[test] = 2005;
  5. int val = MyHash[test];

能够看到正确的数字被返回。

      

     三、关于hash_map的思考:

      

     1、性能分析:採用了内联代码和模版技术的hash_map在效率上应该是很优秀的。但我们还须要注意例如以下几点:

      

     * 经过查看代码。字符串索引会比简单类型索引速度慢,自己定义类型索引的性能则和我们选择hash的内容有非常大关系,简单为主,这是使用hash_map的基本原则。

     * 能够通过重写hash_compair仿函数,更改里面关于桶数量的定义。假设取值合适,也能够得到更优的性能。假设桶数量大于10,则牢记它应该是一个质数。

     * 在自己定义类型是,重载的等号(或者拷贝构造)有可能成为性能瓶颈。使用对象指针最为索引将是一个好的想法,但这就必须重写less仿函数。理由同使用字符串指针作为索引。

自己使用上面的方法成功攻克了使用PTCHAR作为Key的使用。其解决方法例如以下:

  1. inline size_t PTCHAR_hash_value(const PTCHAR str)
  2. {
  3. size_t value = _HASH_SEED;
  4. size_t size = _tcslen(str);
  5. if (size > 0) {
  6. size_t temp = (size/16) + 1;
  7. size -= temp;
  8. for (size_t idx=0; idx<=size; idx+=temp) {
  9. value += (size_t)str[(int)idx];
  10. }
  11. }
  12. return value;
  13. }
  14. class PTCHAR_hash_compare : public stdext::hash_compare<PTCHAR>
  15. {
  16. public:
  17. size_t operator()(const PTCHAR _Key) const {
  18. return ((size_t)PTCHAR_hash_value(_Key));
  19. }
  20. bool operator()(const PTCHAR _Keyval1, const PTCHAR _Keyval2) const {
  21. return (_tcscmp(_Keyval1, _Keyval2));
  22. }
  23. };
  24. stdext::hash_map<PTCHAR, long, PTCHAR_hash_compare > myHash;

hash_map原理及C++实现的更多相关文章

  1. 学习hash_map从而了解如何写stl里面的hash函数和equal或者compare函数

    ---恢复内容开始--- 看到同事用unordered_map了所以找个帖子学习学习 http://blog.sina.com.cn/s/blog_4c98b9600100audq.html (一)为 ...

  2. C++ STL中哈希表Map 与 hash_map 介绍

    0 为什么需要hash_map 用过map吧?map提供一个很常用的功能,那就是提供key-value的存储和查找功能.例如,我要记录一个人名和相应的存储,而且随时增加,要快速查找和修改: 岳不群-华 ...

  3. Java面试& HashMap实现原理分析

    1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端.  数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O( ...

  4. STL 中的map 与 hash_map的理解

    可以参考侯捷编著的<STL源码剖析> STL 中的map 与 hash_map的理解 1.STL的map底层是用红黑树存储的,查找时间复杂度是log(n)级别: 2.STL的hash_ma ...

  5. STL中的map和hash_map

    以下全部copy于:http://blog.chinaunix.net/uid-26548237-id-3800125.html 在网上看到有关STL中hash_map的文章,以及一些其他关于STL ...

  6. C++中的hash_map和map的区别

    hash_map和map的区别在哪里?构造函数.hash_map需要hash函数,等于函数:map只需要比较函数(小于函数). 存储结构.hash_map采用hash表存储,map一般采用红黑树(RB ...

  7. Java HashMap实现原理分析

    参考链接:https://www.cnblogs.com/xiarongjin/p/8310011.html 1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是 ...

  8. LeetCode(3):无重复字符的最长子串

    Medium! 题目描述: 给定一个字符串,找出不含有重复字符的 最长子串 的长度. 示例: 给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ...

  9. map,hash_map, hash_table, 红黑树 的原理和使用

    在刷算法题的时候总是碰到好多题,号称可以用hash table来解题.然后就蒙圈了. 1.首先,map和hash_map的区别和使用: (1)map底层用红黑树实现,hash_map底层用hash_t ...

随机推荐

  1. web显示winform,web打开winform,IE打开winform

    前言:为什么要用ie打开winform 个人觉得,winform部署client太麻烦如金蝶··用友,winfrom打补丁太麻烦,加入新功能再部署很费时间:于是就想为什么不能用IE打开呢?这样就不须要 ...

  2. SDUT--Pots(二维BFS)

    Pots Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描写叙述 You are given two pots, having the ...

  3. Atcoder At Beginner Contest 068 C - Cat Snuke and a Voyage

    C - Cat Snuke and a Voyage Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem State ...

  4. ubuntu搭建交叉编译环境makeinfo: command not found

    解决办法:sudo apt-get install texinfo

  5. linux创建新用户并给予root权限

    root比windows的系统管理员的能力更大,足以把整个系统的大部分文件删掉,导致系统完全毁坏,不能再次使用.所以,用root进行不当的操作是相当危险的,轻微的可以死机,严重的甚至不能开机.所以,在 ...

  6. 洛谷 P1000 超级玛丽游戏

    P1000 超级玛丽游戏 题目背景 本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续尝试P1001.P1008. 题目描述 超级玛丽是一个非常经典的游戏.请你用字符画的形式输出超级 ...

  7. robot framework 使用三:浏览器兼容性自己主动化

    robot framework 測试浏览器兼容性 上图中黄色圈的地方默认什么都不写.是firefox浏览器,写上ie就是ie浏览器了 firefox最新版本号即可.ie须要设置: 1. IE选项设置的 ...

  8. 本地 oracle 安装文件夹满触发 ORA-7445 [_memmove()+64] 导致Instance Crashed 的事故

    近期处理了一个问题,原因是因为命中ORA-600 [kole_t2u], [34] - description, bugs 导致 在udump 文件夹下大量转储 出cdmp 文件, 然后这些 cdmp ...

  9. Mybatis like查询的写法--转载

    原文地址:http://lavasoft.blog.51cto.com/62575/1386870 Mybatis like查询官方文档没有明确的例子可循,网上搜索了很多,都不正确. Mybatis ...

  10. (错误记录)Vue: Unknown custom element

    错误: vue.js:634 [Vue warn]: Unknown custom element: <ve-pie> - did you register the component c ...