Kolejka, która powszechnie jest używana w programowaniu, może zapisywać dane na tablicy o stałej długości. Taka implementacja ma pewne ograniczenia, ale też zalety.
Kolejka jest to struktura danych, która pozwala na:
Elementy w kolejce wychodzą w takiej samej kolejności w jakiej nadeszły, więc dodając do kolejki 1, 2, 3, 4 elementy będą później zdjęte w tej samej kolejności.
Chcą skorzystać z tablicy jak kolejki potrzebne są dwa indeksy oraz rozmiar tablicy. Pierwszy indeks wskazuje, gdzie w tablicy znajduje się pierwszy, nieodczytany element w tablicy. Dalej będziemy go nazywać "Początek". Z kolei drugi indeks wskazuje miejsce zapisu następnego elementu i nazwiemy go "Koniec".
Kiedy "Początek" i "Koniec" są indeksami o tej samej wartości to oznacza, że kolejka jest pusta. Ze względu na to, że tablica ma określony rozmiar to może dojść do sytuacji, gdy nie będzie można zapisać kolejnego elementu. Kolejka będzie pełna, gdy wstawienie kolejnego elementu przesunęłoby indeks "Koniec" tam gdzie znajduje się "Początek". Na podstawie pozycji indeksów można też obliczyć ile w kolejce znajduje się elementów.
Wadą opierania implementacji kolejki o tablicę jest ograniczona pojemność oraz stałe zużycie pamięcie niezależnie od tego jaki będzie maksymalny rozmiar kolejki. Warto jednak zauważyć, że po zaalokowaniu pamięci kolejka zawsze gwarantuje określoną podczas tworzenia ilość pozycji. Wybór pomiędzy kolejką dynamiczną, a statyczną należy wybrać w zależności od projektu.
Przypuśćmy, że mamy kolejkę, która może pomieścić maksymalnie trzy elementy. Wtedy dane o kolejce będą się zmieniać następująco:
Kolejka | Początek | Koniec | Operacja |
---|---|---|---|
[*, -, -] | 0 | 0 | Dodaj(4), umieści 4 w kolejce i zwiększy indeks "Koniec" |
[4, *, -] | 0 | 1 | Dodaj(5) |
[4, 5, *] | 0 | 2 | Usuń() zwróci 4 |
[*, 5, 8] | 1 | 2 | Dodaj(8) |
[*, 5, 8] | 1 | 0 | Dodaj(cokolwiek) zwróci błąd, ponieważ kolejka jest pełna |
[*, 5, 8] | 1 | 0 | Usuń() zwróci element o indeksie 1 czyli 5 |
[*, -, 8] | 2 | 0 | Usuń() zwróci 8 |
[*, -, -] | 0 | 0 | Kolejka jest pusta |
W powyższym schemacie przez gwiazdkę * została oznaczona pozycja indeksu "Koniec" w przypadku, gdy po niej nie występuje puste pole to do kolejki nie może zostać dołączony nowy element.
Celem implementacji jest utworzenie klasy Kolejka, która pozwoli na przechowywanie liczb całkowitych. W przypadku, gdy operacja nie będzie możliwa zostanie zwrócony odpowiedni błąd. Poniższy kod jest przykładowy.
W części prywatnej klasy muszą się znaleźć: tablica do zapisu danych, indeksy oraz rozmiar tablicy.
Kolejka nie będzie działać poprawnie jeśli wartości na początku nie zostaną poprawnie ustawione. Konstruktor będzie przyjmować jeden argument: rozmiar kolejki. Oba indeksy najlepiej jest ustawić na ten sam indeks 0, a tablicę należy przygotować pod zapisanych. Rozmiar deklarowanej tablicy jest o 1 większy niż podany argument w konstruktorze.
Następnie można zaimplementować dwie funkcje, które będą sprawdzać czy kolejka jest pusta czy pełna. Zostaną one wykorzystane podczas odczytu / zapisu, aby uniknąć nieprawidłowej operacji.
Dopóki indeks "Koniec" kolejki jest większy niż indeks "Początek" to długość kolejki to różnica tych dwóch indeksów. Należy jednak pamiętać, że indeksy zmieniają się cyklicznie, więc w pewnym momencie zajdzie odwrotna relacja i "Koniec" znajdzie się przed "Początkiem". Wtedy należy ich sumę odjąć od rozmiaru tablicy.
Funkcja Dodaj() przyjmuje jeden argument - liczbę, która ma zostać umieszczona w kolejce. Przed dopisaniem elementu do tablicy należy upewnić się, że kolejka nie jest pełna. Inaczej po dodaniu większej ilości elementów niż tablica ma rozmiar dojdzie do nadpisywania danych. Pod dopisaniu elementu wystarczy przesunąć indeks "Koniec" o jedno miejsce w prawo.
Analogicznie podczas usuwania funkcja Usun() musi sprawdzić czy kolejka nie jest pusta. Jeśli tak to musi zgłosić wyjątek. W przeciwnym razie pobiera odpowiedni element, zwiększa indeks "Początek" i zwraca odczytaną wartość.
Do zwiększania indeksu o 1 została napisana specjalna funkcja Zwieksz(), która ma za zadanie pilnować, aby indeks był poprawnym indeksem pewnego elementu z tablicy.
Do przetestowania napisanej klasy wystarczy poniższy kod:
Po uruchomieniu zwróci ona następujący wynik:
Klasa działa poprawnie. Początkowo program próbuje zapisać 6 elementów, ale przy szóstym zgłaszany zostaje wyjątek. Następnie jeden element zostaje zdjęty i ponownie włożony. Przed i po tej części długość tablicy nie powinna się zmienić. Sprawdzane jest tutaj obliczanie długości kolejki dla indeksów o różnych relacjach. Następnie zwrócone są kolejno elementy 1, 2, 3, 4, 0, a przy próbie odczytu kolejnego zostaje zgłoszony wyjątek.