Grzegorz Wasylów Konrad Wojtoń Lista dwukierunkowa Lista dwukierunkowa to nic innego jak modyfikacja listy jednokierunkowej. Zaletą takiej listy jest możliwość przejścia nie tylko do następnego elementu, ale i także do poprzedniego elementu w zbiorze danych tzw. liście. Definicja listy: listą będziemy nazywali zestaw liniowo powiązanych ze sobą pól dowolnego typu. Lub też prościej: lista jest w pewnym sensie odpowiednikiem wektora. Cechy wspólne z nim to: liniowe uporządkowanie - zarówno w liście, jak i w wektorze każdy element z wyjątkiem pierwszego i ostatniego ma poprzednika i następnika, obie struktury są jednowymiarowe i o uporządkowanej kolejności. Różnice: z punktu widzenia użytkownika wektor jest strukturą danych o swobodnym dostępie (możemy odwołać się bezpośrednio do dowolnego elementu poprzez jego numer), natomiast dostęp do danych pamiętanych na liście jest sekwencyjny (można odwołać się jedynie do elementów sąsiadujących z aktualnym). Z punktu widzenia systemu operacyjnego, wektor jest ciągłym obszarem pamięci, natomiast lista jest zestawem powiązanych ze sobą, nieciągłych fragmentów umieszczonych w różnych obszarach RAM. Operujemy tutaj głównie na wskaźnikach, dzięki którym znamy poszczególne adresy w pamięci następnego i poprzedniego elementu listy. Język Pascal udostępnia nam możliwość sprawdzenia offsetu pamięci: writeln(ofs(wskaznik^.dane)); Dzięki temu możemy zauważyć, że rezerwowana jest zawsze dokładnie taki sam przedział pamięci na każdy element, w związku z czym łatwo jest obliczyć rozmiar pamięci, czy też położenie danego elementu w liście. Za pomocą procedur new() oraz dispose() dowolnie sterujemy pamięcią komputera poprzez tworzenie miejsca w pamięci i jego zwalnianie. Jest to bardzo istotne podczas dynamicznego tworzenia elementów listy w pamięci. Schemat listy dwukierunkowej: x = nil = wskaźnik
Do listy możemy dodawać nowe elementy, usuwać oraz przeszukiwać ją. Poniżej przedstawione są schematy takich działań: Dodawanie nowego elementu: Usuwanie elementu: Przeszukiwanie listy polega na tym aby sprawdzić w warunku pętli każdy z elementów listy, tj. porównać go wraz z wzorcem szukanym. Należy zmieniać indeks elementu, tzn. musimy wskazywać na wskaźnik do następnego elementu listy, aby zachować jej ciągłość i poprawne działanie. Źródło programu: http://ux.ap.krakow.pl/~blur/alg_and_structs/pro/ Listing programu: {--------------------------------------------------------------------------------} program dwukierunkowa; uses crt; const N = 15; type wsklista = ^element; element = record dane : integer; wskpoprzednika : wsklista; wsknastepnika : wsklista;
type nodelist = ^e; e = record first : wsklista; last: wsklista; aktualny: wsklista; lista: nodelist; wartosc : integer; co: char; procedure showactual( lista: nodelist); writeln(lista^.aktualny^.dane); procedure createlist( lista : nodelist); lista^.first := nil; lista^.last := nil; lista^.aktualny := nil; procedure deletelist( lista : nodelist); tmp: wsklista; lista^.aktualny := lista^.first; while lista^.aktualny <> nil do tmp := lista^.aktualny^.wsknastepnika; lista^.aktualny := tmp; procedure search( lista : nodelist; szukana : integer); lista^.aktualny := lista^.first; while lista^.aktualny <> nil do if(lista^.aktualny^.dane = szukana) then writeln('szukana liczba: ',szukana,' znaleziona w liscie'); break; lista^.aktualny := lista^.aktualny^.wsknastepnika; if(lista^.aktualny) = nil then writeln('nie znaleziono ', szukana);
procedure readlist( lista : wsklista); tmp : wsklista; writeln('zawartosc Listy'); tmp := lista; while tmp <> nil do write(' => ',tmp^.dane); tmp := tmp^.wsknastepnika; writeln; procedure pushfront( lista : nodelist; nowy: wsklista); lista^.first := nowy; nowy^.wsknastepnika := lista^.aktualny; lista^.aktualny^.wskpoprzednika := nowy; nowy^.wskpoprzednika := nil; lista^.aktualny := nowy; procedure pushinside( lista : nodelist; nowy: wsklista); lista^.aktualny^.wskpoprzednika^.wsknastepnika := nowy; nowy^.wsknastepnika := lista^.aktualny; nowy^.wskpoprzednika := lista^.aktualny^.wskpoprzednika; lista^.aktualny^.wskpoprzednika := nowy; procedure pushend( lista: nodelist; nowy: wsklista); if lista^.first = nil then lista^.first := nowy lista^.last^.wsknastepnika := nowy; nowy^.wskpoprzednika := lista^.last; lista^.last := nowy; procedure push( lista: nodelist; wart: integer); nowy: wsklista; new(nowy); nowy^.dane := wart; if lista^.aktualny <> nil then if lista^.aktualny = lista^.first then pushfront(lista, nowy) pushinside(lista, nowy) pushend(lista, nowy) procedure popfront( lista: nodelist);
lista^.first := lista^.first^.wsknastepnika; write('usunieto aktualny czyli '); showactual(lista); lista^.aktualny := lista^.first; if lista^.first <> nil then lista^.first^.wskpoprzednika := nil lista^.last := nil procedure popinside( lista: nodelist); tmp: wsklista; tmp := lista^.aktualny^.wskpoprzednika; tmp^.wsknastepnika := lista^.aktualny^.wsknastepnika; lista^.aktualny^.wsknastepnika^.wskpoprzednika := tmp; write('usunieto aktualny czyli '); showactual(lista); lista^.aktualny := tmp; procedure popend( lista: nodelist); tmp: wsklista; tmp := lista^.aktualny^.wskpoprzednika; tmp^.wsknastepnika := nil; lista^.last := tmp; write('usunieto aktualny czyli '); showactual(lista); lista^.aktualny := nil; procedure pop( lista : nodelist); {if lista^.aktualny = nil then} if lista^.aktualny = lista^.first then popfront(lista) if lista^.aktualny = lista^.last then popend(lista) popinside(lista) { main } new(lista); createlist(lista); repeat clrscr; writeln('d - dodaj do listy'); writeln('s - szukaj w liscie'); writeln('z - usun z listy aktualny');
writeln('w - wypisz liste'); writeln('q - koniec'); co:=readkey; case co of 'd': write('podaj warosc: '); read(wartosc); push(lista, wartosc); 's': writeln('wartosc szukana'); read(wartosc); search(lista, wartosc); co:=readkey; 'z': pop(lista); 'w': readlist(lista^.first); co:=readkey; until co='q'; deletelist(lista);. {--------------------------------------------------------------------------------}