Dwa stosy można skutecznie zaimplementować za pomocą jednej tablicy o stałym rozmiarze: stos nr 1 zaczyna się od lewego końca i rośnie w prawo, a stos nr 2 zaczyna się od prawego końca i rośnie w lewo. Czy to samo jest możliwe dla trzech stosów?
Mówiąc dokładniej, czy możliwe jest wdrożenie trzech stosów, biorąc pod uwagę następujące warunki:
- Masz tablicę o stałym rozmiarze, która może pomieścić N obiektów.
- Dopóki suma trzech rozmiarów stosu wynosi <N, push () nie powinien zawieść.
- Zarówno operacje push (), jak i pop () powinny zająć czas O (1).
- Oprócz tablicy możesz użyć tylko dodatkowego miejsca O (1).
Oto przykłady rozwiązań, które nie spełniają tych wymagań:
- Podział tablicy na 3 stałe części i użycie każdej części do stosu (narusza 2).
- Podobnie jak powyżej, ale z ruchomymi granicami między stosami (narusza 3).
- Proste implementacje oparte na listach połączonych (narusza 4).
Przyjmę nietrywialne algorytmy lub dowody niemożności, nawet jeśli nie spełniają one wszystkich warunków (1) - (4) dokładnie, na przykład algorytm, w którym push / pop zajmuje zamortyzowany czas O (1) lub gdzie dodatkowa pamięć jest mniejsza niż O (N), np. O (log N). Lub dowód niemożności, który pokazuje, że na przykład dostęp do mniej niż 5 elementów tablicy na push / pop jest niemożliwy.
źródło
Odpowiedzi:
Fredman i Goldsmith wykazali w „Three Stacks” (Journal of Algorithms, 1994), że możliwe jest osiągnięcie kawałków zmarnowanej przestrzeni. Jest to również minimum potrzebne dla tablic o rozmiarze co najmniej 16 quattuordecillion yottabajtów. Opisałem prosty algorytm marnujący słowa miejsca w mojej odpowiedzi StackOverflow na to pytanie . Jak wspomniano w komentarzach @ dmitri-urbanowicz, po prostu traktuje tablicę jako bloków o rozmiarze , gdzie każdy blok jest używany dla dokładnie jednego stosu i zawiera pojedynczy wskaźnik do następnego bloku w tym stosie.Θ(nε) Θ(n−−√) n−−√ n−−√
źródło
Niech N będzie długością podstawowej tablicy. Mogę sobie wyobrazić stosy jako połączone listy dużych porcji, dzięki czemu ogólna liczba porcji nie będzie większa niż O (log2 (N)). Umieść trzeci stos między pierwszymi dwoma, o indeksie N / 2. Mamy więc 3 zajęte obszary i 2 bezpłatne. Jeśli stos nie może przyjąć następnego elementu, oznacza to, że jeden wolny obszar jest wyczerpany. Jeśli druga też się wyczerpie, cała pamięć zostanie wyczerpana. W przeciwnym razie istnieje inny wolny obszar o rozmiarze nie większym niż N / 2. Kontynuuj przepełniony stos w tym wolnym obszarze. dzięki czemu cała konfiguracja przypomina początkowy układ stosów. Ponieważ wolna pamięć jest teraz nie większa niż połowa początkowej, nie będzie więcej niż log2 (N) takich operacji łączenia. Każda operacja łączenia wymaga stałej ilości pamięci, aby zapisać poprzedni stan stosu. Więc,
źródło