Hash Map
Son güncelleme
Bir hash map anahtar-değer çiftlerini saklar ve bir değeri anahtarına göre ortalama O(1) sürede aramanıza olanak tanır. Tam olarak bir hash tablosu gibi çalışır, ancak her kova girdisi hem bir anahtarı hem de ona bağlı değeri taşır. Bir çifti saklamak veya getirmek için anahtar bir kova indeksine hash'lenir, ardından eşleşen anahtar için o kovanın zinciri taranır. Çiftlerin hash'lenmiş kovaya yerleştirilmesini ve bir değerin anahtarına göre getirilmesini izlemek için yukarıdaki oynat düğmesine basın.
Bu, Python'daki dict, Java'daki HashMap ve JavaScript'teki Map/nesnelerin arkasındaki yapıdır. Çakışmalar bir hash tablosundaki gibi ele alınır - burada ayrık zincirleme ile - bu yüzden performans iyi bir hash fonksiyonuna ve düşük bir yük faktörüne bağlıdır.
Zaman karmaşıklığı
| İşlem | Ortalama | En kötü durum |
|---|---|---|
| Ekle/güncelle (put) | O(1) | O(n) |
| Ara (get) | O(1) | O(n) |
| Sil | O(1) | O(n) |
| Alan | O(n) | O(n) |
Yaygın dillerde hash map
| Dil | Tür |
|---|---|
| Python | dict |
| Java | HashMap |
| JavaScript | Map / nesne |
| C++ | std::unordered_map |
| Go | map |
Çözümlü örnek
("cat", 3), ("dog", 5), ("cat", 9), ("emu", 7) çiftlerinin 8 kovalı bir haritaya hash(key) % 8 kullanılarak eklenmesi. hash("cat") % 8 = 2, hash("dog") % 8 = 5, hash("emu") % 8 = 2 olduğunu varsayalım:
| Adım | Yapı | İşlem |
|---|---|---|
Put ("cat", 3) | kova 2: [("cat", 3)] | Kova 2'ye hash'lenir; zincir boş, bu yüzden çift eklenir. |
Put ("dog", 5) | kova 2: [("cat", 3)], kova 5: [("dog", 5)] | Kova 5'e hash'lenir; zincir boş, bu yüzden çift eklenir. |
Put ("cat", 9) | kova 2: [("cat", 9)], kova 5: [("dog", 5)] | Kova 2'ye hash'lenir; "cat" anahtarı zaten zincirde, bu yüzden değeri 9 olarak güncellenir. |
Put ("emu", 7) | kova 2: [("cat", 9), ("emu", 7)], kova 5: [("dog", 5)] | Kova 2'ye hash'lenir; "cat" ile çakışır, anahtar bulunamaz, bu yüzden çift eklenir. |
Get "emu" | kova 2: [("cat", 9), ("emu", 7)] | Kova 2'ye hash'lenir; zincir taranır, "cat" atlanır, "emu" eşleşir, 7 döndürülür. |
Ne zaman hash map kullanmalı
| Şu durumda kullanın | Şu durumda kaçının |
|---|---|
Kesin bir anahtara göre ortalama O(1) arama, ekleme ve silme gerektiğinde. | Anahtarları sıralı tutmanız veya aralık sorguları gerektiğinde - dengeli bir BST veya sıralı harita kullanın. |
| Anahtarlar hash'lenebilir ve eşitlik iyi tanımlıysa (dizgeler, tam sayılar, demetler). | Anahtarlar değişebilir ve eklemeden sonra değişebiliyorsa, bu da kovalarını bozar. |
| Bir tanımlayıcıya göre sayım, tekilleştirme, önbellekleme veya indeksleme yapıyorsanız. | Amortize edilmiş ortalama sınırlar yerine en kötü durum O(log n) garantileri gerektiğinde. |
| Yineleme sırası önemli değilse veya ekleme sıralı bir harita yeterliyse. | Bellek çok kısıtlıysa - kovalar, yük faktörü payı ve işaretçiler ek yük getirir. |
Hash Map kodu
Python, JavaScript, Java, C++, C dillerinde temiz ve çalıştırılabilir bir Hash Map uygulaması. Bir dil seçin, kodu kopyalayın veya Coddy Playground'da hazır yüklenmiş olarak açın.
Python ile Hash Map kodu
1# Python's built-in dict is a hash map: O(1) average2# insert, lookup, and delete.3inventory = {"apple": 3, "banana": 7}4
5# Insert and update6inventory["cherry"] = 57inventory["apple"] += 28
9# Lookup, with .get for a safe default on missing keys10print("apple: ", inventory["apple"])11print("mango: ", inventory.get("mango", 0))12
13# Membership test and delete14print("banana in stock:", "banana" in inventory)15del inventory["banana"]16print("banana in stock:", "banana" in inventory)17
18# Iterate over key-value pairs19for fruit, count in sorted(inventory.items()):20 print(f"{fruit}: {count}")21
22# Classic hash map use case: counting frequencies23words = "the quick brown fox jumps over the lazy dog the end".split()24freq = {}25for word in words:26 freq[word] = freq.get(word, 0) + 127
28print("Occurrences of the:", freq["the"])29print("Most common word: ", max(freq, key=freq.get))JavaScript ile Hash Map kodu
1// The built-in Map is the idiomatic hash map in JavaScript:2// any key type, insertion-ordered iteration, O(1) average lookups.3const ages = new Map();4
5ages.set("Alice", 30);6ages.set("Bob", 25);7ages.set("Carol", 35);8ages.set("Bob", 26); // set on an existing key updates the value9
10console.log("Bob:", ages.get("Bob"));11console.log("Has Dave?", ages.has("Dave"));12console.log("Size:", ages.size);13
14ages.delete("Carol");15console.log("Size after delete:", ages.size);16
17for (const [name, age] of ages) {18 console.log(`${name} is ${age}`);19}20
21console.log("Keys:", [...ages.keys()].join(", "));Java ile Hash Map kodu
1import java.util.HashMap;2import java.util.Map;3
4public class Main {5 public static void main(String[] args) {6 Map<String, Integer> ages = new HashMap<>();7 ages.put("Alice", 30);8 ages.put("Bob", 25);9 ages.put("Carol", 35);10
11 System.out.println("Bob -> " + ages.get("Bob"));12 System.out.println("contains Carol: " + ages.containsKey("Carol"));13 System.out.println("Dave or default: " + ages.getOrDefault("Dave", -1));14
15 // getOrDefault makes frequency counting a one-liner16 String[] words = {"apple", "banana", "apple", "cherry", "apple"};17 Map<String, Integer> counts = new HashMap<>();18 for (String w : words) {19 counts.put(w, counts.getOrDefault(w, 0) + 1);20 }21 System.out.println("apple count: " + counts.get("apple"));22
23 ages.remove("Bob");24 System.out.println("size after remove: " + ages.size());25
26 for (Map.Entry<String, Integer> entry : ages.entrySet()) {27 System.out.println(entry.getKey() + " is " + entry.getValue());28 }29 }30}C++ ile Hash Map kodu
1#include <algorithm>2#include <iostream>3#include <string>4#include <unordered_map>5#include <vector>6
7int main() {8 std::unordered_map<std::string, int> ages;9
10 // Insert and update11 ages["alice"] = 30; // operator[] inserts or overwrites12 ages.insert({"bob", 25}); // insert keeps an existing value13 ages.emplace("carol", 41);14 ages["alice"] = 31;15
16 // Lookup17 auto it = ages.find("bob");18 if (it != ages.end()) {19 std::cout << "bob is " << it->second << "\n";20 }21 std::cout << "has dave: " << ages.count("dave") << "\n";22
23 // Remove24 ages.erase("carol");25
26 // Iterate (sort keys first: unordered_map has no defined order)27 std::vector<std::string> keys;28 for (const auto& entry : ages) keys.push_back(entry.first);29 std::sort(keys.begin(), keys.end());30 for (const std::string& name : keys) {31 std::cout << name << " = " << ages[name] << "\n";32 }33 std::cout << "size: " << ages.size() << "\n";34 return 0;35}C ile Hash Map kodu
1#include <stdbool.h>2#include <stdio.h>3#include <stdlib.h>4#include <string.h>5
6#define BUCKETS 167
8typedef struct Node {9 char key[24];10 int value;11 struct Node* next;12} Node;13
14// A small string -> int hash map with a reusable put/get/remove API15typedef struct {16 Node* buckets[BUCKETS];17 int size;18} HashMap;19
20unsigned int hashKey(const char* key) {21 unsigned int h = 5381;22 for (; *key; key++) h = h * 33 + (unsigned char)*key;23 return h % BUCKETS;24}25
26void mapPut(HashMap* map, const char* key, int value) {27 unsigned int i = hashKey(key);28 for (Node* n = map->buckets[i]; n != NULL; n = n->next) {29 if (strcmp(n->key, key) == 0) {30 n->value = value;31 return;32 }33 }34 Node* n = malloc(sizeof(Node));35 strcpy(n->key, key);36 n->value = value;37 n->next = map->buckets[i];38 map->buckets[i] = n;39 map->size++;40}41
42bool mapGet(const HashMap* map, const char* key, int* out) {43 for (Node* n = map->buckets[hashKey(key)]; n != NULL; n = n->next) {44 if (strcmp(n->key, key) == 0) {45 *out = n->value;46 return true;47 }48 }49 return false;50}51
52void mapRemove(HashMap* map, const char* key) {53 Node** link = &map->buckets[hashKey(key)];54 while (*link != NULL) {55 if (strcmp((*link)->key, key) == 0) {56 Node* old = *link;57 *link = old->next;58 free(old);59 map->size--;60 return;61 }62 link = &(*link)->next;63 }64}65
66int main(void) {67 HashMap map = {0};68 mapPut(&map, "alice", 30);69 mapPut(&map, "bob", 25);70 mapPut(&map, "carol", 41);71 mapPut(&map, "alice", 31); // updates the existing key72 int age;73 if (mapGet(&map, "bob", &age)) printf("bob is %d\n", age);74 printf("has dave: %s\n", mapGet(&map, "dave", &age) ? "yes" : "no");75 mapRemove(&map, "carol");76 printf("size: %d\n", map.size);77 return 0;78}Hash Map SSS
Hash map ile hash tablosu arasındaki fark nedir?
Bir hash map'in zaman karmaşıklığı nedir?
O(1)'dir. Tüm anahtarların tek bir kovada çakıştığı patolojik durumda O(n)'e düşerler, bu yüzden yeniden boyutlandırma ve iyi hashing önemlidir.Bir hash map, aynı kovaya hash'lenen iki anahtarı nasıl ele alır?
Hash map ve ikili arama ağacı: hangisini kullanmalıyım?
O(1) işlemler istediğinizde bir hash map kullanın. Sıralı anahtarlar, aralık sorguları veya öncül/ardıl aramaları gerektiğinde dengeli bir ikili arama ağacı (TreeMap veya std::map gibi) kullanın; bunlar O(log n) maliyetlidir. BST, bir hash map'in sağlayamayacağı sıralama garantileri için biraz hızdan ödün verir.Yük faktörü nedir ve neden yeniden boyutlandırmayı tetikler?
0.75 gibi bir eşiği aştığında yeniden boyutlandırır (tipik olarak kovaları ikiye katlar ve her şeyi yeniden hash'ler). Yeniden boyutlandırma O(n)'dir ama nadirdir, bu yüzden amortize edilir ve ortalama işlemleri O(1)'de tutar.Liste gibi değiştirilebilir bir nesneyi hash map anahtarı olarak kullanabilir miyim?
list için TypeError: unhashable type fırlatır. Bir anahtarı ekledikten sonra değiştirirseniz, hash'i değişir ve harita onu artık doğru kovada bulamaz, girdiyi sessizce kaybeder. Dizgeler, sayılar veya demetler gibi değişmez anahtarlar kullanın.