Wieczorowe Studia Licencjackie Wrocław, 9.01.2007 Wstęp do programowania Wykład nr 13 Listy usuwanie elementów Poniżej prezentujemy funkcję, która usuwa element o podanej wartości pola wiek z nieuporządkowanej listy struktur typu struct dana * struct dana *usun(struct dana *lista, int uwiek) // usuniecie pierwszej osoby o wskazanym wieku struct dana *pom, *poprz; while (pom!= NULL && pom->wiek!= uwiek) //poszukiwanie elementu o wieku uwiek poprz = pom; pom = pom->nast; if (pom!= NULL) // na liscie wystapil uwiek if (pom == lista) //do usuniecia pierwszy element lista=lista->nast; else // tworzymy powiazanie omijajace usuw.el. poprz->nast = pom->nast; Komentarz: - pierwsza pętla przechodzi przez listę w poszukiwaniu elementu o wartości pola wiek równej uwiek; - usunięcie elementu z listy wymaga zmiany następnika jego poprzednika, dlatego pierwsza pętla przechowuje wskaźnik na element poprzedni w zmiennej poprz; lista poprz pom - w sytuacji, gdy usuwamy pierwszy element, zmianie musi też ulec wartość wskaźnika na początek listy.
Aby uniknąć pamiętania zawsze wskaźników na element aktualny i poprzedni, możemy zastosować metodę użytą wcześniej przy wstawianiu elementu: pamiętamy tylko element poprzedni i sprawdzamy, czy do usunięcia jest jego następnik: struct dana *usun2(struct dana *lista, int uwiek) // usuniecie pierwszej osoby o wskazanym wieku struct dana *pom, *pom2; if (lista == NULL) return NULL; if (lista->wiek == uwiek) //do usuniecia pierwszy element lista = lista->nast; while (pom->nast!= NULL && pom->nast->wiek!= uwiek) pom = pom->nast; //poszukiwanie elementu o wieku uwiek if (pom->nast!= NULL) //wystepuje element o wieku uwiek pom2 = pom->nast; pom->nast = pom2->nast; free(pom2); Komentarze: - teraz zmienna pom ma zawsze wskazywać na element już sprawdzony, czyli różny od uwiek - dlatego na początku osobno traktujemy przypadek gdy lista jest pusta bądź jej pierwszy element jest do usunięcia.
Operacje na listach rekurencyjnie Wypisywanie elementów: void drukrek(struct dana *lista) if (lista!= NULL) printf("%d\n", lista->wiek); drukrek(lista->nast); Wstawianie elementu do listy uporządkowanej: struct dana *wstawporzadekrek(struct dana *lista, struct dana *nowy) // wstawia element,na który wskazuje nowy // nowy nie moze miec wartosci NULL // wstawia wg wieku niemalejaco struct dana *pom; int pwiek; if (lista==null lista->wiek >= nowy->wiek) nowy->nast = lista; return nowy; else pom = wstawporzadekrek(lista->nast,nowy); lista->nast = pom; Usuwanie elementu z listy (nieuporzadkowanej): struct dana *usunrek(struct dana *lista, int uwiek) // usuniecie pierwszej osoby o wskazanym wieku // z listy nieuporzadkowanej struct dana *pom, *pom2; if (lista!= NULL) if (lista->wiek == uwiek) //do usuniecia pierwszy element lista = lista->nast; else pom = usunrek(lista->nast, uwiek); lista->nast = pom;
Operacje listowe na dwa sposoby: lista wynikowa jako wartość funkcji i jako parametr (wskaźnik na wskaźnik). Struktura danych: struct elem int klucz; struct elem *nast; ELLIST; Wstawianie elementu na początek listy: struct elem *wstaw1(struct elem *lista, int nklucz) struct elem *pom; pom = (struct elem *) malloc(sizeof(ellist)); pom->klucz = nklucz; pom->nast = lista; return pom; void wstaw2(struct elem **lista, int nklucz) struct elem *pom; pom = (struct elem *) malloc(sizeof(ellist)); pom->klucz = nklucz; pom->nast = *lista; *lista = pom; Dla listy, na którą wskazuje zmienna struct elem *mlista wywołania wyglądają następująco mlista=wstaw1(mlista, 5); wstaw2(&mlista, 5);
Usuwanie elementu: struct elem *usun1(struct elem *lista, int uklucz) struct elem *pom, *poprz; while (pom!= NULL && pom->klucz!= uklucz) poprz = pom; pom = pom->nast; if (pom!= NULL) if (pom == lista) lista=lista->nast; else poprz->nast = pom->nast; void usun2(struct elem **lista, int uklucz) struct elem *pom, *poprz; pom = *lista; while (pom!= NULL && pom->klucz!= uklucz) poprz = pom; pom = pom->nast; if (pom!= NULL) if (pom == *lista) *lista=(*lista)->nast; else poprz->nast = pom->nast; Dla listy na którą wskazuje zmienna struct elem *mlista wywołania wyglądają następująco mlista=usun1(mlista, 5); usun2(&mlista, 5);
Listy a tablice: Lista dostęp do elementu na określonej pozycji wymaga czasu proporcjonalnego do odległości od początku listy zajętość pamięci jest proporcjonalna do aktualnej liczby elementów wyszukanie elementu wymaga liniowego czasu (proporcjonalnego do liczby elementów na liście) usunięcie wskazanego elementu lub wstawienie elementu na wskazanej pozycji można zrealizować w czasie niezależnym od rozmiaru listy Tablica dostęp do elementu na określonej pozycji w czasie niezależnym od rozmiaru tablicy zajęta pamięć jest proporcjonalna do rozmiaru tablicy wyszukiwanie w czasie liniowym, ale w przypadku uporządkowania elementów w tablicy, wyszukanie elementu możliwe jest w czasie logarytmicznym usunięcie elementu znajdującego się na określonej pozycji lub wstawienie elementu na wskazaną pozycję wymaga czasu proporcjonalnego do liczby elementów Usprawnienia i rozszerzenia: Dodanie wartownika na końcu listy (przyspieszenie wyszukiwania). Listę opisuje wskaźnik na pierwszy i na ostatni element na liście (umożliwia szybkie wstawianie na koniec listy). Lista dwukierunkowa (wskaźniki do następnego i poprzedniego elementu).