8268
edycji
(poprawienie błędów) |
(revert, wytłumaczenie jest w dyskusji, odnieś się do niej najpierw. przed dalszą edycją prosze napisać na stronie dyskusji modułu odpowiedź na moje wątpliwości) |
||
=== Implementacja listy ===
W języku C aby stworzyć listę musimy użyć struktur. Dlaczego? Ponieważ musimy przechować co najmniej dwie wartości:
#
# wskaźnik na kolejny element listy
Przyjmijmy, że szukając liczb pierwszych nie przekroczymy możliwości typu unsigned long:
<source lang="c">
typedef struct
struct
}
</source>
Zacznijmy zatem pisać nasz eksperymentalny program, do wyszukiwania liczb pierwszych. Pierwszą liczbą pierwszą jest liczba 2 Pierwszym elementem naszej listy będzie zatem struktura, która będzie przechowywała liczbę 2. Na co będzie wskazywało pole next? Ponieważ na początku działania programu będziemy mieć tylko jeden element listy, pole next powinno wskazywać na NULL. Umówmy się zatem, że pole next ostatniego elementu listy będzie wskazywało NULL - po tym poznamy, że lista się skończyła.
<source lang="c">
#include <stdio.h>
#include <stdlib.h>
typedef struct
struct
}
el_listy *first; /* pierwszy element listy */
int main ()
unsigned long i = 3; /* szukamy liczb pierwszych w zakresie od 3 do 1000 */
const unsigned long END = 1000;
first = malloc (sizeof(el_listy));
for (;i<=END;++i) {
/* tutaj powinien znajdować się kod, który sprawdza podzielność sprawdzanej liczby przez
że jest ona liczbą pierwszą. */
}
return 0;
}
# Przesuń wskaźnik na element, który jest wskazywany przez pole next
# Wróć do punktu 2
<source lang="c">
{
el_listy *wsk=lista; /*
while( wsk != NULL ) /* 2 */
{
} /*
}
</source>
# nadać polu next ostatniego elementu listy wartość NULL
# w pole next ostatniego elementu listy wpisać adres nowo przydzielonego obszaru
Napiszmy zatem odpowiednią funkcję:
<source lang="c">
void dodaj_do_listy (el_listy *lista, unsigned long liczba)
{
el_listy
wsk = lista;
while (wsk->next != NULL) /* 1 */
{
wsk = wsk->next; /* przesuwamy wsk aż znajdziemy ostatni element */
}
nowy
nowy->
nowy->next = NULL; /* 4 */
wsk->next = nowy; /* 5 */
}
</source>
I... to już właściwie koniec naszej funkcji (warto zwrócić uwagę, że funkcja w tej wersji zakłada, że na liście jest już przynajmniej jeden element). Wstaw ją do kodu przed funkcją main. Został nam jeszcze jeden problem: w pętli for musimy dodać kod, który odpowiednio będzie "badał" liczby oraz w przypadku stwierdzenia pierwszeństwa liczby, będzie dodawał ją do listy. Ten kod powinien wyglądać mniej więcej tak:
<source lang="c">
int jest_pierwsza(el_listy *lista, int liczba)
{
wsk = lista;
while (wsk != NULL) {
if ((liczba %
przez którąkolwiek z poprzednio
znalezionych liczb pierwszych
jest równa zero, to znaczy, że liczba
ta nie jest liczbą pierwszą
wsk = wsk->next;
}
}
...
for (;i<=END;++i) {
if (
}
</source>
#include <stdlib.h>
typedef struct
struct
} el_listy;
void dodaj_do_listy (
{
wsk = lista;
while (wsk->next != NULL)
wsk = wsk->next; /* przesuwamy wsk aż znajdziemy ostatni element */
}
nowy = malloc (sizeof
nowy->val = liczba;
nowy->next = NULL;
wsk->next = nowy; /* podczepiamy nowy element do ostatniego z listy */
}
void wypisz_liste(el_listy *lista)
{
el_listy
while( wsk != NULL )
{
wsk = wsk->next;
}
}
{
wsk = lista;
while (wsk != NULL) {
if ((liczba%
wsk = wsk->next;
}
{
unsigned long i = 3; /* szukamy liczb pierwszych w zakresie od 3 do 1000 */
const unsigned long END = 1000;
first =
first->val = 2;
first->next = NULL;
for (;i!=END;++i) {
if (
}
return 0;
}
Możemy jeszcze pomyśleć, jak można by wykonać usuwanie elementu z listy. Najprościej byłoby zrobić:
wsk->next = wsk->next->next
ale wtedy element, na który wskazywał wcześniej <tt>wsk->next</tt> przestaje być dostępny i zaśmieca pamięć. Trzeba go usunąć. Zauważmy, że aby usunąć element potrzebujemy wskaźnika do '''elementu go poprzedzającego''' (po to, by nie rozerwać listy)
<source lang="c">
void usun_z_listy(el_listy *lista, int element)
{
el_listy
while (wsk->next != NULL)
{
if (wsk->next->val == element) /* musimy mieć wskaźnik do elementu poprzedzającego */
{
el_listy *usuwany=wsk->next; /* zapamiętujemy usuwany element */
wsk->next = usuwany->next; /* przestawiamy wskaźnik next by omijał usuwany element */
free(usuwany); /* usuwamy z pamięci */
} else
wsk = wsk->next; /* idziemy dalej tylko wtedy kiedy nie usuwaliśmy */
} /* bo nie chcemy zostawić duplikatów */
}
}
</source>
Funkcja ta działa poprawnie tylko wtedy, gdy nie chcemy usuwać pierwszego elementu. Można to poprawić - dodając instrukcję warunkową do funkcji lub dodając do listy "głowę" - pierwszy element nie przechowujący niczego, ale upraszczający operacje na liście. Zostawiamy to do samodzielnej pracy.
Cały powyższy przykład omawiał tylko jeden przypadek listy - listę jednokierunkową. Jednak istnieją jeszcze inne typy list, np. lista jednokierunkowa cykliczna, lista dwukierunkowa oraz dwukierunkowa cykliczna. Różnią się one od siebie tylko tym, że:
* w przypadku list dwukierunkowych - w strukturze el_listy znajduje się jeszcze pole, które wskazuje na element poprzedni
* w przypadku list cyklicznych - ostatni element wskazuje na pierwszy (nie rozróżnia się wtedy elementu pierwszego, ani ostatniego)
<noinclude>{{Nawigacja|C|
|
edycji