Strona głównaArtykułyAlgorytmy

Skippowane listy: dyskretnie zastępcze ścieżki nad połączoną listą

Rzut monetą decyduje o promocji, a wynik daje strukturę równoważną bez żadnych obrótów.

mysimulator teamZaktualizowano — czerwiec 2026≈ 7 min czytania▶ Otwórz symulację

Idea: tunelery nad posortowaną listą

Posortowana lista jednokierunkowa sprawia, że wyszukiwanie ma złożoność O(n): możesz poruszać się w dół tylko jednym węzłem na raz. Lista skippowana Williamego Pugh'a (1989) poprawia to tworząc dodatkowe

Tworzenie poziomów z rzutu monetą

Wysokość każdego węzła jest decydujona niezależnie, podczas wstawiania, przez powtarzane rzuty monetą: z prawdopodobieństwem p (zazwyczaj 1/2) jest przenoszone do kolejnego poziomu wyżej, a następnie to się powtarza, dopóki rzut nie przestanie się udawać. Brak globalnej balansowania, brak rotacji, brak kolorów — równowaga struktury wynika jedynie z prawdopodobieństwa.

randomLevel(p = 0.5, maxLevel):
  level = 1
  while random() < p and level < maxLevel:
    level += 1
  return level

insert(key):
  level = randomLevel()
  find the predecessor node at each level 1..level (search path)
  splice the new node into the forward pointers at each of those levels
demo na żywo · powiązana symulacja● LIVE

Dlaczego oczekiwany czas wyszukiwania wynosi O(log n)

Z p = 1/2, około połowa węzłów na każdym poziomie jest przenoszona do kolejnego poziomu wyższego, więc oczekiwana liczba węzłów na poziomie k wynosi n/2^(k-1) — a oczekiwany najwyższy poziom wynosi około log2(n). Wyszukiwanie rozpoczęte od najwyższego poziomu i przesuwające się prawo-obocze lub w dół na każdym kroku zajmuje oczekiwane O(1) kroki na poziom (argument geometryczny ogranicza liczbę ruchów w prawo przed opuszczeniem poziomu), dla całkowitej oczekiwanej kosztu O(log n) na wszystkich poziomach. To odzwierciedla analizę równoważnego drzewa binarnego niemal dokładnie, ale z losowością w miejsce jasno określonego warunku balansowania.

Skip lists w porównaniu do drzew równych

Kompromis, jaki robią skippowane listy, jest szczerzy: zastępują gwarancję najgorszego przypadku na znacznie prostszą implementację. Wstawianie i usuwanie w skippowanej liście to tylko łączenie i odłączanie wskaźników po już znalezionym ścieżce wyszukiwania — bez rotacji, recoloringa ani cascadowych napraw. Ta prostość jest najważniejsza w kodzie równoległym, gdzie bezpieczna lub z graniastosłupowymi blokadami skippowana lista jest znacznie łatwiejsza do prawidłowej implementacji niż drzewo równoczesne bez blokady, ponieważ aktualizacje na różnych poziomach często mogą się przeprowadzać niezależnie.

Gdzie są wykorzystywane w produkcyjnych systemach

Redis implementuje typ zagnieżdżony (ZSET) za pomocą listy skippowanej połączonej z tabelą hash, konkretnie dlatego, że listy skippowane ułatwiają realizację zapytań zakresowych ("podaj mi 10 najwyższych wyników") i wykonywanie operacji rankingu wraz z czasowym złożonościem O(log n) do wstawiania i usuwania. Wiele silników magazynowania opartych na drzewach LSM, w tym memtable w LevelDB i RocksDB, używa listy skippowanej jako buforu uporządkowanego w pamięci, do którego zapisy przychodzące docierają przed usunięciem do dysku, co ponownie przeważy prostota i współbieżne zapisy bez blokady nad szybszym drzewem równoważnym.

Często zadawane pytania

Czy poszukiwanie w liście skokowej o złożoności O(log n) jest gwarantowane?

Tylko w średnim przypadku, a nie w najgorszym. Ponieważ promocja poziomu to rzut monetą, możliwe jest, że bardzo nie szczęśliwa seria rzutów pozostawi wszystkie węzły na poziomie 1, co może spowodować, że poszukiwanie stanie się O(n). W praktyce prawdopodobieństwo tego jest astronomicznie małe i maleje eksponencjalnie z n, dlatego liście skokowe są traktowane jako O(log n) dla wszystkich praktycznych celów, z małą, dobrze zrozumiałą zmienną czynnika.

Dlaczego używać listy skokowej zamiast drzewa równoważnego?

Lista skokowa nie wymaga rotacji ani bitów kolorowych, a także nie ma logiki do sprawdzania równowagi — wstawianie i usuwanie są prosimi aktualizacjami lokalnych wskaźników po znalezieniu ścieżki poszukiwania, co ułatwia jej implementację prawidłową, szczególnie w zasadniczo nieblokującym lub współczesnym kontekście, gdzie równoważenie drzewa pod wpływem zmian współczesnych jest znane jako trudne. Koszt to mała ilość dodatkowej pamięci dla wskaźników przód na promowanych węzłach oraz graniczące z prawdopodobieństwiste, a nie gwarantowane, ograniczenia najgorszego przypadku.

Co determinuje liczbę poziomów potrzebnych przez listę skokową?

Z prawdopodobieństwem promocji p = 1/2, oczekiwana liczba poziomów dla n elementów wynosi około log2(n), ponieważ każdy poziom zawiera w przybliżeniu połowę węzłów co do tego poniżej. Implementacje ograniczają maksymalny poziom do czegoś w rodzaju log(1/p) oczekiwanej maksymalnej n (często 16 lub 32) jedynie z myślą o granicach pamięci, ponieważ poziomy ponad to są niemal nieistotnie nieprzeznaczone do użycia.

Wypróbuj na żywo

Wszystko powyżej działa bezpośrednio w Twojej przeglądarce — otwórz Skip List — Probabilistic Balanced Search i zmieniaj parametry podczas działania. Nic nie jest instalowane ani przesyłane na serwer, cały model działa w jednej karcie.

▶ Otwórz symulację Skip List — Probabilistic Balanced Search

Co znalazłeś?

Dodaj kroki odtworzenia (opcjonalnie)