青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

xiaoguozi's Blog
Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習慣原本生活的人不容易改變,就算現(xiàn)狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預(yù)料,人們需要更細心的觀察別人,要隨時注意才能保護別人,因為他們未必知道自己要什么·····

說來慚愧,使用了很久Visual Stdio 2003了,只知道MFC升級到了7.0,ATL也升級到了7.0,對于這兩個經(jīng)典的類庫做了一些研究,但一直沒有注意C++標準庫的變化。

     今天嘗試的使用了stdext::hash_map這個庫,果然不錯。下面寫下一些心得。

     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結(jié)構(gòu),簡要地偽碼如下:

          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++標準庫的泛型模版一向以嵌套復(fù)雜而聞名,初學時看類庫,無疑天書啊。微軟的hash_map類還聚合了hash_compare仿函數(shù)類,hash_compare類里有聚合了less仿函數(shù)類,亂七八糟的。

     下面說說使用方法:

     一、簡單變量作為索引:整形、實性、指針型
     其實指針型也就是整形,算法一樣。但是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的時候,不需要聲明模版的后兩個參數(shù)(最后一個參數(shù)指名hash_map節(jié)點的存儲方式,默認為pair,我覺得這就挺好,沒必要修改),使用默認值就好。
     2、對于除過字符串的其它簡單類型,hash_map使用模版函數(shù) size_t hash_value(const _Kty& _Keyval) 計算hash值,計算方法是經(jīng)典的掩碼異或法,自動溢出得到索引hash值。微軟的工程師也許開了一個玩笑,這個掩碼被定義為0xdeadbeef(死牛肉,抑或是某個程序員的外號)。
     3、對于字符串指針作索引的時候,使用定類型函數(shù)inline size_t hash_value(const char *_Str)或inline size_t hash_value(const wchar_t *_Str)計算hash值,計算方法是取出每一個字符求和,自動溢出得到hash值。對于字符串型的hash索引,要注意需要自定義less仿函數(shù)。
     因為我們有理由認為,人們使用hash表進行快速查找的預(yù)期成本要比在hash表中插入的預(yù)期成本低得多,所以插入可以比查找昂貴些;基于這個假設(shè),hash_map在有沖突時,插入鏈表是進行排序插入的,這樣在進行查詢沖突解決的時候就能夠更快捷的找到需要的索引。
     但是,基于泛型編程的原則,hash_map也有理由認為每一種類型都支持使用"<"來判別兩個類型值的大小,這種設(shè)計恰好讓字符串類型無所適從,眾所周知,兩個字符串指針的大小并不代表字符串值的大小。見如下代碼:
          hash_map<const char*, int> CharHash;
          CharHash["a"] = 123;
          CharHash["b"] = 456;

          char szInput[64] = "";
          scanf("%s", szInput);

          int val = CharHash[szInput];

     最終的結(jié)果就是無論輸入任何字符串,都無法找到對應(yīng)的整數(shù)值。因為輸入的字符串指針是szInput指針,和"a"或"b"字符串常量指針的大小是絕對不會相同。解決方法如下:
     首先寫一個仿函數(shù)CharLess,繼承自仿函數(shù)基類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);
               }
          };

     很好,有了這個仿函數(shù),就可以正確的使用字符串指針型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];
     
     現(xiàn)在就可以正常工作了。至此,簡單類型的使用方法介紹完畢。

     二、用戶自定義類型:比如對象類型,結(jié)構(gòu)體。
     這種情況比價復(fù)雜,我們先說簡單的,對于C++標準庫的string類。
     
     慶幸的是,微軟為basic_string(string類的基類)提供了hash方法,這使得使用string對象做索引簡單了許多。值得注意(也值得郁悶)的是,雖然支持string的hash,string類卻沒有重載比較運算符,所以標準的hash_compare仿函數(shù)依舊無法工作。我們繼續(xù)重寫less仿函數(shù)。
         
          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設(shè)計要灑脫一些)更加復(fù)雜一些。很顯然,標準庫里不包含對于CString的支持,但CString卻重載了比較運算符(郁悶)。我們必須重寫hash_compare仿函數(shù)。值得一提的是,在Virtual Stdio 2003中,CString不再是MFC的成員,而成為ATL的成員,使用#include <atlstr.h>就可以使用。我沒有采用重寫hash_compare仿函數(shù)的策略,而僅僅是繼承了它,在模版庫中的繼承是沒有性能損耗的,而且能讓我偷一點懶。
     首先重寫一個hash_value函數(shù):
     
          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仿函數(shù):
     
          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仿函數(shù)的引入,因為CString具備比較運算符,我們可以使用默認的less仿函數(shù),在這里映射為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值,也可以使用更復(fù)雜的函數(shù)計算所有域總的hash值
                    return(m_value ^ 0xdeadbeef 
               }
           
               virtual bool operator < (const IHashable& val) const
               {
                    return(m_value < ((CTest&)val).m_value);
               }
          };
     
     用這個類的對象做為hash索引準備工作如下,因為接口中規(guī)定了比較運算符,所以這里可以使用標準的less仿函數(shù),所以這里忽略:
     
          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];
     
     可以看到正確的數(shù)字被返回。
     
     三、關(guān)于hash_map的思考:
     
     1、性能分析:采用了內(nèi)聯(lián)代碼和模版技術(shù)的hash_map在效率上應(yīng)該是非常優(yōu)秀的,但我們還需要注意如下幾點:
     
     * 經(jīng)過查看代碼,字符串索引會比簡單類型索引速度慢,自定義類型索引的性能則和我們選擇hash的內(nèi)容有很大關(guān)系,簡單為主,這是使用hash_map的基本原則。
     * 可以通過重寫hash_compair仿函數(shù),更改里面關(guān)于桶數(shù)量的定義,如果取值合適,也可以得到更優(yōu)的性能。如果桶數(shù)量大于10,則牢記它應(yīng)該是一個質(zhì)數(shù)。
     * 在自定義類型是,重載的等號(或者拷貝構(gòu)造)有可能成為性能瓶頸,使用對象指針最為索引將是一個好的想法,但這就必須重寫less仿函數(shù),理由同使用字符串指針作為索引。

posted on 2008-01-12 18:31 小果子 閱讀(9710) 評論(0)  編輯 收藏 引用 所屬分類: 學習筆記
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲免费av观看| 亚洲欧美激情一区二区| 六月婷婷一区| 日韩视频在线播放| 亚洲激情视频在线| 欧美精品在线免费播放| 中国成人亚色综合网站| 亚洲一卡久久| 在线成人欧美| 亚洲精品免费一区二区三区| 欧美体内she精视频在线观看| 亚洲欧美影院| 久久精品国产2020观看福利| 亚洲国产精品传媒在线观看| 亚洲黄色性网站| 国产精品日韩在线观看| 久久婷婷一区| 欧美日韩第一页| 欧美一级在线亚洲天堂| 久久久久久久国产| 亚洲色无码播放| 欧美一区深夜视频| 91久久国产精品91久久性色| 最新国产成人在线观看| 国产欧美精品在线播放| 亚洲大胆av| 国产精品自在线| 亚洲国产精品专区久久 | 欧美顶级艳妇交换群宴| 欧美日韩国产在线播放| 久久久噜久噜久久综合| 欧美精品一区二区三区四区| 午夜精品视频网站| 欧美大胆a视频| 久久久久久成人| 欧美四级电影网站| 亚洲国产毛片完整版| 国产欧美日韩三级| 一本一本久久a久久精品综合妖精| 国产视频观看一区| avtt综合网| 亚洲经典一区| 久久精品99国产精品日本| 中文一区二区| 欧美a级在线| 久久综合九色综合欧美就去吻| 欧美视频福利| 亚洲精选在线观看| 亚洲激情一区二区| 久久这里只有| 快she精品国产999| 国产日韩精品一区二区三区| 99这里只有久久精品视频| 亚洲人体大胆视频| 麻豆精品一区二区综合av| 久久久噜噜噜久久人人看| 国产精品亚洲综合一区在线观看| 亚洲激情一区| 一本色道久久加勒比88综合| 美女图片一区二区| 欧美成人精品在线播放| 国产亚洲精品7777| 亚洲欧美视频在线观看| 亚洲在线日韩| 国产精品永久免费在线| 亚洲校园激情| 久久精品成人一区二区三区蜜臀| 国产精品欧美风情| 亚洲专区在线| 久久久久久夜精品精品免费| 国产欧美亚洲视频| 欧美在现视频| 欧美国产免费| 亚洲精品在线免费观看视频| 欧美国产日韩二区| 一片黄亚洲嫩模| 性欧美xxxx大乳国产app| 国产精品一区三区| 久久久久国产精品一区三寸| 久热精品在线视频| 亚洲欧洲在线免费| 欧美日韩国产一区二区| 99视频热这里只有精品免费| 亚洲视频综合| 国产一本一道久久香蕉| 久久天天躁夜夜躁狠狠躁2022| 欧美成人精品不卡视频在线观看| 最新高清无码专区| 国产精品黄色| 久久久久久久久久码影片| 欧美成人一区在线| 亚洲专区在线| 黄色国产精品| 欧美巨乳在线观看| 午夜欧美大片免费观看| 欧美aⅴ99久久黑人专区| 在线视频日韩精品| 狠狠入ady亚洲精品| 欧美大片第1页| 亚洲男人的天堂在线| 男女精品网站| 亚洲在线成人精品| 亚洲激情偷拍| 国产女人aaa级久久久级| 美女精品国产| 午夜天堂精品久久久久| 欧美韩日一区| 久久av红桃一区二区小说| 亚洲国产精品成人久久综合一区| 欧美日韩国产一中文字不卡| 欧美自拍偷拍| 亚洲性视频h| 亚洲第一在线视频| 久久精品成人一区二区三区蜜臀 | 欧美日韩精品二区| 久久久噜噜噜久久| 亚洲午夜在线视频| 亚洲精品小视频在线观看| 久久久亚洲一区| 亚洲综合好骚| 亚洲精品一区二区在线观看| 国产欧美视频在线观看| 欧美日韩黄色一区二区| 免费久久精品视频| 久久久久国产一区二区三区| 一本色道88久久加勒比精品| 免费亚洲电影| 久久在线免费视频| 久久国产精品99精品国产| 亚洲视频网站在线观看| 亚洲国内精品在线| 在线播放一区| 在线观看欧美成人| 国产午夜精品全部视频在线播放| 欧美日韩一区二区在线观看视频 | 一二三区精品福利视频| 亚洲国产高清在线| 欧美成人网在线| 欧美18av| 欧美国产大片| 欧美激情一区二区久久久| 久久亚洲精品欧美| 免费成人在线视频网站| 麻豆9191精品国产| 欧美成人资源| 欧美激情一区二区三区| 亚洲成在人线av| 亚洲人成欧美中文字幕| 亚洲三级免费观看| 一级成人国产| 亚洲欧美激情在线视频| 亚洲欧美国产制服动漫| 小黄鸭精品密入口导航| 欧美一区二区在线看| 欧美在线视频免费播放| 久久免费国产精品| 欧美国产日韩视频| 欧美日韩一级黄| 国产精品视频一区二区高潮| 国产精品尤物福利片在线观看| 国产欧美视频在线观看| 国产一区二区你懂的| …久久精品99久久香蕉国产 | 国产日韩欧美在线播放| 国产一区久久久| 亚洲精品久久久久久久久久久久 | 免播放器亚洲| 亚洲欧洲一二三| 亚洲午夜精品在线| 欧美综合国产精品久久丁香| 久久欧美肥婆一二区| 欧美激情91| 国产欧美一区二区色老头| 一区在线电影| 亚洲午夜激情网页| 久久九九热re6这里有精品| 亚洲电影自拍| 亚洲永久免费观看| 欧美成人网在线| 国产伦精品一区二区三区视频孕妇| 国内精品亚洲| 亚洲在线中文字幕| 免费在线播放第一区高清av| 91久久国产综合久久91精品网站| 亚洲一区二区三区四区中文| 久久久精品国产99久久精品芒果| 欧美激情视频免费观看| 国产有码一区二区| 亚洲一区二区三区高清不卡| 久久久久久尹人网香蕉| 亚洲乱码国产乱码精品精可以看| 欧美在线视屏 | 久久久久久久欧美精品| 欧美日韩一区二区三区在线 | 欧美婷婷久久| 亚洲激情综合| 久久久女女女女999久久| 亚洲最新视频在线| 欧美大片91| 91久久精品www人人做人人爽|