STL'nin bir HashMap API'sı olduğunu biliyorum, ancak bununla ilgili iyi örneklerle iyi ve eksiksiz bir belge bulamıyorum.
Herhangi bir iyi örnek takdir edilecektir.
STL'nin bir HashMap API'sı olduğunu biliyorum, ancak bununla ilgili iyi örneklerle iyi ve eksiksiz bir belge bulamıyorum.
Herhangi bir iyi örnek takdir edilecektir.
Yanıtlar:
Standart kütüphane sıralı ve sırasız harita ( std::map
ve std::unordered_map
) kaplarını içerir. Sıralı bir haritada elemanlar tuşa göre sıralanır, ekleme ve erişim O'da (log n) olur . Genellikle standart kütüphane sıralı haritalar için dahili olarak kırmızı siyah ağaçlar kullanır . Ancak bu sadece bir uygulama detayıdır. Sırasız bir harita eki ve erişimi O (1) 'de. Bir hashtable için sadece başka bir isim.
(Sıralı) ile bir örnek std::map
:
#include <map>
#include <iostream>
#include <cassert>
int main(int argc, char **argv)
{
std::map<std::string, int> m;
m["hello"] = 23;
// check if key is present
if (m.find("world") != m.end())
std::cout << "map contains key world!\n";
// retrieve
std::cout << m["hello"] << '\n';
std::map<std::string, int>::iterator i = m.find("hello");
assert(i != m.end());
std::cout << "Key: " << i->first << " Value: " << i->second << '\n';
return 0;
}
Çıktı:
23 Anahtar: merhaba Değer: 23
Konteynırınızda sipariş vermeniz gerekiyorsa ve O (log n) çalışma zamanı ile uyumluysanız, sadece kullanın std::map
.
Eğer gerçekten (O (1) insert / erişimi) karma-tablo gerekir Aksi takdirde, kontrol std::unordered_map
benzer olan, std::map
(sadece arama ve değiştirmek zorunda yukarıdaki örnekte örneğin API map
ile unordered_map
).
unordered_map
Kap ile tanıtıldı C ++ 11 standart revizyon. Bu nedenle, derleyicinize bağlı olarak, C ++ 11 özelliklerini etkinleştirmeniz gerekir (örn. GCC 4.8 kullanırken -std=c++11
CXXFLAGS'a eklemeniz gerekir).
C ++ 11 sürümünden önce bile GCC desteklenir unordered_map
- ad alanında std::tr1
. Böylece, eski GCC derleyicileri için bunu şu şekilde kullanmayı deneyebilirsiniz:
#include <tr1/unordered_map>
std::tr1::unordered_map<std::string, int> m;
Ayrıca güçlendirmenin bir parçasıdır, yani daha iyi taşınabilirlik için karşılık gelen yükseltme başlığını kullanabilirsiniz .
hash_map
unordered_map
. Dolayısıyla, standart olmayanı düşünmek için hiçbir neden yoktur hash_map
.
A hash_map
, standardizasyon amacıyla neyin daha eski, standartlaştırılmamış bir versiyonudur unordered_map
(başlangıçta TR1'de ve C ++ 11'den beri standarda dahil edilmiştir). Adından da anlaşılacağı gibi, bu farklıdır std::map
öncelikle sırasız olmak - Bir harita üzerinden size iterate, eğer örneğin begin()
üzere end()
, anahtar tarafından sırayla öğeleri olsun 1 , ama bir yoluyla size yinelerler eğer unordered_map
gelen begin()
etmek end()
, sen a öğeleri olsun az ya da çok keyfi düzen.
An unordered_map
normalde sabit bir karmaşıklığa sahip olması beklenir. Yani, bir ekleme, arama vb., Tabloda kaç öğe olduğuna bakılmaksızın, genellikle sabit bir süre alır. A std::map
, depolanan öğe sayısı üzerinde logaritmik bir karmaşıklığa sahiptir - yani bir öğe ekleme veya alma zamanı artar, ancak harita büyüdükçe oldukça yavaş olur . Örneğin, 1 milyon öğeden birini aramak 1 mikrosaniye alırsa, 2 milyon öğeden birini aramak için yaklaşık 2 mikrosaniye, 4 milyon öğeden biri için 3 mikrosaniye, 8 milyondan biri için 4 mikrosaniye bekleyebilirsiniz. öğeler, vb.
Pratik bir bakış açısından, bu aslında tüm hikaye değil. Doğası gereği, basit bir karma tablosu sabit bir boyuta sahiptir. Genel amaçlı bir kap için değişken boyutlu gereksinimlere uyarlanması biraz önemsizdir. Sonuç olarak, (potansiyel olarak) tabloyu büyüten operasyonlar (örneğin, yerleştirme) potansiyel olarak nispeten yavaştır (yani, çoğu oldukça hızlıdır, ancak periyodik olarak bir tane daha yavaş olacaktır). Tablonun boyutunu değiştiremeyen aramalar genellikle çok daha hızlıdır. Sonuç olarak, ekleme sayısına kıyasla çok fazla arama yaptığınızda, karma tabanlı tabloların çoğu en iyi durumda olma eğilimindedir. Çok fazla veri eklediğiniz durumlarda, sonuçları almak için tabloyu bir kez yineleyin (örneğin, bir dosyadaki benzersiz kelimelerin sayısını saymak)std::map
aynı derecede hızlı ve muhtemelen daha hızlı olacaktır (ancak yine de hesaplama karmaşıklığı farklıdır, bu nedenle dosyadaki benzersiz kelimelerin sayısına da bağlı olabilir).
1std::less<T>
Varsayılan olarak , haritayı oluştururken siparişin üçüncü şablon parametresi tarafından tanımlandığı yer .
rehash
. Aradığınızda rehash
, tablo için bir boyut belirtirsiniz. Bu boyut, tablo için belirtilen maksimum yük faktörünü aşmadığı sürece kullanılacaktır (bu durumda, yük faktörünü sınırlar dahilinde tutmak için boyut otomatik olarak artırılacaktır).
Derleme hataları oluşturmak için gerekli olmayan, daha eksiksiz ve esnek bir örnek:
#include <iostream>
#include <unordered_map>
class Hashtable {
std::unordered_map<const void *, const void *> htmap;
public:
void put(const void *key, const void *value) {
htmap[key] = value;
}
const void *get(const void *key) {
return htmap[key];
}
};
int main() {
Hashtable ht;
ht.put("Bob", "Dylan");
int one = 1;
ht.put("one", &one);
std::cout << (char *)ht.get("Bob") << "; " << *(int *)ht.get("one");
}
İşaretçiler olarak önceden tanımlanmadıkları sürece tuşlar için özellikle yararlı değildir, çünkü eşleşen bir değer işe yaramaz! (Ancak, normalde anahtarlar için dizeler kullandığım için, anahtar bildirimi "const void *" yerine "dize" yerine bu sorunu çözmelidir.)
void*
. Yeni başlayanlar için, unordered_map
standardın bir parçası olduğu ve kod sürdürülebilirliğini azalttığı için sarmak için bir neden yoktur . Sonra, sarmakta ısrar ediyorsanız, kullanın templates
. Onlar tam olarak bunun için.
std::unordered_map
GCC'de karma harita kullanan kanıtlar stdlibc ++ 6.4
Bu, şu adreste belirtilmiştir: https://stackoverflow.com/a/3578247/895245 ama aşağıdaki cevapta: st ++ içinde hangi veri yapısı var: C ++ haritası? GCC stdlibc ++ 6.4 uygulaması için daha fazla kanıt verdim:
İşte bu cevapta açıklanan performans karakteristik grafiğinin bir önizlemesi:
Özel sınıf ve hash işlevi nasıl kullanılır? unordered_map
Bu yanıt onu çiviler: Anahtar olarak özel bir sınıf türü kullanarak C ++ unordered_map
Alıntı: eşitlik:
struct Key
{
std::string first;
std::string second;
int third;
bool operator==(const Key &other) const
{ return (first == other.first
&& second == other.second
&& third == other.third);
}
};
Özet fonksiyonu:
namespace std {
template <>
struct hash<Key>
{
std::size_t operator()(const Key& k) const
{
using std::size_t;
using std::hash;
using std::string;
// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:
return ((hash<string>()(k.first)
^ (hash<string>()(k.second) << 1)) >> 1)
^ (hash<int>()(k.third) << 1);
}
};
}
Standart şablonu kullanırken kendi sınıflarımızı nasıl karılacağını anlamaya çalışanlarımız için basit bir çözüm var:
Sınıfınızda bir eşitlik operatörü aşırı yüklemesi tanımlamanız gerekir ==
. Bunu nasıl yapacağınızı bilmiyorsanız, GeeksforGeeks'in harika bir öğreticisi var https://www.geeksforgeeks.org/operator-overloading-c/
Standart ad alanı altında, tür olarak sınıf adınızla hash adında bir şablon yapısı bildirin (aşağıya bakın). XOR ve bitshifting kullanarak hash hesaplamanın bir örneğini de gösteren harika bir blog yazısı buldum, ancak bu sorunun kapsamı dışında, ancak aynı zamanda hash işlevlerini nasıl kullanacağınız hakkında ayrıntılı talimatlar da içeriyor https://prateekvjoshi.com/ 2014/06/05 / kullanarak karması fonksiyonlu-in-c-için kullanıcı tanımlı-sınıfları /
namespace std {
template<>
struct hash<my_type> {
size_t operator()(const my_type& k) {
// Do your hash function here
...
}
};
}
std::map
ya std::unordered_map
tıpkı normalde yapacağını ve kullanım my_type
anahtarı olarak, standart kütüphane otomatik karma Sizin (2. adımda) önce tanımlanmış karma işlevi kullanacak senin anahtarların.#include <unordered_map>
int main() {
std::unordered_map<my_type, other_type> my_map;
}