Lista dwukierunkowa

background image

Lista

dwukierunkowa

PODSTAWOWE INFORMACJE, INTERPRETACJA
GRAFICZNA, PODSTAWOWE OPERACJE, IMPLEMENTACJA
W JĘZYKU C ORAZ NAJCZĘŚCIEJ WYSTĘPUJĄCE ZADANIA
ZWIĄZANE Z LISTĄ DWUKIERUNKOWĄ

Łukasz Krupa,

2014

1

background image

2

Podstawowe informacje

Niezbędne informacje, związane z listą, były przedstawione w pierwszej prezentacji pod tytułem „Lista

jednokierunkowa”.

Lista dwukierunkowa jest rozszerzeniem listy jednokierunkowej. W liście jednokierunkowej każdy element

listy zawierał dwa pola – klucz oraz adres_nast. Widzimy więc, że możemy poruszać się tylko w jedną stronę,

ponieważ nie mamy adresu elementu, występującego przed elementem n-tym. W związku z tym należało

cały czas przechowywać adres głowy listy, ponieważ w przypadku przesunięcia głowy o n elementów,

nieodwracalnie gubimy adresy n wcześniejszych elementów.

Lista dwukierunkowa, prócz pól klucz oraz adres_nast, zawierała będzie jeszcze jedno pole – adres_poprz.

Pozwoli to poruszać się po liście w dowolnym kierunku, a do początku listy będziemy mogli dojść z każdego

elementu listy (co w przypadku listy jednokierunkowej było niemożliwe).

Zgodnie z tym, co zostało powiedziane przy okazji omawiania listy jednokierunkowej, zmienna wskaźnikowa,

wskazująca na adres elementu następnego, zajmuje w pamięci 4b miejsca. Wzrasta zatem koszt pamięciowy

utrzymania listy dwukierunkowej – z 8 bajtów (lista jednokierunkowa) do 12 bajtów (lista dwukierunkowa).

Łukasz Krupa,

2014

background image

3

Łukasz Krupa,

2014

Interpretacja graficzna

Sposobów interpretacji graficznej listy dwukierunkowej jest taki sam, jak listy jednokierunkowej, z małym

rozszerzeniem o adres elementu poprzedniego.

Niech nasza lista przechowuje liczby całkowite (int). Zgodnie z tym, co zostało powiedziane w

wiadomościach wstępnych, lista zawiera daną, adres kolejnego elementu listy oraz adres wcześniejszego

elementu listy.

Niech pojedynczym elementem listy będzie kontener, zawierający trzy kieszenie – liczba, adres_nast oraz

adres_poprz:

Jak będzie wyglądać lista złożona z trzech elementów (kolejno) 3, 8, 15 ?

0xFB12

0

x

FA

4

1

Kolumna po lewo w każdym „kontenerze” to adres w pamięci, pod którym zapisany jest dany „kontener”.

3

NULL

0

x

FB

1

2

8

NULL

0

xF

F8

8

0xFF88

15

NULL

liczba

adres_nas

t

adres_pop

rz

NULL

NULL

NULL

0x

FA41

0xFB12

głowa

listy

ogon

listy

background image

4

Łukasz Krupa,

2014

Podstawowe operacje –

dodawanie

Podstawowe operacje, związane z listą, ograniczają się do trzech – dodawania elementu do listy, usuwania

elementu z listy oraz wyszukiwania danego elementu w liście. Zajmijmy się pierwszą – dodawaniem.

Podczas dodawania należy rozpatrzyć dwa przypadki:

lista, do której dodajemy, jest pusta

lista zawiera przynajmniej jeden element

Umownie dodawać będziemy na początek listy, który stanowi ostatni dodany do listy element.

PRZYPADEK 1: lista nie istnieje (nie zawiera ani jednego elementu)

Dodajemy do pustej listy element o kluczu równym 5

0

x

9

6

C

4

5

NULL

Nowa głowa
listy

Adres nowego

elementu listy w

pamięci (przydzielany

dynamicznie)

Adres następnego

elementu listy

(NULL, bo lista była

pusta)

NULL

Adres poprzedniego

elementu listy

(NULL, bo lista była

pusta)

background image

5

Łukasz Krupa,

2014

Podstawowe operacje –

dodawanie

PRZYPADEK 2: lista istnieje (zawiera przynajmniej jeden element)

Dodajemy na początek poniższej listy element o kluczu równym 9

0

x

9

6

C

4

5

0xA812

Głowa listy

0

xA

8

1

2

7

0

x

A

A

7

6

2

0xAA7

6

NULL

0

x1

3

3

D

9

0x96C4

nowa głowa
listy

Nową głową listy jest nowododany „kontener” z kluczem równym 9

Podczas implementacji funkcji dodawania do listy można połączyć oba przypadki w jeden – przy

odpowiednim przypisaniu adresu elementu poprzedniego oraz następnego w liście.

NULL

NULL

NULL

NULL

0xA812

0x96C4

0x133

D

NULL

background image

6

Łukasz Krupa,

2014

Podstawowe operacje –

usuwanie

Usuwanie z listy, podobnie jak dodawanie, jest podstawową operacją dla list. Mówiliśmy już o

tym przy okazji przerabiania listy jednokierunkowej. Wartym zaznaczenia jest fakt, że

podstawowa operacja usuwania usuwa pierwszy napotkany element, zgodny z podanym

kluczem przeznaczonym do usunięcia.
Podczas usuwania należy rozpatrzyć trzy przypadki:
• lista, z której usuwamy, jest pusta
• lista zawiera element przeznaczony do usunięcia
• lista nie zawiera elementu przeznaczonego do usunięcia

PRZYPADEK 1: lista, z której usuwamy, nie istnieje (nie zawiera ani jednego elementu – jest

pusta)

W tym przypadku nie robimy nic. Wskaźnik na głowę listy jest pusty, czyli wynosi NULL.

background image

7

Łukasz Krupa,

2014

Podstawowe operacje –

usuwanie

PRZYPADEK 2: lista zawiera element przeznaczony do usunięcia

W tym przypadku należy rozważyć, teoretycznie, trzy inne przypadki:

usuwany element jest głową listy

usuwany element znajduje się w środku listy

usuwany element jest ogonem listy

Dlaczego „teoretycznie” trzy? Otóż przypadek 2 i 3 przy odpowiedniej implementacji listy pokrywają się, tj. mogą zostać

obsłużone bez konieczności wyodrębniania obu przypadków. Dla zainteresowanych – przypadek 1 również można połączyć z 2 i

3, lecz na potrzeby lepszego zrozumienia algorytmów będziemy skupiać się na funkcji usuwania, rozróżniającej przypadek 1 od

2 i 3.

PRZYPADEK 2.1: element przeznaczony do usunięcia jest głową listy

Usuwany z poniższej listy element o kluczu 9

Głowa listy

Nowa głowa listy

Po usunięciu z listy elementu, który był jej głową, nową głową jest element, na którego adres wskazywał wskaźnik na następny element listy usuwanego elementu.

0

x

9

6

C

4

5

0xA812

0

x

A

8

1

2

7

0

x

A

A

7

6

2

0xAA7

6

NULL

0

x

1

3

3

D

9

0x96C4

NULL

NULL

NULL

NULL

0xA812

0x96C4

0x133

D

background image

8

Łukasz Krupa,

2014

Podstawowe operacje –

usuwanie

PRZYPADEK 2.2: element usuwany znajduje się w środku listy

Usuwany z poniższej listy element o kluczu 7

Głowa listy

Po usunięciu z listy elementu, który był jej głową, nową głową jest element, na którego adres wskazywał wskaźnik na następny element

listy usuwanego elementu.

Tymczasowa głowa listy

9 != 7

5 != 7

7 == 7

Usuwany z poniższej listy element o kluczu 2

Głowa listy

PRZYPADEK 2.3: element przeznaczony do usunięcia znajduje się na końcu listy (jest ogonem)

Tymczasowa głowa listy

9 != 2

5 != 2

7 != 22 == 2

Po usunięciu elementu, który był ogonem listy, nowym ogonem staje się element poprzedzający elementu usunięty – jego pole adresu,
Wskazujące na kolejny element listy, zamieniane jest na NULL.

0

x

9

6

C

4

5

0xA812

0

xA

8

1

2

7

0

x

A

A

7

6

2

0xAA7

6

NULL

0

x

1

3

3

D

9

0x96C4

NULL

NULL

NULL

NULL

0xA812

0x96C4

0x133

D

0xAA7

6

0x96C4

0

x9

6

C

4

5

0xA812

0

x

A

8

1

2

7

0

x

A

A

7

6

2

0xAA7

6

NULL

0

x

1

3

3

D

9

0x96C4

NULL

NULL

NULL

NULL

0xA812

0x96C4

0x133

D

NULL

background image

9

Łukasz Krupa,

2014

Podstawowe operacje –

usuwanie

PRZYPADEK 3: lista nie zawiera elementu przeznaczonego do usunięcia

Przypadek ten najczęściej łączony jest z przypadkiem 2. W przypadku listy nieposortowanej,

aby sprawdzić, czy lista nie zawiera żądanego elementu, należy każdorazowo przeszukać całą

listę.

W przypadku listy posortowanej, w pewnych przypadkach, nie ma potrzeby przechodzenia całej

listy by stwierdzić, że żądany element nie zawiera się w liście. Oczywiście, jest gro przypadków,

w których bez względu na to, czy lista jest posortowana, czy też nie – algorytm usuwania

przejdzie ją całą.

Usuwany z poniższej listy element o kluczu 10 (nie należącym do listy)

Głowa listy

Tymczasowa głowa
listy

9 != 10

5 != 10

7 != 10

2 != 10

Brak kolejnego

elementu

listy

KONIEC PRACY

ALGORYTMU

Lista nie zostanie zmodyfikowana, ponieważ żądany do usunięcia element nie zawierał się w

podanej liście.

0

x9

6

C

4

5

0xA812

0

x

A

8

1

2

7

0

x

A

A

7

6

2

0xAA7

6

NULL

0

x

1

3

3

D

9

0x96C4

NULL

NULL

NULL

NULL

0xA812

0x96C4

0x133

D

background image

10

Łukasz Krupa,

2014

Podstawowe operacje –

wyszukiwanie

Ostatnią operacją podstawową, którą omówimy, będzie wyszukiwanie elementu w liście. Z

operacji wyszukiwania korzystaliśmy niejawnie podczas usuwania elementu z listy.

Wartym zaznaczenia jest fakt, że podstawowa operacja wyszukiwania zwraca adres

pierwszego napotkanego elementu, zgodny z podanym kluczem do wyszukania.

Podczas usuwania należy rozpatrzyć trzy przypadki:
• lista, którą przeszukujemy, jest pusta
• lista zawiera element szukany
• lista nie zawiera elementu szukanego

Ponieważ operację wyszukiwania wykorzystywaliśmy podczas operacji usuwania, nie będzie

ona omawiana osobno – wystarczy zapoznać się ze wspomnianą funkcją usuwania.

background image

11

Łukasz Krupa,

2014

Implementacja w języku C

W tej części skupimy się już na programowaniu tego, o czym do tej pory mówiliśmy i co

rozważaliśmy.

Zaimplementowane zostaną funkcje:
• Dodaj do listy
• Usuń z listy
• Wyszukaj w liście

Ponieważ operować możemy na pojedynczym lub podwójnym wskaźniku, wszystkie wyżej

podane funkcje będą zaimplementowane w obu wersjach – z pojedynczym oraz z podwójnym

wskaźnikiem.

Funkcje implementowane będą w języku angielskim – wynika to z faktu, że większość kodów

dostępnych w internecie posługuje się anglojęzycznymi nazwami zmiennych i funkcji.

background image

12

Łukasz Krupa,

2014

Implementacja w języku C -

dodawanie

Zdefiniujmy najpierw strukturę listy dwukierunkowej oraz zadeklarujmy alias dla naszej listy:

struct

list

{

int

key

;

struct

list

*

prev

,

*

next

;

};

typedef

struct

list list

;

Teraz możemy zaimplementować funkcję dodającą do listy, w oparciu o powyższą strukturę.

list

*

add

(

list

*

head

,

int

key

)

{

list

*

newHead

=

(

list

*)

malloc

(

sizeof

(

list

));

newHead

->

key

=

key

;

newHead

->

prev

=

NULL

;

newHead

->

next

=

head

;

if

(

head

)

head

->

prev

=

newHead

;

return

newHead

;

}

void

add

(

list

**

head

,

int

key

)

{

list

*

newHead

=

(

list

*)

malloc

(

sizeof

(

list

));

newHead

->

key

=

key

;

newHead

->

prev

=

NULL

;

newHead

->

next

=

*

head

;

if

(*

head

)

(*

head

)->

prev

=

newHead

;

*

head

=

newHead

;

}

dodaj przy użyciu pojedynczego wskaźnika:

dodaj przy użyciu podwójnego wskaźnika:

background image

13

Łukasz Krupa,

2014

Implementacja w języku C -

usuwanie

Funkcja usuwająca element listy zwraca:
• W przypadku usunięcia elementu, który jest głową – przesunięcie głowy na kolejny element listy i

zwrócenie adresu nowej głowy

• W przypadku, gdy usuwamy element, będący jedynym elementem listy – NULL
• W przeciwnym przypadku – ten sam adres, który przekazywaliśmy do funkcji jako argument

Argumentami funkcji są: adres głowy listy oraz konkretna wartość, która ma zostać usunięta z listy.

Ponieważ funkcja usuwania zajmuje więcej linii niż dodawanie czy wyszukiwanie, została ona umieszczona

na osobnym slajdzie.

Zanim przejdziemy do części z kodem funkcji, sprawdźmy, jak wywoływać funkcję na pojedynczym i

podwójnym wskaźniku.

head

=

remove

(

head

,

10

);

list

**

phead

=

&

head

;

.

.
.

remove

(

phead

,

10

);

list

*

phead

=

NULL

;

.

.
.

remove

(&

head

,

10

);

wywołanie funkcji opartej o wskaźnik pojedynczy:

wywołanie funkcji opartej o wskaźnik podwójny:

background image

14

Łukasz Krupa,

2014

Implementacja w języku C -

usuwanie

list

*

remove

(

list

*

head

,

int

key

)

{

if

(

head

)

{

list

*

tmpHead

=

head

;

while

(

tmpHead

&&

tmpHead

->

key

!=

key

)

tmpHead

=

tmpHead

->

next

;

if

(

tmpHead

)

{

if

(

tmpHead

==

head

)

head

=

head

->

next

;

list

*

trash

=

tmpHead

;

if

(

tmpHead

->

next

)

tmpHead

->

next

->

prev

=

tmpHead

->

prev

;

if

(

tmpHead

->

prev

)

tmpHead

->

prev

->

next

=

tmpHead

->

next

;

free

(

trash

);

}

}

return

head

;

}

void

remove

(

list

**

head

,

int

key

)

{

if

(*

head

)

{

list

*

tmpHead

=

*

head

;

while

(

tmpHead

&&

tmpHead

->

key

!=

key

)

tmpHead

=

tmpHead

->

next

;

if

(

tmpHead

)

{

if

(

tmpHead

==

*

head

)

*

head

=

(*

head

)->

next

;

list

*

trash

=

tmpHead

;

if

(

tmpHead

->

next

)

tmpHead

->

next

->

prev

=

tmpHead

->

prev

;

if

(

tmpHead

->

prev

)

tmpHead

->

prev

->

next

=

tmpHead

->

next

;

free

(

trash

);

}

}
}

usuń przy użyciu pojedynczego wskaźnika:

usuń przy użyciu podwójnego wskaźnika:

background image

15

Łukasz Krupa,

2014

Implementacja w języku C -

przeszukanie

Funkcja przeszukująca listę zwraca:
• W przypadku znalezienia szukanego elementu – adres do pamięci, zawierający ten element
NULL w przeciwnym wypadku

Argumentami funkcji są: adres głowy listy oraz konkretna wartość, którą ma zawierać zwracany adres do

komórki pamięci.

list

*

find

(

list

*

head

,

int

key

)

{

while

(

head

&&

head

->

key

!=

key

)

head

=

head

->

next

;

return

head

;

}

void

find

(

list

**

itemAddress

,

int

key

)

{

while

(*

itemAddress

&&

(*

itemAddress

)->

key

!=

key

)

*

itemAddress

=

(*

itemAddress

)->

next

;

}

wyszukaj przy użyciu pojedynczego wskaźnika:

wyszukaj przy użyciu podwójnego wskaźnika:

Skupmy się na chwilę na funkcji zbudowanej w oparciu o podwójny wskaźnik.

Przed jej wywołaniem w programie, należy zadeklarować stosowny wskaźnik oraz przypisać do wskaźnika wartość zmiennej

head, lub adres tej zmiennej (w zależności od tego, czy zechcemy działać od razu na podwójnym wskaźniku). Oto przykładowe

wywołania (funkcji zbudowanej w oparciu o podwójny wsk.):

list

**

itemAddress

=

&

head

;

find

(

itemAddress

,

10

);

list

*

itemAddress

=

head

;

find

(&

itemAddress

,

10

);

W obu przypadkach „10” jest elementem, który chcemy wyszukać w liście, a head jest zmienną wskaźnikową, przechowującą

adres bieżącej głowy listy.

background image

16

Łukasz Krupa,

2014

Przykładowe zadania – zadanie 1

Przedstawione zostały do tej pory trzy funkcje, które tworzą niezbędne minimum, by móc posługiwać się

listą dwukierunkową.

Teraz skupimy się na zadaniach, które mogą pojawić się na kolokwiach czy egzaminach, a które ściśle

związane są z tematem list dwukierunkowych.

Zadanie 1

*

Dana jest posortowana lista dwukierunkowa określona przez poniższą strukturę. Napisz funkcję void removeDuplicates(struct list* head),

która usunie z listy wszystkie duplikaty. Na bazie napisanej funkcji napisz funkcję void removeDuplicates (struct list** head).

Przykład:

1 1 3 4 4 4 6 6 8 9 9

po usunięciu wszystkich duplikatów:

1 3 4 6 8 9

struct list
{
int key;
struct list *prev, *next;
};

Najpierw stwórzmy alias dla naszej listy, ponieważ dość irytujące jest ciągłe wpisywanie struct lista w

funkcje.

typedef

struct

list list

;

Rozwiązanie zadania zamieszczone na kolejnym slajdzie.

background image

17

Łukasz Krupa,

2014

Przykładowe zadania – zadanie 1

void

removeDuplicates

(

list

*

head

)

{

if

(

head

)

{

list

*

tmpHead

=

head

;

while

(

tmpHead

)

{

list

*

tmp

=

tmpHead

->

next

;

while

(

tmp

&&

tmp

->

key

==

tmpHead

->

key

)

{

list

*

trash

=

tmp

;

tmp

->

prev

->

next

=

tmp

->

next

;

if

(

tmp

->

next

)

tmp

->

next

->

prev

=

tmp

->

prev

;

tmp

=

tmp

->

next

;

free

(

trash

);

}

tmpHead

=

tmpHead

->

next

;

}

}
}

void

removeDuplicates

(

list

**

head

)

{

if

(*

head

)

{

list

*

tmpHead

=

*

head

;

while

(

tmpHead

)

{

list

*

tmp

=

tmpHead

->

next

;

while

(

tmp

&&

tmp

->

key

==

tmpHead

->

key

)

{

list

*

trash

=

tmp

;

tmp

->

prev

->

next

=

tmp

->

next

;

if

(

tmp

->

next

)

tmp

->

next

->

prev

=

tmp

->

prev

;

tmp

=

tmp

->

next

;

free

(

trash

);

}

tmpHead

=

tmpHead

->

next

;

}

}
}

removeDuplicates przy użyciu pojedynczego
wskaźnika:

removeDuplicates przy użyciu podwójnego
wskaźnika:

background image

18

Łukasz Krupa,

2014

Przykładowe zadania – zadanie 2

Zadanie 2

Dana jest lista dwukierunkowa określona przez poniższą strukturę. Napisz funkcję struct list* rotateRight(list* head, int position), dokona

obrotu logicznego listy o position miejsc w prawo. Na postawie napisanej funkcji napisz funkcję void rotateRight(list** head, int

position), przy użyciu podwójnego wskaźnika.

Przykład:

2 8 9 6 1 4

obrót o 2 pozycje:

1 4 2 8 9 6

struct list
{
int key;
struct list *prev, *next;
};

Ponieważ rozwiązanie zadania jest złożone, zatem najpierw zostanie przedstawione na przykładzie.

Niech dana będzie lista jak poniżej, a wartość position wynosi 2.

0

x

9

6

C

4

5

0xA812

0

xA

8

1

2

7

0

xA

A

7

6

2

0xAA7

6

NULL

0

x1

3

3

D

9

0x96C4

NULL

NULL

NULL

NULL

0xA812

0x96C4

0x133

D

NULL

Głowa listy

Tymczasowa głowa
listy

Licznik
elementów = 0

Licznik
elementów = 1

Licznik
elementów = 2

Licznik
elementów = 3

Licznik
elementów = 4

0x133

D

0xAA7

6

Powstała lista
cykliczna

Position = 2

STOP!

Position = 1

Position = 0

STO

P!

NULL

NULL

Nowa głowa
listy

Po wykonaniu funkcji, lista będzie rozpoczynała się elementem 7, a kończyła 5. Będzie miała kolejność: 7 2 9

5.

background image

19

Łukasz Krupa,

2014

Przykładowe zadania – zadanie 2

list

*

rotateRight

(

list

*

head

,

int

position

)

{

if

(

head

&&

position

>

0

)

{

int

lengthOfList

=

0

,

guard

=

1

;

list

*

tmpHead

=

head

;

while

(

guard

)

{

if

(!

tmpHead

->

next

)

{

tmpHead

->

next

=

head

;

head

->

prev

=

tmpHead

;

guard

=

0

;

}

lengthOfList

++;

tmpHead = tmpHead

->

next

;

}

int

rotNumber

=

position

%

lengthOfList

;

while

(

rotNumber

--)

head

=

head

->

prev

;

head

->

prev

->

next

=

NULL

;

head

->

prev

=

NULL

;

}

return

head

;

}

void

rotateRight

(

list

**

head

,

int

position

)

{

if

(*

head

&&

position

>

0

)

{

int

lengthOfList

=

0

,

guard

=

1

;

list

*

tmpHead

=

*

head

;

while

(

guard

)

{

if

(!

tmpHead

->

next

)

{

tmpHead

->

next

=

*

head

;

(*

head

)->

prev

=

tmpHead

;

guard

=

0

;

}

lengthOfList

++;

tmpHead

=

tmpHead

->

next

;

}

int

rotNumber

=

position

%

lengthOfList

;

while

(

rotNumber

--)

*

head

=

(*

head

)->

prev

;

(*

head

)->

prev

->

next

=

NULL

;

(*

head

)->

prev

=

NULL

;

}

}

rotateRight przy użyciu pojedynczego wskaźnika:

rotateRight przy użyciu podwójnego wskaźnika:

background image

20

Łukasz Krupa,

2014

Przykładowe zadania – zadanie 3

Zadanie 3

Dana jest lista dwukierunkowa określona przez poniższą strukturę. Napisz funkcję int showList(struct list* head), która wyświetli wszystkie

elementy listy i zwróci jej długość. Na podstawowie napisanej funkcji, napisz funkcję int showList(list** head).

Przykład:

2 8 9

Po wykonaniu funkcji showList:

2 8 9, dlugosc: 3

struct list
{
int key;
struct list *prev, *next;
};

typedef

struct

list list

;

Najpierw stwórzmy alias dla naszej listy, ponieważ dość irytujące jest ciągłe wpisywanie struct lista w

funkcje.

int

showList

(

list

*

head

,

int

key

)

{

int

counter

=

0

;

while

(

head

)

{

printf

(

%d

,

head

->

key

);

head

=

head

->

next

;

counter

++;

}

return

counter

;

}

int

showList

(

list

**

head

,

int

key

)

{

int

counter

=

0

;

list

*

tmpHead

=

*

head

;

while

(

tmpHead

)

{

printf

(

%d

,

tmpHead

->

key

);

tmpHead

=

tmpHead

->

next

;

counter

++;

}

return

counter

;

}

showList przy użyciu pojedynczego wskaźnika:

wyszukaj przy użyciu podwójnego wskaźnika:

background image

21

Podsumowanie

Materiał o listach jednokierunkowych, jak i dwukierunkowych, został przedstawiony w dwóch

dotychczasowych prezentacjach.

Dzięki znajomości przedstawionych zagadnień można bez problemu zabrać się za, np. Implementację

grafów, algorytmy ich przeszukiwań czy algorytm przechodzenia drzewa w porządku in level. Wszędzie tam

wykorzystywane są listy, zarówno jedno-, jak i dwukierunkowe.

Dalsze omawiane tematy będą w bardzo dużym stopniu korzystać z materiału już omówionego, zatem jeżeli

czujesz, że nie do końca przyswoiłeś wszystko, co zostało do tej pory przedstawione, cofnij się do

krytycznego momentu i prześledź przedstawione Ci materiały jeszcze raz. Zrozumienie list (pełne

zrozumienie, a nie wyuczenie się gotowych funkcji na pamięć) to klucz do zrozumienia np. implementacji

grafów, ponieważ bazuje ona na liście jedno- i dwukierunkowej (jako, odpowiednio – lista krawędzi danego

wierzchołka i lista wierzchołków grafu).

Również tablice z hashowaniem będą realizowane nie tylko na tablicy (alokowanej dynamicznie rzecz jasna),

ale także będą realizowane przy użyciu list.

Łukasz Krupa,

2014

background image

22

Autor: Łukasz Krupa

lukasz_krupa@gazeta.pl

Łukasz Krupa,

2014

Autor zezwala na kopiowanie i rozpowszechnianie powyższej

pracy, pod warunkiem zachowania informacji o oryginalnym

autorze niniejszej prezentacji.


Document Outline


Wyszukiwarka

Podobne podstrony:
lista dwukierunkowa F2DA6TW4OI2FJVP3HK3RXEDDNW6SZWKVQ4OUEOY
algorytmy lista dwukierunkowa, WAT, SEMESTR II, ALS
Lista 2012 2
Polecenia lista 5
macierze i wyznaczniki lista nr Nieznany
Lista 14
Analiza matematyczna, lista analiza 2008 6 szeregi
Analiza III semestr lista nr 3 Nieznany (2)
lista produktow
podstawy automatyki ćwiczenia lista nr 4b
lista parafraz modu A
Lista watykańskich masonów
Lista czesci
eksploracja lab03, Lista sprawozdaniowych bazy danych
lista przed zabr id 270172 Nieznany
analiza sem 2 lista nr5 id 6134 Nieznany (2)
LISTA 14 Całki krzywoliniowe
lista 04 (2)
lista jednokierunkowa

więcej podobnych podstron