1. 程式人生 > >c++STL中的hash_map自定義類。

c++STL中的hash_map自定義類。

是的,hash_map是一個很方便的容器,有了STL確確實實給了C++developer很大方便,hash_map就是其中一種。他在資料少的時候,作用和基於RB-tree的map差不多,甚至不如,畢竟有hasher。但是在大量資料的時候,就很快捷了。我平時用hash_map都是用基本型別的,最多弄個string類,也是庫裡已經弄好了的。直接套模板就行。可是今天遇到一個問題就是當你需要把一個自定義類作為key的時候,應該怎麼辦?當我寫完程式並編譯的時候,他報錯了,報了很長的一段錯。前兩行是這樣的:

error C2784: “bool std::operator <(const std::list<_Ty,_Alloc> &,const std::list<_Ty,_Alloc> &)”: 未能從“const Box”為“const std::list<_Ty,_Alloc> &”推導 模板 引數
e:\program files\vc\include\list(1958) : 參見“std::operator <”的宣告

然後我根本不知道這是什麼問題,只好百度,百度裡基本說到都是忘記使用#include<string>,然而這並不是問題的關鍵,因為我並沒有用到字串啊,就是加上也是一樣報錯。

終於我耗時1h才找到隻言片語,又回頭看看錯誤報告,似乎是<的原因?沒有過載?是了,因為hash_map實現的時候需要用less也就是<函式來對key排序,那就把<過載了

	bool operator<(const Box &k2)const
	{
		if ((*this).width != k2.width)
		{
			return (*this).width < k2.width;
		}

		if ((*this).depth != k2.depth)
		{
			return (*this).depth < k2.depth;
		}
		if ((*this).height != k2.height)
		{
			return (*this).height < k2.height;
		}
		return false;
	}


那麼應該可以了吧?結果還是報錯:

1>e:\program files\vc\include\xhash(30): error C2440: “型別轉換”: 無法從“const Box”轉換為“size_t”
1>          沒有可用於執行該轉換的使用者定義的轉換運算子,或者無法呼叫該運算子

那麼是跟size_t有關嘍,又用了1h我終於知道問題所在了,http://www.cplusplus.com/中的定義是這樣的


然後詳細情況如下:


是的少了個hasher,在《STL原始碼剖析》中,闡明瞭只有基本型別和字元指標可以呼叫預設hash函式。在使用了其他型別時(比如自定義類)使用者必須為其自定義一個hash函式像這樣:size_t operator() (const Box& b)const放在一個結構體中,作為仿函式,也就是函式物件。

我個人在這是這樣實現hasher的:

size_t operator() (const Box& b)const


{


return (b.depth + 10 * b.height + 100 * b.width) % 20;


};

本來以為總算可以了,然後還是報錯:1>e:\program files\vc\include\xhash(264): error C2039: “bucket_size”: 不是“cmp_key”的成員
1>          c:\users\administrator\documents\visual studio 2013\projects\最高的箱子\最高的箱子\源.cpp(47) : 參見“cmp_key”的宣告

是的,真煩,bucket_size是什麼鬼啊,繼續查資料。。。

終於,我找到了,在http://www.cplusplus.com/中的定義是這樣的:


雖然是unordered_map不過定義應該差不多吧。而在stackoverflow中,大神是這麼說的:



在《STL原始碼剖析》中,是這麼說buckets的:hashTable表格內的元素為桶子(bucket),就是說表格內的每個單元,涵蓋的不只是個節點,甚至可能是一“桶”節點。

這就很明瞭了,我們可以在結果中加上:

enum
{   //   parameters   for   hash   table   
bucket_size = 4,   //   0   <   bucket_size   
min_buckets = 8  //   min_buckets   =   2   ^^   N,   0   <   N   
};

必不可少的。然而還是報錯:

1>e:\program files\vc\include\xhash(744): error C2064: 項不會計算為接受 2 個引數的函式
1>          類不會將“operator()”或使用者定義的轉換運算子定義到指向函式的指標或指向函式的引用(它們接受適當數量的引數)

恩,過載<在此時來說是不行的,需要在結構體中加上:

bool operator()(const Box &k1, const Box &k2)const
{
if (k1.width != k2.width)
{
return k1.width < k2.width;
}


if (k1.depth != k2.depth)
{
return k1.depth < k2.depth;
}
if (k1.height != k2.height)
{
return k1.height < k2.height;
}
return false;
}

依然是仿函式,而不是過載運算子作為equalToKey()。這樣就全部完成了,全部程式碼在這:http://blog.csdn.net/youngstunner/article/details/50583852

完整的實現了一個自定義類的hash_map,大功告成!

相關推薦

c++STLhash_map定義

是的,hash_map是一個很方便的容器,有了STL確確實實給了C++developer很大方便,hash_map就是其中一種。他在資料少的時候,作用和基於RB-tree的map差不多,甚至不如,畢竟有hasher。但是在大量資料的時候,就很快捷了。我平時用hash_map

Object-C定義實現協議

如果嘗試使用自定義類(例如,人類(person類)、地址簿類(myBook類)、分數類(Fraction類))中的copy方法,如 myBook = [myBook mutableCopy]; person = [Person copy];等類似的操作,將會收到一條異

問題解決——在STL的queue使用定義

本文原創,轉載請保證文章的完整性,並顯要的註明出處。 平時很少用STL,就算用,也基本是使用queue<int>之類的簡單資料型別,偶爾在MFC裡寫點小程式碼,用的也是queue<CString>。 (求不要吐槽我為什麼用CString不用stri

Idea_學習_03_IDEA使定義型的文件進行代碼高亮識別

segment tar register 定義 類型 自定義類 pos edi ref 如果你只是想用xml的編輯模式來編輯*.screen文件的話,可以在 Settings->Editor->File Types 中,在Recognized File Ty

Java定義和ArrayList<E>的使用案例

自定義類和ArrayList的使用 自定義類: 將生活中事物抽象成程式碼,或者說是對生活中事物的一種對映。 1.類是一種引用資料型別 2.類中包含了屬性和功能, 屬性:事物的特性,例如:name(姓名),gender(性別),color(顏色),brand(品牌),siz

map使用定義指標作為key

//先上程式碼 #pragma once //想用類作為key,必須過載<運算子 或者提供 //想用指標作為key,也是可以的,不過要自己提供仿函式 class CBase { public:     explicit CBase(int a);     ~CBase(void); private:

C# WinForm如何定義config檔案(XML檔案),並且讀取和儲存它

我這裡以連結資料庫為例子, 其中書寫的Config的xml檔案如下: <?xml version="1.0" encoding="utf-8"?> <configuration>   <appSettings>     <add k

vector存放定義 ,對的要求

vector中存放自定義類的前提是: 自定義的類必須有預設建構函式。因為vector會呼叫預設建構函式來初始化元素的物件。 那必須要明確:編譯器什麼時候隱式宣告預設建構函式? 有兩個條件: · 該類沒有顯式宣告任何建構函式。--既然你都定義了,系統就不給你生成了。 · 資料

淺談VB6定義的使用

   PS:除非特別宣告,本文所說VB指的是VB6,而非VB.NET。    大家都知道,VB是一種半面向物件(也有人稱之為“偽面向物件”)的語言,他雖然可以寫自定義的類,但是由於種種原因,使得他在這方面的發育產生了一點問題,比如說:VB寫出來的類是不能繼承的(不孕不育?!-_-#...傳說VB的偶像是東方

HashMap使用定義作為Key時,為何要重寫HashCode和Equals方法

ide string https object 避免 equals方法 args sys 添加 之前一直不是很理解為什麽要重寫HashCode和Equals方法,才只能作為鍵值存儲在HashMap中。通過下文,可以一探究竟。 首先,如果我們直接用以下的Person類

c#定義泛型、泛型方法和泛型接口

泛型方法 return bsp 其中 tel sts code 方式 void ? 泛型的產生其中一個原因就是為了解決原來集合類中元素的裝箱和拆箱問題: 一、泛型類: /// <summary> /// 返回前臺的消息 /// &

C# 有關控件、定義事件的委托鏈的獲取、移除操作

ons class 單擊 spa inf += finish ati pre 直接來代碼吧,這樣幹脆直接,也不耽誤我午休了。一切盡在源碼中。 public class ControlEventTool { /// <summary>

c++ STL 之 unorder_map及unorder_set使用定義作為key的方法

  #include <iostream> #include <string> #include <unordered_map> #include <unordered_set> using namespace std; str

C#定義操作主窗體控制元件,通過委託實現

主窗體中包含一個標籤label1和一個按鈕button1 程式碼如下: public void ChangeLabel(string text) { label1.Text = text; } private void button1_Click(o

C++hash_map定義雜湊函式和比較函式的理解

#include "stdafx.h" #include <iostream> #include <hash_map> #include <vector>using std::vector; using stdext::hash_map;class  hash_wchar_

Lambda語句創建定義型時,也可指定某種特定型,方法是在new與{}之間寫上型名稱

特定 pan sel lambda語句 lam {} where distinct select 如: var fc =...ChildFath = fc.Select(c => new Child_Father { child = c.child, father =

工作總結 Rezor 裏面的一些小知識----定義型 放在標簽值 會直接跳過去

直接 技術 例如 images 定義變量 png 索引 log blog 0 的時候不報錯 1 的時候 報錯了 原因 是 imagesname[i] 索引超出了 為什麽在 上面 報錯呢? 不在這裏報錯呢? 說明了 Rezor 對於 自定義的變量 放在標

java定義型 作為HashMap的Key值 (Pair<V,K>為例)

由於 con als void hash system 進行 原型 自定義 由於是自定義類型,所以HashMap中的equals()函數和hashCode()函數都需要自定義覆蓋。 不然內容相同的對象對應的hashCode會不同,無法發揮算法的正常功能,覆蓋equals函

c/c++ 標準庫 set 定義關鍵字型與比較函數

尖括號 ios template end 傳遞函數 使用 out 例子 比較 標準庫 set 自定義關鍵字類型與比較函數 問題:哪些類型可以作為標準庫set的關鍵字類型呢??? 答案: 1,任意類型,但是需要額外提供能夠比較這種類型的比較函數。 2,這種類型實現了 &l

資料結構與演算法----定義函式與資料成員

近期在梳理知識,做一個小結,希望自己能多多使用 在標頭檔案中: enum sign {plus, minus}; class Accruency { public: Accruency(sign s = plus, unsigned long d = 0, unsigned in