Найти Π² Π”Π·Π΅Π½Π΅
АлСксСй Никитин

πŸ— Π₯Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ β€” быстрый поиск ΠΏΠΎ ΠΊΠ»ΡŽΡ‡Ρƒ Π±Π΅Π· ΠΌΠ°Π³ΠΈΠΈ

πŸ—Β Π₯Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹Β β€” быстрый поиск ΠΏΠΎΒ ΠΊΠ»ΡŽΡ‡Ρƒ Π±Π΅Π·Β ΠΌΠ°Π³ΠΈΠΈ Π‘Π°ΠΌΡƒΡ€Π°ΠΉ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ Π²Β Π΄ΠΎΠ΄Π·Ρ‘, Π½Π°Π·Ρ‹Π²Π°Π΅Ρ‚ своё имя β€” Ρ…Ρ€Π°Π½ΠΈΡ‚Π΅Π»ΡŒ сразу Π²Ρ‹Π΄Π°Ρ‘Ρ‚ ΠΊΠ°Ρ‚Π°Π½Ρƒ ΠΈΠ·Β Π½ΡƒΠΆΠ½ΠΎΠΉ ячСйки. Как ΠΎΠ½ Π½Π°ΡˆΡ‘Π» ΠΌΠ΅Ρ‡ Π²Β ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΉ ΠΎΡ€ΡƒΠΆΠ΅ΠΉΠ½ΠΎΠΉ Π·Π° долю сСкунды? ΠžΡ‚Π²Π΅Ρ‚Β β€” Ρ…Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Π°. πŸ””Β Π’Ρ‹ΠΏΡƒΡΠΊ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Π²Ρ‚ΠΎΡ€Π½ΠΈΠΊ. Π”Π΅Π»ΠΈΡ‚Π΅ΡΡŒ постом, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡƒΡ‚ΡŒ код‑самурая рос! βΈ» 1. Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ Ρ…Π΅Ρˆβ€‘Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ Π‘Π΅Ρ€Ρ‘ΠΌ ΠΊΠ»ΡŽΡ‡ β†’ запускаСм Π±Ρ‹ΡΡ‚Ρ€ΡƒΡŽ ΠΌΠ°Ρ‚Π΅ΠΌΠ°Ρ‚ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ β†’ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ число‑индСкс. ΠšΠ»ΡŽΡ‡ΠΈ Ρ€Π°Π·Π½Ρ‹Ρ… Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠ² (строки, числа) ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ в фиксированноС Ρ†Π΅Π»ΠΎΠ΅. Π“Π»Π°Π²Π½ΠΎΠ΅ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠ΅Β β€” быстро ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ€Π°Π²Π½ΠΎΠΌΠ΅Ρ€Π½ΠΎ Ρ€Π°ΡΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡ΠΈ. 2. Как Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ поиск O(1) 1. Π’Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚ΡŒ индСкс: index = hash(key) % N (NΒ β€” Π΄Π»ΠΈΠ½Π° Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π³ΠΎ массива). 2. ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΏΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŽ сразу к ячСйкС index. 3. Π‘Ρ€Π°Π²Π½ΠΈΡ‚ΡŒ Ρ…Ρ€Π°Π½ΠΈΠΌΡ‹ΠΉ ΠΊΠ»ΡŽΡ‡ с искомым: Ссли совпал — Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅. Π’Π°ΠΆΠ½ΠΎ: O(1) β€” срСднСС врСмя. Π’Β ΠΊΡ€Π°ΠΉΠ½ΠΈΡ… случаях (всС ΠΊΠ»ΡŽΡ‡ΠΈ ΡΡ‚ΠΎΠ»ΠΊΠ½ΡƒΠ»ΠΈΡΡŒ) ΠΌΠΎΠΆΠ΅Ρ‚ вырасти Π΄ΠΎΒ O(n), Π½ΠΎΒ ΠΏΡ€ΠΈ Ρ…ΠΎΡ€ΠΎΡˆΠ΅ΠΉ Ρ…Π΅Ρˆβ€‘Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ это Ρ€Π΅Π΄ΠΊΠΎΡΡ‚ΡŒ. 3. ΠšΠΎΠ»Π»ΠΈΠ·ΠΈΠΈΒ β€” ΠΊΠΎΠ³Π΄Π° Π΄Π²Π° ΠΊΠ»ΡŽΡ‡Π° ΠΏΠ°Π΄Π°ΡŽΡ‚ Π²Β ΠΎΠ΄ΠΈΠ½ индСкс Бпособы лСчСния: β€’ Π¦Π΅ΠΏΠΎΡ‡ΠΊΠΈΒ (Chaining

πŸ—Β Π₯Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹Β β€” быстрый поиск ΠΏΠΎΒ ΠΊΠ»ΡŽΡ‡Ρƒ Π±Π΅Π·Β ΠΌΠ°Π³ΠΈΠΈ

Π‘Π°ΠΌΡƒΡ€Π°ΠΉ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ Π²Β Π΄ΠΎΠ΄Π·Ρ‘, Π½Π°Π·Ρ‹Π²Π°Π΅Ρ‚ своё имя β€” Ρ…Ρ€Π°Π½ΠΈΡ‚Π΅Π»ΡŒ сразу Π²Ρ‹Π΄Π°Ρ‘Ρ‚ ΠΊΠ°Ρ‚Π°Π½Ρƒ ΠΈΠ·Β Π½ΡƒΠΆΠ½ΠΎΠΉ ячСйки. Как ΠΎΠ½ Π½Π°ΡˆΡ‘Π» ΠΌΠ΅Ρ‡ Π²Β ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΉ ΠΎΡ€ΡƒΠΆΠ΅ΠΉΠ½ΠΎΠΉ Π·Π° долю сСкунды? ΠžΡ‚Π²Π΅Ρ‚Β β€” Ρ…Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Π°.

πŸ””Β Π’Ρ‹ΠΏΡƒΡΠΊ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Π²Ρ‚ΠΎΡ€Π½ΠΈΠΊ. Π”Π΅Π»ΠΈΡ‚Π΅ΡΡŒ постом, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡƒΡ‚ΡŒ код‑самурая рос!

βΈ»

1. Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ Ρ…Π΅Ρˆβ€‘Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ

Π‘Π΅Ρ€Ρ‘ΠΌ ΠΊΠ»ΡŽΡ‡ β†’ запускаСм Π±Ρ‹ΡΡ‚Ρ€ΡƒΡŽ ΠΌΠ°Ρ‚Π΅ΠΌΠ°Ρ‚ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ β†’ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ число‑индСкс.

ΠšΠ»ΡŽΡ‡ΠΈ Ρ€Π°Π·Π½Ρ‹Ρ… Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠ² (строки, числа) ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ в фиксированноС Ρ†Π΅Π»ΠΎΠ΅. Π“Π»Π°Π²Π½ΠΎΠ΅ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠ΅Β β€” быстро ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ€Π°Π²Π½ΠΎΠΌΠ΅Ρ€Π½ΠΎ Ρ€Π°ΡΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡ΠΈ.

2. Как Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ поиск O(1)

1. Π’Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚ΡŒ индСкс: index = hash(key) % N (NΒ β€” Π΄Π»ΠΈΠ½Π° Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π³ΠΎ массива).

2. ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΏΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŽ сразу к ячСйкС index.

3. Π‘Ρ€Π°Π²Π½ΠΈΡ‚ΡŒ Ρ…Ρ€Π°Π½ΠΈΠΌΡ‹ΠΉ ΠΊΠ»ΡŽΡ‡ с искомым: Ссли совпал — Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

Π’Π°ΠΆΠ½ΠΎ: O(1) β€” срСднСС врСмя. Π’Β ΠΊΡ€Π°ΠΉΠ½ΠΈΡ… случаях (всС ΠΊΠ»ΡŽΡ‡ΠΈ ΡΡ‚ΠΎΠ»ΠΊΠ½ΡƒΠ»ΠΈΡΡŒ) ΠΌΠΎΠΆΠ΅Ρ‚ вырасти Π΄ΠΎΒ O(n), Π½ΠΎΒ ΠΏΡ€ΠΈ Ρ…ΠΎΡ€ΠΎΡˆΠ΅ΠΉ Ρ…Π΅Ρˆβ€‘Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ это Ρ€Π΅Π΄ΠΊΠΎΡΡ‚ΡŒ.

3. ΠšΠΎΠ»Π»ΠΈΠ·ΠΈΠΈΒ β€” ΠΊΠΎΠ³Π΄Π° Π΄Π²Π° ΠΊΠ»ΡŽΡ‡Π° ΠΏΠ°Π΄Π°ΡŽΡ‚ Π²Β ΠΎΠ΄ΠΈΠ½ индСкс

Бпособы лСчСния:

β€’ Π¦Π΅ΠΏΠΎΡ‡ΠΊΠΈΒ (Chaining)Β β€” в ячСйкС Ρ…Ρ€Π°Π½ΠΈΠΌ список записСй.

β€’ ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚Π°Ρ адрСсация — ΠΈΡ‰Π΅ΠΌ сосСднюю ΡΠ²ΠΎΠ±ΠΎΠ΄Π½ΡƒΡŽ ячСйку (Π»ΠΈΠ½Π΅ΠΉΠ½ΠΎΠ΅ ΠΈΠ»ΠΈ ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚ΠΈΡ‡Π½ΠΎΠ΅ ΠΏΡ€ΠΎΠ±ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅).

β€’ Π”Π²ΠΎΠΉΠ½ΠΎΠ΅ Ρ…Π΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅Β β€” ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π²Ρ‚ΠΎΡ€ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, Ссли пСрвая занята.

4. ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π½Π°Β PHP (ассоц‑массив ΡƒΠΆΠ΅ Ρ…Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Π°)

$userScores = [

'ryu' => 42,

'ken' => 39,

'akira' => 50,

];

// Π§Ρ‚Π΅Π½ΠΈΠ΅ O(1)

$score = $userScores['ryu'];

Бвоя Ρ…Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Π° с Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ°ΠΌΠΈ

class HashTable {

private array $buckets;

public function __construct(private int $size = 8) {

$this->buckets = array_fill(0, $size, []);

}

private function hash(string $key): int {

return crc32($key) % $this->size; // простая Ρ…Π΅Ρˆβ€‘Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ

}

public function put(string $key, mixed $value): void {

$i = $this->hash($key);

foreach ($this->buckets[$i] as &$pair) {

if ($pair[0] === $key) { $pair[1] = $value; return; }

}

$this->buckets[$i][] = [$key, $value];

}

public function get(string $key): mixed {

$i = $this->hash($key);

foreach ($this->buckets[$i] as $pair) {

if ($pair[0] === $key) return $pair[1];

}

return null; // not found

}

}

5. ΠŸΠ»ΡŽΡΡ‹ ΠΈ минусы

+ ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½Ρ‹ΠΉ доступ ΠΏΠΎ ΠΊΠ»ΡŽΡ‡Ρƒ (срСднСС O(1))

+ Π³ΠΈΠ±ΠΊΠΎΡΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ (строки, числа, UUID)

βˆ’ Π½Π΅Ρ‚ упорядочСнности, нСльзя ΠΈΡ‚Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Β«Π² отсортированном Π²ΠΈΠ΄Π΅Β»

βˆ’ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ большС памяти (пустыС ячСйки, списки ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΉ)

βˆ’ Π½ΡƒΠΆΠ½ΠΎ ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ Π·Π° load factor (>Β 0.75Β β€” Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅ΠΌ массив)

6. ΠœΠΈΠ½ΠΈβ€‘Ρ‡Π΅ΠΊβ€‘Π»ΠΈΡΡ‚: ΠΊΠΎΠ³Π΄Π° Π±Ρ€Π°Ρ‚ΡŒ Ρ…Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ?

β€’ НуТно быстро ΠΈΡΠΊΠ°Ρ‚ΡŒ, Π²ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ, ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ ΠΏΠΎΒ ΠΊΠ»ΡŽΡ‡Ρƒ.

β€’ Π Π°Π·ΠΌΠ΅Ρ€ Π΄Π°Π½Π½Ρ‹Ρ… растёт β€” Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ массива дСшСвлС, Ρ‡Π΅ΠΌ сортировка.

β€’ ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ элСмСнтов Π½Π΅Β Π²Π°ΠΆΠ΅Π½.

β€’ ΠŸΠ°ΠΌΡΡ‚ΡŒ Π½Π΅ Π²Β Π΄Π΅Ρ„ΠΈΡ†ΠΈΡ‚Π΅ (ΠΈΠ»ΠΈ ΠΊΡ€ΠΈΡ‚ΠΈΡ‡Π΅Π½ ΠΈΠΌΠ΅Π½Π½ΠΎ доступ).

πŸŒΒ ΠŸΡ€Π°ΠΊΡ‚ΠΈΡ‡Π΅ΡΠΊΠΈΠΉ кСйс: Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ Π΄ΡƒΠ±Π»ΠΈΠΊΠ°Ρ‚ΠΎΠ² ΠΏΡ€ΠΈ ΠΈΠΌΠΏΠΎΡ€Ρ‚Π΅ CSV

ΠŸΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ Ρ„Π°ΠΉΠ» Π²Β 100β€―000 строк: user_id;email. НуТно Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ, игнорируя Π΄ΡƒΠ±Π»ΠΈΠΊΠ°Ρ‚Ρ‹ ΠΏΠΎ email.Π‘Π΅Π· Ρ…Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΏΡ€ΠΈΡˆΠ»ΠΎΡΡŒΒ Π±Ρ‹ Π½Π°Β ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Π½ΠΎΠ²Ρ‹ΠΉ email Π΄Π΅Π»Π°Ρ‚ΡŒ in_array() ΠΏΠΎ растущСму списку (O(nΒ²)).Π‘ Ρ…Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ (ассоциативным массивом‑мноТСство) провСряСм Π½Π°Π»ΠΈΡ‡ΠΈΠ΅ Π·Π° O(1).

$seen = [];

foreach ($rows as $row) {

[$id, $email] = $row;

if (isset($seen[$email])) {

// ΡƒΠΆΠ΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π»ΠΈ β€” пропускаСм

continue;

}

$seen[$email] = true; // mark

saveUser($id, $email);

}

PHP‑массив здСсь ΠΈ Π΅ΡΡ‚ΡŒ Ρ…Π΅Ρˆβ€‘Ρ‚Π°Π±Π»ΠΈΡ†Π°: ΠΊΠ»ΡŽΡ‡ email прогоняСтся Ρ‡Π΅Ρ€Π΅Π· Π²ΡΡ‚Ρ€ΠΎΠ΅Π½Π½ΡƒΡŽ Ρ…Π΅Ρˆβ€‘Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, Π΄Π²ΠΈΠΆΠΎΠΊ сразу Π·Π½Π°Π΅Ρ‚, Π² ΠΊΠ°ΠΊΠΎΠΉ Β«ΠΊΠΎΡ€Π·ΠΈΠ½Π΅Β» Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΊΡƒ. На ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅ Ρ‚Π°ΠΊΠΎΠΉ ΠΏΡ€ΠΈΡ‘ΠΌ ускоряСт ΠΈΠΌΠΏΠΎΡ€Ρ‚ с ΠΌΠΈΠ½ΡƒΡ‚ Π΄ΠΎ сСкунд.

βΈ»

❓ Вопрос ΠΊ читатСлям: ΠΊΠ°ΠΊΠΈΠ΅ Π½Π΅ΠΎΠΆΠΈΠ΄Π°Π½Π½Ρ‹Π΅ Ρ…Π΅Ρˆβ€‘Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ встрСчали Π²Β ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°Ρ…? Π”Π΅Π»ΠΈΡ‚Π΅ΡΡŒ Π² коммСнтариях!

#Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΡ‹Β #Ρ…Π΅ΡˆΡ‚Π°Π±Π»ΠΈΡ†Π°Β #phpΒ #кодБамурая