é »åº¦è¨æ°ã«ããã unordered_map ã®èª¿æ´ï¼C++ï¼
å½¢æ ç´ ã®é »åº¦ãã«ã¦ã³ãããã¨ããã·ã³ãã«ãªã¿ã¹ã¯ã§ std::tr1::unordered_map ã®æ§è½ã«ã¤ãã¦å®é¨ãã¦ã¿ã¾ããï¼std::string ãã const char * ã®æ¹ãã¡ã¢ãªãç¯ç´ã§ããã¨ãããããªè»½ãå 容ã§ãï¼
å®é¨æ¦è¦
å®é¨ç°å¢ã¯ä»¥ä¸ã®ã¨ããã§ãï¼
- å®é¨ç°å¢
- CPUï¼Core 2 Duo U9600 1.60GHz
- ã³ã³ãã¤ã©ï¼gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)
å ¥åã¨ãã¦ä½¿ç¨ããã®ã¯ï¼ã¦ã§ãã³ã¼ãã¹ããæ½åºããå½¢æ ç´ ãæ¹è¡åºåãã§ä¿åãããã¡ã¤ã«ã§ãï¼
- å
¥å
- ãµã¤ãºï¼815,793,701 bytes
- å½¢æ ç´ æ°ï¼133,940,786
- ç°ãªãæ°ï¼516,612
å½¢æ ç´ ã®å ¥åã«ã¤ãã¦ã¯ï¼std::ios::sync_with_stdio(false) ãå¼ã³åºããå¾ã§ std::getline() ã使ãããã«ãã¦ãã¾ãï¼åè¡ãçãã®ã§ï¼ãªã¼ãã¼ãããã大ãããªã£ã¦ãã¾ãï¼fgets() ã getline() ãªã©ã«åãæ¿ãããã¨ã§ï¼ããªãç縮ã§ããããããã¾ããï¼
å®é¨æ¦è¦ã¯ä»¥ä¸ã®ããã«ãªã£ã¦ãã¾ãï¼
- getline
- å½¢æ ç´ ã®èªã¿è¾¼ã¿ã«ãããæéãè¨æ¸¬ãã¾ãï¼
- map
- std::map<std::string, int>
- std::tr1::unordered_map ã使ãã¾ãããï¼
- unordered-map
- std::tr1::unordered_map<std::string, int>
- ãã¼ã¹ã©ã¤ã³ã§ãï¼åºæ¬ã¯ããã§åé¡ããã¾ããï¼
- custom-map0
- std::string + FNV Hash
- FNV Hash: http://isthe.com/chongo/tech/comp/fnv/
- ããã·ã¥é¢æ°ãå ¥ãæ¿ããã ãã§ãï¼äºæ³ä»¥ä¸ã®å¹æãããã¾ããï¼â
- std::string + FNV Hash
- custom-map1
- èªä½ String, StringPool + FNV Hash + std::strcmp()
- String: const char *
- std::string ã¯ã¡ã¢ãªã使ãããã ã¨ãããã¨ã§ï¼æååãæ ¼ç´ããããã®é åãèªåã§ç®¡çããããã«ãã¦ã¿ã¾ããï¼
- èªä½ String, StringPool + FNV Hash + std::strcmp()
- custom-map2
- èªä½ String, StringPool + FNV Hash + èªä½æ¯è¼é¢æ°ï¼ãã¤ã³ã¿ã®ã¤ã³ã¯ãªã¡ã³ãï¼
- std::strcmp() ã®é¢æ°å¼ã³åºããå°å³ã«å¹ãã¦ãããããããªãã¨æã£ã¦è©¦ãã¦ã¿ã¾ããï¼â
- custom-map3
- èªä½ String, StringPool + FNV Hash + èªä½æ¯è¼é¢æ°ï¼ã«ã¦ã³ã¿ã®ã¤ã³ã¯ãªã¡ã³ãï¼
- ãã¤ã³ã¿ã¨ã«ã¦ã³ã¿ã¨ã©ã¡ããéãããªãã¦æ°ã«ãã¦ãä»æ¹ããªãâ¦ã¨ãããã¨ã¯ãªãããã§ãï¼â
- custom-map4
- std::string + hashlittle() + èªä½æ¯è¼é¢æ°ï¼ã«ã¦ã³ã¿ã®ã¤ã³ã¯ãªã¡ã³ãï¼
- hashlittle(): http://burtleburtle.net/bob/c/lookup3.c
- FNV Hash ããå¼·åãªããã·ã¥é¢æ°ã試ãã¦ã¿ã¾ããï¼
- std::string + hashlittle() + èªä½æ¯è¼é¢æ°ï¼ã«ã¦ã³ã¿ã®ã¤ã³ã¯ãªã¡ã³ãï¼
- custom-map5
- èªä½ String, StringPool + hashlittle() + èªä½æ¯è¼é¢æ°ï¼ã«ã¦ã³ã¿ã®ã¤ã³ã¯ãªã¡ã³ãï¼
- String: const char *, std::size_t
- std::string ã¯ã¡ã¢ãªã使ãããï¼ä»¥ä¸ç¥ï¼
- èªä½ String, StringPool + hashlittle() + èªä½æ¯è¼é¢æ°ï¼ã«ã¦ã³ã¿ã®ã¤ã³ã¯ãªã¡ã³ãï¼
â ï¼ããã·ã¥é¢æ°ã®ä¸èº«ãæé©åã®å¹æã¯ç°å¢ã«ãã£ã¦ç°ãªãã®ã§ï¼å®éã®ã¨ããã¯è©¦ãã¦ã¿ãªãã¨åããã¾ããï¼
å®é¨çµæ
å®é¨çµæï¼å¦çæéã¨ã¡ã¢ãªä½¿ç¨éï¼ã¯ä»¥ä¸ã®ã¨ããã§ãï¼
- | å¦çæé | ã¡ã¢ãªä½¿ç¨é |
---|---|---|
getline | 13,376 ms | - |
map | 184,964 ms | 64 MiB |
unordered-map | 36,312 ms | 52 MiB |
custom-map0 | 31,870 ms | 52 MiB |
custom-map1 | 31,281 ms | 28 MiB |
custom-map2 | 31,036 ms | 28 MiB |
custom-map3 | 29,831 ms | 28 MiB |
custom-map4 | 32,467 ms | 52 MiB |
custom-map5 | 29,269 ms | 35 MiB |
å¦çæéã«ã¤ãã¦ã¯ï¼std::tr1::unordered_map ã®æ¹ã std::map ããæããã«é«éã§ãï¼std::map ã使ã£ã¦ããã³ã¼ããæå ã«ããã®ã§ããã°ï¼std::tr1::unordered_map ã«åãæ¿ããã ãã§ãããªãã®é«éåãæå¾ ã§ãã¾ãï¼ä¸æ¹ï¼custom-map ã¸ã®åãæ¿ãã«ããã¦ã¯ï¼å¦çæéã¯ããã»ã©ç縮ããã¾ããï¼
ã¡ã¢ãªä½¿ç¨éã«ã¤ãã¦ã¯ï¼std::string ããèªä½ã®ã¯ã©ã¹ã«ç§»è¡ãããã¨ã§ã¡ã¢ãªãç¯ç´ã§ãã¾ãï¼ç°¡åãªæ©è½ã®ã¿ãå®è£ ããã®ã§ããã° 100 è¡ããããªã®ã§ï¼ããã»ã©æéã¯ãããã¾ããï¼
追è¨ï¼2010-11-29ï¼ï¼å¯æããªããæ¸ããããããæããããªçµããæ¹ã«ãªã£ã¦ããã®ã§ï¼std::string ã«ã¤ãã¦ï¼å°ãæ¸ã足ãã¦ããã¾ãï¼
å®éã®ã¨ããï¼ã»ã¨ãã©ã®ç¨éã§ã¯ std::string ã使ã£ã¦ããã°åé¡ãªãã¨æãã¾ãï¼ä»åã®ã¿ã¹ã¯ã«ãã¦ãï¼ãã®è¦æ¨¡ã§ããã°ï¼std::string ããã®ã¾ã¾ä½¿ãã®ãæé©ãªé¸æã§ãï¼30 ç§ã§çµããã¿ã¹ã¯ã« 100 è¡ãã³ã¼ããå ãããªãã¦ï¼ã©ãèãã¦ã趣å³ã®é åã§ãï¼ãã¹ããå¿ è¦ã«ãªãã¾ããï¼æ¡ç®ãåãã¾ããï¼
ããã¦èªåã®ã¯ã©ã¹ãç¨æãããããªç¶æ³ã¨ãã¦ã¯ï¼ç¾å®ã«ã¡ã¢ãªãä¸è¶³ããããªã¨ããï¼æååã®å®ä½ãæãããããªãã¨ããªã©ã§ããããï¼å¾è ã«ã¤ãã¦ã¯ï¼substr() ãåãããããã¨æãã¾ãï¼std::string ã§ã¯æ°ãã確ä¿ããé åã« substr() ã§æå®ããé¨åãã³ãã¼ããã¨ãã大ä»äºã«ãªãã¾ããï¼ãã¤ã³ã¿ã¨é·ãã®ã¿ãæã¤ã¯ã©ã¹ã§ããã°ï¼ãã¤ã³ã¿ã¨é·ããè¨å®ããã ãã«ãªãã¾ãï¼
çµå±ã®ã¨ããã¯é©æé©æãä¸çªã¨ãããã¨ã§ï¼ãããµããçµè«ã«è½ã¡çãã¾ãï¼
# ã¨ã¯ããï¼ãã¾ãæå³ããªãã¨åãã£ã¦ãã¦ãï¼ä½ãæ°ãããã¨ã試ãã¦ã¿ããï¼å¹çåãæ½ããããã¦ãã¾ããã®ã§ãï¼
å®éã®ã³ã¼ã
以ä¸ï¼custom-map0 ãã custom-map3 ã¾ã§ã§ä½¿ã£ãã³ã¼ãã§ãï¼
class String { public: String() : str_(NULL) {} explicit String(const char *str) : str_(str) {} String(const String &str) : str_(str.str_) {} ~String() {} String &operator=(const String &str) { str_ = str.str_; return *this; } bool operator==(const String &rhs) const { return std::strcmp(str_, rhs.str_) == 0; } const char &operator[](std::size_t index) const { return str_[index]; } const char *str() const { return str_; } private: const char *str_; }; class StringPool { public: StringPool() : chunks_(), ptr_(NULL), avail_(0) {} ~StringPool() {} String Clone(const char *ptr, std::size_t length) { if (length >= avail_) { NewChunk(length + 1); } for (std::size_t i = 0; i < length; ++i) { ptr_[i] = ptr[i]; } String clone(ptr_); ptr_[length] = '\0'; ptr_ += length + 1; avail_ -= length + 1; return clone; } private: enum { MIN_CHUNK_SIZE = 4096 }; std::vector<std::tr1::shared_ptr<std::vector<char> > > chunks_; char *ptr_; std::size_t avail_; void NewChunk(std::size_t chunk_size) { if (chunk_size < MIN_CHUNK_SIZE) { chunk_size = MIN_CHUNK_SIZE; } std::tr1::shared_ptr<std::vector<char> > new_chunk( new std::vector<char>(chunk_size)); chunks_.push_back(new_chunk); ptr_ = &new_chunk->front(); avail_ = chunk_size; } // Disallows copy and assignment. StringPool(const StringPool &); StringPool &operator=(const StringPool &); }; class StringHash { public: uint32_t operator()(const String &str) const { uint32_t a = 0x811C9DC5; for (const char *p = str.str(); *p != '\0'; ++p) { a *= 0x01000193; a ^= static_cast<unsigned char>(*p); } return a; } };
以ä¸ï¼custom-map4 㨠custom-map5 ã§ä½¿ã£ãã³ã¼ãã§ãï¼
class String { public: String() : ptr_(NULL), length_(0) {} String(const char *ptr, std::size_t length) : ptr_(ptr), length_(length) {} String(const String &str) : ptr_(str.ptr_), length_(str.length_) {} ~String() {} String &operator=(const String &str) { ptr_ = str.ptr_; length_ = str.length_; return *this; } bool operator==(const String &rhs) const { if (length_ != rhs.length_) { return false; } if (ptr_ == rhs.ptr_) { return true; } for (std::size_t i = 0; i < length_; ++i) { if (ptr_[i] != rhs.ptr_[i]) { return false; } } return true; } const char &operator[](std::size_t index) const { return ptr_[index]; } const char *ptr() const { return ptr_; } std::size_t length() const { return length_; } private: const char *ptr_; std::size_t length_; }; class StringPool { public: StringPool() : chunks_(), ptr_(NULL), avail_(0) {} ~StringPool() {} String Clone(const String &str) { if (str.length() > avail_) { NewChunk(str.length()); } for (std::size_t i = 0; i < str.length(); ++i) { ptr_[i] = str[i]; } String clone(ptr_, str.length()); ptr_ += str.length(); avail_ -= str.length(); return clone; } private: enum { MIN_CHUNK_SIZE = 4096 }; std::vector<std::tr1::shared_ptr<std::vector<char> > > chunks_; char *ptr_; std::size_t avail_; void NewChunk(std::size_t chunk_size) { if (chunk_size < MIN_CHUNK_SIZE) { chunk_size = MIN_CHUNK_SIZE; } std::tr1::shared_ptr<std::vector<char> > new_chunk( new std::vector<char>(chunk_size)); chunks_.push_back(new_chunk); ptr_ = &new_chunk->front(); avail_ = chunk_size; } // Disallows copy and assignment. StringPool(const StringPool &); StringPool &operator=(const StringPool &); }; // This hash function is defined in lookup3.c uint32_t hashlittle(const void *key, size_t length, uint32_t initval); class StringHash { public: uint32_t operator()(const String &str) const { return hashlittle(str.ptr(), str.length(), 0); } };