Podstawy Programowania. Listy i stosy

Podobne dokumenty
Dynamiczne struktury danych

Zmienne dynamiczne. nazwy; odwo lania do nich sa za pomoca być tworzone jawnie procedura zmienne dynamiczne maja

Algorytmy i złożoności. Wykład 3. Listy jednokierunkowe

Wstęp do programowania

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.


Materiał uzupełniający do ćwiczen z przedmiotu: Programowanie w C ++ - ćwiczenia na wskaźnikach

ZASADY PROGRAMOWANIA KOMPUTERÓW

Wykład 5 Wybrane zagadnienia programowania w C++ (c.d.)

Podstawy programowania. Wykład 7 Tablice wielowymiarowe, SOA, AOS, itp. Krzysztof Banaś Podstawy programowania 1

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

INFORMATYKA. Podstawy programowania w języku C. (Wykład) Copyright (C) 2005 by Sergiusz Sienkowski IME Zielona Góra

Szablony klas, zastosowanie szablonów w programach

Struktury Danych i Złożoność Obliczeniowa

Struktury. Przykład W8_1

Lista dwukierunkowa - przykład implementacji destruktorów

Struktury danych: stos, kolejka, lista, drzewo

Dynamiczny przydział pamięci w języku C. Dynamiczne struktury danych. dr inż. Jarosław Forenc. Metoda 1 (wektor N M-elementowy)

Dynamiczne struktury danych

Lab 9 Podstawy Programowania

Algorytmy i Struktury Danych. Co dziś? Drzewo decyzyjne. Wykład IV Sortowania cd. Elementarne struktury danych

Podstawowe struktury danych

Informatyka 1. Przetwarzanie tekstów

Podstawy Programowania 2 Dwukierunkowa lista liniowa. Plan. Wstęp. Implementacja. Notatki. Notatki. Notatki. Notatki.

dr inż. Paweł Myszkowski Wykład nr 11 ( )

E S - uniwersum struktury stosu

. Podstawy Programowania 2. Dwukierunkowa lista liniowa. Arkadiusz Chrobot. 7 kwietnia 2019

Podstawy Programowania 2 Jednokierunkowa lista liniowa. Plan. Jednokierunkowa lista liniowa. Jednokierunkowa lista liniowa. Notatki. Notatki.

Programowanie obiektowe

. Podstawy Programowania 2. Jednokierunkowa lista liniowa. Arkadiusz Chrobot. 28 marca 2017

Podstawy programowania. Wykład 6 Złożone typy danych: struktury, unie. Krzysztof Banaś Podstawy programowania 1

Wykład 6_1 Abstrakcyjne typy danych stos Realizacja tablicowa i za pomocą rekurencyjnych typów danych

Podstawy programowania w języku C++

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania 2. Przygotował: mgr inż. Tomasz Michno

1 Wskaźniki i listy jednokierunkowe

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

Listy, kolejki, stosy

Podstawy programowania w języku C++

Wprowadzenie do szablonów szablony funkcji

Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04

Typy wyliczeniowe Konwersje napis <-> liczba Struktury, unie Scanf / printf Wskaźniki

Wprowadzenie do szablonów szablony funkcji

Języki programowania obiektowego Nieobiektowe elementy języka C++

Szablony funkcji i szablony klas

WYKŁAD 10. Zmienne o złożonej budowie Statyczne i dynamiczne struktury danych: lista, kolejka, stos, drzewo. Programy: c5_1.c, c5_2, c5_3, c5_4, c5_5

Zmienne i struktury dynamiczne

Laboratorium 6: Dynamiczny przydział pamięci. dr inż. Arkadiusz Chrobot dr inż. Grzegorz Łukawski

Podstawy Programowania Obiektowego

Programowanie i struktury danych. Wykład 4 Dr Piotr Cybula

Wykład 8: klasy cz. 4

Podstawy programowania w języku C++

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Zadanie polega na stworzeniu bazy danych w pamięci zapewniającej efektywny dostęp do danych baza osób.

Laboratorium nr 9. Temat: Wskaźniki, referencje, dynamiczny przydział pamięci, tablice dynamiczne. Zakres laboratorium:

Drzewa podstawowe poj

Algorytmy i Struktury Danych.

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Podstawy programowania obiektowego

Prezentacja systemu RTLinux

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

Konwersje napis <-> liczba Struktury, unie Scanf / printf Wskaźniki

Teoretyczne podstawy informatyki

. Podstawy Programowania 2. Drzewa bst - część druga. Arkadiusz Chrobot. 12 maja 2019

TEMAT : KLASY DZIEDZICZENIE

Wskaźniki. nie są konieczne, ale dają językowi siłę i elastyczność są języki w których nie używa się wskaźników typ wskaźnikowy typ pochodny:

Wskaźniki. Programowanie Proceduralne 1

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Podstawy programowania

Podstawy programowania komputerów

Tablice i struktury. czyli złożone typy danych. Programowanie Proceduralne 1

Klasa 2 INFORMATYKA. dla szkół ponadgimnazjalnych zakres rozszerzony. Założone osiągnięcia ucznia wymagania edukacyjne na. poszczególne oceny

Referencje do zmiennych i obiektów

Programowanie i struktury danych

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

dr inż. Jarosław Forenc

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Wykład 3 Składnia języka C# (cz. 2)

Wykład 9: Polimorfizm i klasy wirtualne

. Podstawy Programowania 2. Dwukierunkowa lista cykliczna. Arkadiusz Chrobot. 24 kwietnia 2016

Język C, tablice i funkcje (laboratorium, EE1-DI)

Języki programowania. Przetwarzanie tablic znaków. Część druga. Autorzy Tomasz Xięski Roman Simiński

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Podstawy Informatyki. Wykład 6. Struktury danych

Podstawy programowania w języku C++

Ćwiczenie 3 z Podstaw programowania. Język C++, programy pisane w nieobiektowym stylu programowania. Zofia Kruczkiewicz

Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

1. Kalkulator czterech działań. 2. Konwersja ciągu znaków do tablicy.

Ćwiczenie 7 z Podstaw programowania. Język C++, programy pisane w nieobiektowym stylu programowania. Zofia Kruczkiewicz

Wyszukiwanie w BST Minimalny i maksymalny klucz. Wyszukiwanie w BST Minimalny klucz. Wyszukiwanie w BST - minimalny klucz Wersja rekurencyjna

Konstruktor kopiujacy

Deklaracja struktury w C++

Wstęp do programowania

Algorytmy i struktury danych. Wykład 6 Tablice rozproszone cz. 2

Lista dwukierunkowa. Grzegorz Wasylów Konrad Wojtoń

Schemat konstrukcja pliku Makefile

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

int tab_a [ 2 ] [ 3 ];

Transkrypt:

Podstawy Programowania Wykład IX Listy i stosy Robert Muszyński Katedra Cybernetyki i Robotyki, PWr Zagadnienia: listy: tworzenie, wyszukiwanie, przeglądanie, usuwanie, problemy, listy z głową, z wartownikiem, dwustronnie połączone, kołowe, abstrakcyjne typy danych: stosy, kolejki chronologiczne, bufory cykliczne. Copyright c 2007 2017 Robert Muszyński Niniejszy dokument zawiera materiały do wykładu na temat podstaw programowania w językach wysokiego poziomu. Jest on udostępniony pod warunkiem wykorzystania wyłącznie do własnych, prywatnych potrzeb i może być kopiowany wyłącznie w całości, razem ze stroną tytułową. Skład FoilTEX

Listy i stosy 1 Lista regularna struktura dynamiczna typedef struct elem { t_info info; struct elem *nastepny; } t_elem; /* i gdzies dalej t_elem *lista; */ zmienne statyczne pamięć dynamiczna lista info nast. info nast.... info nast. info nast. NULL dynamiczna struktura danych jest regularną strukturą łączącą elementy treści z elementami konstrukcyjnymi (wskaźnikami) niezbędna jest co najmniej jedna zmienna statyczna zapewniająca dostęp do struktury dynamicznej specjalna wartość wskaźnikowa NULL jest przydatna do oznakowania pustych zakończeń struktury dynamicznej

Listy i stosy 2 t_elem *lista, *pom; Listy tworzenie lista = NULL; /* zainicjuj pusta liste */ } while (!koniec_danych) { /* dopoki sa dane */ pom = (t_elem *)malloc(sizeof(t_elem)); /* utworz element */ wczytaj_element(str_danych, pom); /* wczytaj do niego dane */ pom->nastepny = NULL /* to na wszelki wypadek */ dodaj_element(lista, pom); /* wlacz element do listy */ Trzy etapy w procesie konstrukcji listy: stworzenie nowej zmiennej dynamicznej wpisanie do niej właściwej treści utworzenie właściwych wskaźników konstrukcyjnych dla włączenia nowego elementu do reszty listy należy pamiętać o wartości wskaźnikowej NULL

Listy i stosy 3 Listy tworzenie cd. void dodaj_element(t_elem **wsk_lista, t_elem *elem) { /* na poczatek listy */ elem->nastepny = *wsk_lista; *wsk_lista = elem; } /* dodaj_element */ lista = NULL; /* i wtedy w jakiejs funkcji */ pom = malloc(sizeof(t_elem)); /*pomijamy kwestie rzutowania*/ pom->info = A ; dodaj_element(&lista,pom); pom = malloc(sizeof(t_elem)); pom->info = B ; dodaj_element(&lista,pom); pom = malloc(sizeof(t_elem)); pom->info = C ; dodaj_element(&lista,pom); pom = malloc(sizeof(t_elem)); pom->info = D ; dodaj_element(&lista,pom); lista info nast. info nast. info nast. info nast. D C B A NULL

Listy i stosy 4 Listy tworzenie cd. void dodaj_element(t_elem **wsk_lista, t_elem *elem) { /* na koniec listy, rekurencyjnie */ if (*wsk_lista == NULL) *wsk_lista = elem; else dodaj_element(&(wsk_lista->nastepny), elem); elem->nastepny = NULL; /* moze niekonieczne, ale poprawne */ } /* dodaj_element */ Zauważmy, że sprawdzenie czy *wsk_lista == NULL dotyczy nie tyle przypadku pustej listy (początkowo), ale ogólnie przypadku końca listy; a więc każdy nowy element będzie wpisywany w miejsce tej pustej wartości NULL, zauważmy również, że ta niewinnie wyglądająca funkcja wykonuje przeszukiwanie całej istniejącej listy, w dodatku szeregiem tylu wywołań rekurencyjnych, ile elementów ma lista, gdybyśmy tylko mieli wskaźnik ostatniego elementu :-(

Listy i stosy 5 Listy wyszukiwanie elementu char porownaj_element(t_elem e1, t_elem e2) {...} /*niech zwraca jeden ze znakow: <, =, > */ /* wersja 1 - zla; moze nie zatrzymac sie na koncu */ pom = lista; while (porownaj_element(*pom, elem_wzorcowy)!= = ) pom = pom->nastepny; /* wersja 2 - dobra; ale dlaczego nie zawsze? */ pom = lista; while (pom!= NULL && porownaj_element(*pom, elem_wzorcowy)!= = ) pom = pom->nastepny; /* wersja 3 - tez dobra i to zawsze */ pom = lista; znalazl = 0; while (pom!= NULL &&!znalazl) { if (porownaj_element(*pom, elem_wzorcowy) == = ) znalazl = 1; else pom = pom->nastepny;

Listy i stosy 6 Listy usuwanie elementu Musimy odróżnić czynność wyłączania elementu ze struktury danych od trwałego unicestwiania elementu i odzyskiwania zajmowanej pamięci (przy użyciu funkcji free). Najprostszy jest przypadek wyłączenia z listy pierwszego elementu, w pewnym sensie analogiczny do wstawiania elementu na początek listy: void usun_element(t_elem **lista, t_elem *elem) { /* wylacza pierwszy element z listy, i zwraca go */ /* w parametrze elem */ element = *lista; *lista = (*lista)->nastepny; } /* usun_element */ zauważmy, że procedura nie sprawdza, czy lista nie jest przypadkiem pusta (co spowodowałoby błąd wykonania). Wyłączanie z listy elementu, gdy mamy wskaźnik elementu poprzedniego poprzedni->nastepny = poprzedni->nastepny->nastepny;

Listy i stosy 7 Listy usuwanie elementu cd. Usunięcie z listy konkretnego elementu, do którego mamy wskaźnik, wymaga przeszukiwania. Nie zawsze mamy jawny wskaźnik elementu, który chcemy usunąć często wiemy tylko jaki element chcemy usunąć; możemy wtedy porównywać kolejno wszystkie elementy z elementem wzorcowym poszukać go. Jeśli przy przeszukiwaniu zapamiętamy położenie elementu szukanego w celu jego usunięcia będziemy musieli szukać ponownie. Schemat ten możemy powtarzać, aby usunąć z listy kolejne (wszystkie) elementy pasujące do elementu wzorcowego. Ostateczne kasowanie elementu ze zwalnianiem pamięci dynamicznej: free(elem); elem = NULL; Przypisanie wskaźnikowi wartości NULL ułatwia wykrywanie późniejszych błędnych odwołań do skasowanego elementu pamięci, ale im nie zapobiega!

Listy i stosy 8 Problemy ze wskaźnikami Typowym błędem zdarzającym się w programach ze wskaźnikami jest wypadnięcie przez koniec listy, co jest trochę podobne do przekroczenia zakresu indeksów tablicy. Wskaźniki umożliwiają jednak popełnianie znacznie więcej rodzajów błędów, np. używanie niezainicjowanych wskaźników, bądź wskaźników do skasowanych zmiennych dynamicznych. Takie błędy możemy łatwiej wykrywać systematycznie ustawiając nieużywane wskaźniki na NULL. Innym rodzajem błędów jest gubienie wskaźników do zmiennych dynamicznych (tworzenie nieużytków pamięci), bądź niezwalnianie niepotrzebnej pamięci dynamicznej, nawet jeśli nadal mamy do niej wskaźnik. Aby temu zaradzić dobrze jest systematycznie zwalniać każdy element pamięci dynamicznej w chwili, gdy stał się niepotrzebny. Jeszcze innym rodzajem błędów, jest przypadek wyczerpania pamięci dynamicznej.

Listy i stosy 9 Listy przeglądanie void przegladaj_element(t_elem); void przegladaj_liste(t_elem *lista) { /* wersja iteracyjna */ vo while (lista!= NULL) { przegladaj_element(*lista); lista = lista->nastepny; } } /* przegladaj_liste */ }

Listy i stosy 10 Listy z głową typedef struct elem { t_info info; struct elem *nastepny; } t_elem, *t_lista; typedef struct glowa { t_lista pierwszy; /* inne informacje o liscie, np. ostatni, dlugosc */ } t_listazg; /* i wtedy gdzies w jakiejs funkcji */ t_listazg baza_danych; /* powinna byc statyczna */ baza_danych.pierwszy = NULL; /* inicjacja listy */ baza_danych.dlugosc = 0; baza danych pierwszy: ostatni:... zmienne statyczne pamięć dynamiczna... info nast. info nast. info nast. info nast. NULL

Listy i stosy 11 Listy z głową cd Zastosowania głowy: przechowywanie dwóch wskaźników listy, pierwszego i ostatniego elementu, w celu np.: szybkiego dodawania węzłów na koniec listy, szybkiego włączania całej listy w środek innej listy, pojemnik na informacje: liczba elementów, liczba referencji, itp., umożliwienie usuwania pierwszego elementu listy, gdy wskaźnik listy jest skopiowany w kilku miejscach, np. w strukturach danych, znacznik na listach kołowych. Użycie głowy komplikuje procedury rekurencyjne.

Listy i stosy 12 Listy z wartownikiem Posługiwanie się listą ma pewne niespójności ponieważ operacje na wskaźniku listy czasem muszą być różne dla listy pustej i niepustej. Możemy to zmienić stosując zwykły schemat listy z dodatkiem wartownika, czyli wyróżnionego, dodatkowego elementu, którego treść jest nieistotna i nieużywana i który jest niewidoczny dla programisty wykorzystującego listę. np. lista z wartownikiem na początku lub na końcu jak poniżej zmienne statyczne pamięć dynamiczna lista wart lista ost.element info nast. info nast. info nast.... wartownik

Listy i stosy 13 Listy dwustronnie połączone typedef struct elem { t_info info; struct elem *nastepny; struct elem *poprzedni; } t_elem, *t_lista; void dodaj_element(t_lista *lista, t_elem *elem) { elem->nastepny = *lista; elem->poprzedni = NULL; if ((*lista)!= NULL) { elem->poprzedni = (*lista)->poprzedni; if ((*lista)->poprzedni!= NULL) (*lista)->poprzedni->nastepny = elem; (*lista)->poprzedni = elem; } else *lista = elem; } /* dodaj_element */

Listy i stosy 14 Listy dwustronnie połączone cd Listy dwustronnie połączone mają wiele cech odmiennych od zwykłych list, np. można się na nich cofnąć, łatwo włączać i usuwać elementy, dostęp do całej listy zapewnia wskaźnik dowolnego elementu. Jednak zasadnicze cechy list pozostają te same: sekwencyjny dostęp do elementów, brak istotnych korzyści z porządkowania elementów. Posługiwanie się listami dwustronnie połączonymi jest bardziej złożone niż zwykłymi listami, np. trzeba uważać na koniec listy po obu stronach. void usun_element(t_lista *lista, t_elem *elem) { /*wylaczanie dowolnego elementu z listy*/ if (elem->nastepny!= NULL) /*w el.nastepnym, zaktualizuj*/ elem->nastepny->poprzedni = elem->poprzedni; /*poprzedni*/ else if (elem->poprzedni!= NULL) /*jesli istn.poprzedni,*/ elem->poprzedni->nastepny = NULL; /*wpisz,ze nie ma nast.*/ if (elem->poprzedni!= NULL) /*w el.poprzednim,zaktualizuj*/ elem->poprzedni->nastepny = elem->nastepny; /*nastepny*/ else IF (elem->nastepny!= NULL) /*jesli istn.nastepny, */ elem->nastepny->poprzedni = NULL /*wpisz,ze nie ma poprz*/ else *lista = NULL; /*w tym przyp.lista jest pusta*/ if (*lista == elem) /*...*/; /*ten przyp.tez wymaga korekty*/ } /*usun_element*/

Listy i stosy 15 Listy kołowe zmienne statyczne pamięć dynamiczna lista... info nast. info nast. info nast. info nast. Listy kołowe nie mają fizycznego końca (ani początku), nie mają pustych wskaźników NULL i są całkowicie symetryczne. Nadają się np. do realizacji tzw. buforów kołowych (cyklicznych), służących np. do przechowywania pewnej ilości danych historycznych, automatycznie kasowanych w miarę zapisywania nowych danych czy też synchronizacji pracy funkcji programu (procesów).

Listy i stosy 16 Połączenia Często przydatne jest łączenie różnych modyfikacji podstawowego schematu listy, np.: lista z wartownikiem i wskaźnikiem ostatniego elementu, lista kołowa dwustronnie połączona, nie ma sensu dodawanie wartownika ani wskaźnika ostatniego elementu do listy kołowej, głowa przydaje się i można ją dodać do każdego rodzaju listy.

Listy i stosy 17 Abstrakcyjne typy danych (wstęp) Przez ATD rozumiemy określenie typu danych poprzez zdefiniowanie zestawu operacji, jakie mają być dlań dostępne. ATD wnoszą wyższy poziom abstrakcji niż typy danych definiowane w programach i pozwalają rozdzielić proces tworzenia programu na implementację ATD, oraz pisanie właściwego programu przy ich użyciu. Przykłady ATD: stosy (LIFO) dodaj na stos (push) zdejmij ze stosu (pop) sprawdź szczyt stosu (top) sensowna realizacja przez zwykłe listy, a także tablice statyczne kolejki chronologiczne (FIFO) dodaj na koniec usuń z początku podaj długość kolejki (?) sensowna realizacja przez listy ze wskaźnikiem ostatniego elementu, a także tablice statyczne (z zawijaniem ) bufory cykliczne

Listy i stosy 18 Zagadnienia podstawowe Podsumowanie 1. Co oznacza pojęcie zgubienia wskaźnika do zmiennej dynamicznej? 2. Czy można zdefiniować listę tylko i wyłącznie przy użyciu dynamicznych struktur danych? 3. W jaki sposób dodaje się i usuwa elementy z listy? 4. Jakie czynności należy wykonać by z listy usunąć element na który mamy wskaźnik? 5. Czy można zbudować listę, która nie będzie miała końca? Jeśli tak, ile elementów musi zawierać najkrótsza taka lista? 6. Jakie są różnice między listą a tablicą? 7. Wskaż wady i zalety list dwustronnie połączonych w porównaniu ze standardowymi listami jednokierunkowymi. 8. Czym różni się abstrakcyjna struktura danych od rzeczywistej struktury danych? 9. W jaki sposób definiuje się stos? Jak może być on zaimplementowany? Który rodzaj listy najlepiej nadaje się do jego implementacji? 10. Co to jest kolejka FIFO? Zagadnienia rozszerzające 1. Znajdź informacje na temat zastosowań abstrakcyjnych struktur danych typu stos i kolejka chronologiczna. Jakie inne abstrakcyjne struktury danych można wyróżnić?

Listy i stosy 19 2. Programy w trakcie swojego działania wykorzystują stos m.in. do przechowywania danych związanych z uruchamianymi funkcjami. Używając debugera gdb do uruchomienia dowolnego programu rekurencyjnego przeanalizuj zmiany zawartości stosu podczas działania programu. 3. Czym jest bufor pośredniczący przy wymianie danych pomiędzy procesami w systemie? Znajdź przykładowe implementacje. Zadania 1. Napisz dwa moduły: pierwszy implementujący listę jednokierunkową za pomocą zmiennych dynamicznych i drugi realizujący tę samą funkcję bazując na tablicy statycznej. Następnie przygotuj program pozwalający na przetestowanie poprawności napisanych modułów (driver). Program testujący i struktura całości powinny być na tyle uniwersalne, by zmiana modułu poddawanego testom nie wymagała zmian w kodzie całości, a jedynie zamianę dolinkowywanego modułu. 2. Napisz funkcję umożliwiającą usunięcie z listy wszystkich elementów zgodnych z podanym wzorcem. 3. Zapisz strukturę danych do przechowywania elementu listy dwukierunkowej zawieracjącej liczby zespolone. 4. Zaproponuj strukturę kolejki priorytetowej oraz sposób jej implementacji za pomocą struktur dynamicznych. 5. Zaproponuj implementację bufora cyklicznego. W jaki sposób definiuje się funkcje dodawania, usuwania, wyszukiwania elementów?