Programowanie komputerów. Jacek Lach Zakład Oprogramowania Instytut Informatyki Politechnika Śląska

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

Listy, kolejki, stosy

Wysokość drzewa Głębokość węzła

Wykład X. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2016 Janusz Słupik

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

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

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

Struktury danych: stos, kolejka, lista, drzewo

Drzewa wyszukiwań binarnych (BST)

ALGORYTMY I STRUKTURY DANYCH

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

Dynamiczne struktury danych

Porządek symetryczny: right(x)

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

Wykład 6. Drzewa poszukiwań binarnych (BST)

Wykład 2. Drzewa poszukiwań binarnych (BST)

Drzewa poszukiwań binarnych

Wstęp do programowania

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

Podstawy Informatyki. Metody dostępu do danych

Stos LIFO Last In First Out

Drzewo. Drzewo uporządkowane ma ponumerowanych (oznaczonych) następników. Drzewo uporządkowane składa się z węzłów, które zawierają następujące pola:

< K (2) = ( Adams, John ), P (2) = adres bloku 2 > < K (1) = ( Aaron, Ed ), P (1) = adres bloku 1 >

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

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Algorytmy i struktury danych Laboratorium 7. 2 Drzewa poszukiwań binarnych

Algorytmy i Struktury Danych

Wykład 3. Złożoność i realizowalność algorytmów Elementarne struktury danych: stosy, kolejki, listy

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

Algorytmy i Struktury Danych.

Drzewa poszukiwań binarnych

część 16 struktury rekurencyjne i ich zastosowania drzewa binarne, algorytmy rekurencyjne dla drzew binarnych

Programowanie obiektowe

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

Algorytmy i Struktury Danych

Programowanie obiektowe

Programowanie obiektowe

Wstęp do programowania

E S - uniwersum struktury stosu

Struktura danych. Sposób uporządkowania informacji w komputerze. Na strukturach danych operują algorytmy. Przykładowe struktury danych:

Programowanie obiektowe i C++ dla matematyków

. Podstawy Programowania 2. Drzewa bst - część pierwsza. Arkadiusz Chrobot. 22 maja 2016

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

Drzewa BST i AVL. Drzewa poszukiwań binarnych (BST)


Algorytmy i Struktury Danych.

Algorytmy i struktury danych. wykład 5

Tadeusz Pankowski

Wykład 7 Abstrakcyjne typy danych słownik (lista symboli)

Struktury. Przykład W8_1

Algorytmy i Struktury Danych

Teoretyczne podstawy informatyki

Wstęp. #define include include include include include include

Abstrakcyjne struktury danych w praktyce

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

Algorytmy i. Wykład 5: Drzewa. Dr inż. Paweł Kasprowski

Drzewa binarne. Drzewo binarne to dowolny obiekt powstały zgodnie z regułami: jest drzewem binarnym Jeśli T 0. jest drzewem binarnym Np.

Podstawowe struktury danych

Struktury dynamiczne

Struktura danych. Sposób uporządkowania informacji w komputerze. Na strukturach danych operują algorytmy. Przykładowe struktury danych:

PLAN WYKŁADU BAZY DANYCH INDEKSY - DEFINICJE. Indeksy jednopoziomowe Indeksy wielopoziomowe Indeksy z użyciem B-drzew i B + -drzew

prowadzący dr ADRIAN HORZYK /~horzyk tel.: Konsultacje paw. D-13/325

Podstawy Programowania. Listy i stosy

WYŻSZA SZKOŁA INFORMATYKI STOSOWANEJ I ZARZĄDZANIA

Algorytmy i. Wykład 3: Stosy, kolejki i listy. Dr inż. Paweł Kasprowski. FIFO First In First Out (kolejka) LIFO Last In First Out (stos)

Wskaźniki. Programowanie Proceduralne 1

Programowanie obiektowe i C++ dla matematyków

Wykład 2. Drzewa zbalansowane AVL i 2-3-4

WSTĘP DO INFORMATYKI. Drzewa i struktury drzewiaste

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

ZASADY PROGRAMOWANIA KOMPUTERÓW ZAP zima 2014/2015. Drzewa BST c.d., równoważenie drzew, kopce.

STRUKTURY DANYCH I ZŁOŻONOŚĆ OBLICZENIOWA STRUKTURY DANYCH I ZŁOŻONOŚĆ OBLICZENIOWA. Część 3. Drzewa Przeszukiwanie drzew

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).

Lista dwukierunkowa - przykład implementacji destruktorów

ALGORYTMY I STRUKTURY DANYCH

Struktury czyli rekordy w C/C++

Podstawy Informatyki. Wykład 6. Struktury danych

Wstęp do programowania. Drzewa podstawowe techniki. Piotr Chrząstowski-Wachtel

Tablice, funkcje - wprowadzenie

Drzewa czerwono-czarne.

ALGORYTMY I STRUKTURY DANYCH

DYNAMICZNE PRZYDZIELANIE PAMIECI

Typy złożone. Struktury, pola bitowe i unie. Programowanie Proceduralne 1

ZASADY PROGRAMOWANIA KOMPUTERÓW

Każdy węzeł w drzewie posiada 3 pola: klucz, adres prawego potomka i adres lewego potomka. Pola zawierające adresy mogą być puste.

Indeksy. Wprowadzenie. Indeksy jednopoziomowe indeks podstawowy indeks zgrupowany indeks wtórny. Indeksy wielopoziomowe

Poprawność semantyczna

Algorytmy i Struktury Danych.

Przykładowe B+ drzewo

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

TABLICE W JĘZYKU C/C++ typ_elementu nazwa_tablicy [wymiar_1][wymiar_2]... [wymiar_n] ;

Teoretyczne podstawy informatyki

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

Algorytmy i Struktury Danych, 9. ćwiczenia

Plan wykładu. Klucz wyszukiwania. Pojęcie indeksu BAZY DANYCH. Pojęcie indeksu - rodzaje indeksów Metody implementacji indeksów.

Wykład 8. Drzewa AVL i 2-3-4

Dynamiczne struktury danych

Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04

Lista liniowa dwukierunkowa

Programowanie obiektowe i C++ dla matematyków

Transkrypt:

Programowanie komputerów Jacek Lach Zakład Oprogramowania Instytut Informatyki Politechnika Śląska

Plan Dynamiczne struktury danych Lista jednokierunkowa Lista dwukierunkowa Lista podwieszana Graf Drzewa BST

Dynamiczne struktury danych Struktura dynamiczna struktura tworzona w trakcie działania programu Najczęstsze zastosowanie tworzenie abstrakcyjnych typów/struktur danych (szczególnie przydatne w zastosowaniach algorytmicznych)

Dynamiczne struktury danych Przykłady struktur: lista jednokierunkowa lista dwukierunkowa drzewo graf UWAGA: każdą z w/w struktur można zrealizować stosując struktury statyczne (np. tablice)

Lista jednokierunkowa Składa się z pewnej liczby węzłów (elementów), z których każdy zawiera pewien zestaw danych adres następnego elementu Dodatkowo należy zapamiętać adres pierwszego węzła (tzw. głowa) Ostatni element wyróżnia się poprzez nadanie adresowi określonej wartości, którą można odpowiednio zinterpretować, tzn. inaczej niż adres (w języku C: NULL)

Lista jednokierunkowa Głowa (NULL)

Definicja elementu Elementem listy jest najczęściej zmienna typu struktura #define MAX_ROZMIAR 50; /* definicja elementu listy */ struct elem_tag { char wyraz[max_rozmiar+1]; struct elem_tag *nast; ; /* korzystamy ze zmiennych wskaźnikowych glowa jeśli jest zmienna statyczna, jest inicjowana wartością 0, czyli NULL */ struct elem_tag *glowa;

Wyświetlanie listy Styl Pascala: void wypisz ( char *Akomunikat ) { struct elem_tag *p; printf("\n%s \n", Akomunikat); /* wersja odpowiadająca programowi w "pascalu" */ p = glowa; while (p) { printf ( "kolejny wyraz to: %s\n", p->wyraz ); p = p->nast;

Wyświetlanie listy Styl C: void wypisz (char *Akomunikat) { struct elem_tag *p; printf("\n%s \n", Akomunikat); for(p=glowa;p;p=p->nast) printf ( "kolejny wyraz to: %s\n", p->wyraz );

Metoda fifo glowa ostatni nowy

Metoda fifo glowa ostatni nowy

Metoda fifo /* wczytanie wyrazow i utworzenie listy zgodnie z zasadą nowy na końcu listy */ void wczytaj_fifo ( void ) { char buf[max_rozmiar+1]; struct elem_tag *nowy, *ostatni; printf ( "wpisz [%s] aby zakonczyc\n", KONIEC ); // jesli wczytywanym wyrazem nie jest 'koniec' while (wczytaj_jeden_wyraz(buf)) { /* próba przydzielenia pamięci */ nowy = ( struct elem_tag* )malloc( sizeof(struct elem_tag) ); /* prawdopodobnie brak pamięci */ if (!nowy) exit(1);

Metoda fifo /* kopiowanie wczytanego wyrazu */ strcpy( nowy->wyraz, buf ); nowy->nast=null; /* pierwszy element listy - głowa wskazuje NULL */ if (!glowa) glowa=nowy; else ostatni->nast=nowy; /* nowo utworzony element listy jest jej ostatnim elementem */ ostatni=nowy;

Metoda lifo glowa ostatni nowy

Metoda lifo glowa nowy ostatni

Metoda lifo /* wczytanie wyrazow i utworzenie listy zgodnie z zasadą nowy na początku listy */ void wczytaj_lifo ( void ) { char buf[max_rozmiar+1]; struct elem_tag *poprzednia_glowa; printf ( "wpisz [%s] aby zakonczyc\n", KONIEC ); /* jesli wczytywanym wyrazem nie jest 'koniec' */

Metoda lifo while (wczytaj_jeden_wyraz(buf)) { /* zapamietuje poprzednia glowe */ poprzednia_glowa=glowa; /* próba przydzielenia pamięci */ glowa = ( struct elem_tag* ) malloc( sizeof(struct elem_tag) ); /* prawdopodobnie brak pamięci */ if (!glowa) exit(1); /* wczytanego wyrazu */ strcpy( glowa->wyraz, buf ); /* lacze z poprzednia glowa */ glowa->nast=poprzednia_glowa;

Usuwanie listy z pamięci /* usunięcie listy z pamięci */ void kasuj ( void ) { struct elem_tag *p; /* zaczynamy od pierwszego elementu */ while (glowa) { /* zapamiętanie adresu następnego elementu */ p = glowa->nast; /* zwolnienie pamięci */ free (glowa); /* glowa wskazuje na kolejny element */ glowa = p;

Lista jednokierunkowa Wstawianie elementu na pewnej pozycji : wartości atrybutów numer pozycji na której należy wstawić element

Wstawianie Głowa (NULL)

Wstawianie Metoda 1 Przesuń się na element o danym numerze Wstaw element do listy Uzupełnij połączenia

Wstawianie Głowa (NULL)

Dodawanie v1 void dodaj_po_elem_v1(struct elem_tag *q, char *wyraz) { struct elem_tag *nowy; /* próba przydzielenia pamięci kolejnemu elementowi */ nowy = ( struct elem_tag* ) malloc( sizeof(struct elem_tag) ); /* prawdopodobnie brak pamięci */ if (!nowy) exit(1); /* przepisanie wczytanego wyrazu */ strcpy( nowy->wyraz, wyraz );

Dodawanie v1 /* połączenie listy */ /* na koncu listy zostanie skopiowany NULL */ nowy->nast = q->nast; q->nast = nowy; void dodaj_na_poz_v1(int poz, char *wyraz) { /* wyszukaj wskaźnik na kolejną pozycję */ for(p = glowa ;p && poz; p=p->nast, poz--); if (p) dodaj_po_elem_v1(p, wyraz);

Dodawanie v1 Wady Trudno dodać element na pozycji 0 By dodać element na pozycji 0 należałoby modyfikować wskaźnik na pierwszy element, co skomplikowałoby dodatkowo kod Rozwiązanie Wykorzystać wskaźniki na wskaźniki

Dodawanie Głowa (NULL)

Dodawanie Głowa Głowa struct elem_tag * Głowa struct elem_tag **

Dodawanie v2 void dodaj_po_v2(struct elem_tag **pp, char *wyraz){ /* próba przydzielenia pamięci kolejnemu elementowi */ p = ( struct elem_tag* )malloc( sizeof(struct elem_tag) ); if (!p) exit(1); /* prawdopodobnie brak pamięci */ /*przepisanie wczytanego wyrazu */ strcpy( p->wyraz, wyraz ); // p jest wskaznikiem na nowoutworzony rekord, zawierajacy już slowo /* połączenie listy */ p->nast = *pp; // pp jest adresem glowy, *pp jest glowa, a zatem wskaznikem // na pierwszy element listy; operacja powoduje, ze kopiujemy glowe // do pola nast *pp = p; // *pp jest glowa, kopiuje wskazania na nowoutworzony // element do glowy

Dodawanie v2 void dodaj_na_pozycji_v2(int poz, char *wyraz) { struct elem_tag **pp; /* wyszukaj wskaźnik na kolejną pozycję */ for (pp = &glowa ;*pp && poz; pp=&((*pp)->nast), poz--); // pp jest adresem glowy w PAO // jeżeli glowa istniala if (pp) dodaj_po_v2(pp, wyraz);

Lista dwukierunkowa Elementem listy dwukierunkowej jest najczęściej zmienna typu struktura #define MAX_STR 50; struct elem_tag { /* dane */ int pole1; char [MAX_STR+1] pole2; double pole3; /* adres następnego elementu listy */ struct elem_tag *nast, *poprz; glowa_1, glowa_2

Lista dwukierunkowa Składowe listy wielokierunkowej : wartości atrybutów Wskaźnik na następny element Wskaźnik na poprzedni element Dwa wskaźniki na elementy (pierwszy i ostatni)

Lista dwukierunkowa Głowa_2 Głowa_1 (NULL) (NULL)

Wstawianie elementu Głowa_2 Głowa_1 (NULL) (NULL)

Tworzenie listy void dodaj_do_listy(char *buf) { /* próba przydzielenia pamięci elementowi */ struct elem_tag *p= (struct elem_tag* ) malloc( sizeof(struct elem_tag) ); if (!p) exit(1); /* prawdopodobnie brak pamięci */ strcpy( p->wyraz, buf ); /*przepisanie wczytanego wyrazu */ if (!glowa_1) /* jesli lista nie istniała */ { glowa_1=glowa_2=p; p->nast=p->poprz=0; else /* jeśli był choć jeden element listy */ { glowa_2->nast = p; p->poprz = glowa_2; glowa_2 = p;

Metoda wstawiania Mamy trzy przypadki Dodawanie elementu na pozycji 0 Dodawanie elementu na pozycji n, gdzie 0<=n<liczba elementów listy Dodawanie elementu jako ostatniego elementu listy Pominiemy jawne rozróżnianie tych warunków (ćwiczenie) i przejdziemy do bardziej wyrafinowanego rozwiązania

Wstawianie na danej pozycji void dodaj_na_pozycji_v2(int poz, char *wyraz) { struct elem_tag **pp; for(pp = &glowa_1 ;*pp && poz; pp=&((*pp)->nast), poz--); if (pp) dodaj_po_v2(pp, wyraz);

Wstawianie na danej pozycji void dodaj_po_v2(struct elem_tag **q, char *wyraz) { struct elem_tag *p = (struct elem_tag* ) malloc( sizeof(struct elem_tag) ); if (!p) exit(1); /* prawdopodobnie brak pamięci */ strcpy( p->wyraz, wyraz ); p->nast = *q; if(*q) { p->poprz=(*q)->poprz; (*q)->poprz = p; else { p->poprz=glowa_2; glowa_2 = p; *q = p;

Wstawianie na danej pozycji inny zapis void dodaj_po_compact(struct elem_tag **q, char *wyraz) { /* n - adres elementu, który ma stać się następny */ /* p - adres pola poprz do zmodyfikowania, adres pola poprz następnego rekordu lub głowa */ struct elem_tag *n = *q, **p = n? &(n->poprz):&glowa_2; /* q jest adresem (głowy lub pola nast) do zmodyfikowania */ /* wartość wskazania *q została zapamiętana w n, tak więc if(!(*q = ( struct elem_tag* )malloc( sizeof(struct elem_tag)))) exit(1); strcpy( (*q)->wyraz, wyraz ); (*q)->nast = n; /* połączenie z następnym */ (*q)->poprz = *p; /* pole poprz kopiujemy z rekordu, który stał się następny */ *p = *q; /* pole poprz z następnego rekordu na nasz */

Wstawianie na danej pozycji inny zapis Uwaga: Jak widać na poprzednim przykładzie, pewne konstrukcje języka C mogą prowadzić do zmniejszania się czytelności kodu. Należy raczej unikać takiego stylu programowania, chyba że istnieją ku temu obiektywne powody (wielkość kodu, szybkość działania itp.)

Struktury danych implementowane jako listy Stos (Stack) Last In First Out (LIFO) Operacja push Operacja pop Kolejka (Queue) First In First Out (FIFO) Operacja put Operacja get

Listy podwieszane: definicje Mamy to do czynienia z sytuacją, gdy jedna z list o organizacji liniowej, zawiera wskaźniki do innych list, niejako podwieszonych pod listą główną Elementem listy dwukierunkowej jest najczęściej zmienna typu struktura

Listy podwieszane struct elem_item { /* jakieś dane */ /* adres elementu */ struct elem_item *dol; struct elem_tag { /* jakieś dane */ /* następny element */ struct elem_tag * nast; /* lista podwieszana */ struct elem_item *dol; glowa;

Listy podwieszane Głowa_1 (NULL) D D (NULL) D D D D (NULL) D (NULL)

Szczególny przypadek: graf Głowa_1 o wierzchołku 1 o wierzchołku 2 o wierzchołku 3 (NULL) 1 2 3 D D (NULL) D D D D (NULL) D (NULL)

Zalety reprezentacji Mała objętość w porównaniu do metod opartych o tablice, takich jak macierz sąsiedztwa, tablice wierzchołków wchodzących, wychodzących itp. Wady zmniejszenie czytelności algorytmów grafowych Dany wierzchołek grafu G=(N,E) można znaleźć w O( N ) krokach Wierzchołek można dodać w O(1) krokach Krawędź można znaleźć, dodać lub usunąć w O( N + E ) krokach (znalezienie wierzchołka, a następnie znalezienie, dodanie lub usunięcie krawędzi wychodzących) Reprezentacja zalecana dla grafów dla których N 2 >> E ; w przypadku grafów o dużej liczbie krawędzi w stosunku do kwadratu liczby wierzchołków lepiej zastosować struktury statyczne

Drzewa binarne korzeń Data Data Data Data liście Data Data Data

Drzewo BST (Binary Search Tree) Każdy element zawiera klucz Klucze są takiej postaci, że można je uporządkować liniowo Wszystkie elementy w lewym poddrzewie mają klucz mniejszy niż klucz rodzica Wszystkie elementy w prawym poddrzewie mają klucze większe niż klucz poddrzewa

BST przykład lewe poddrzewo; wszystkie klucze lewego poddrzewa są mniejsze niż klucz korzenia 4 korzeń 6 12 15 liść 17 19 22 9 20 25 prawe poddrzewo; wszystkie klucze prawego poddrzewa są większe niż klucz korzenia

BST Operacje: Poszukiwanie elementu Poszukiwanie poprzednika Poszukiwanie następcy Poszukiwanie minimum Poszukiwanie maksimum Wstawianie elementów Usuwanie elementów Wypisywanie elementów

Rekord drzewa BST typedef struct bstel { int data; struct bstel *left; struct bstel *right; bn;

Poszukiwanie elementu int find(int key, struct bstel *node) { if (!node) return 0; /* nie znaleziono */ if (key == node->data) return 1; /* znaleziono */ if (key < node->data) return find(key, node->left); else return find(key, node->right);

Wstawianie elementu int insert(bn *p, bn **root) { if (*root && (*root)->data == p->data) return 1; /* już jest w drzewie */ if (!*root) { /* drzewo bez elementów */ *root = p; return 0; else if (p->data > (*root)->data) insert(p,&((*root)->right)); else insert(p,&((*root)->left)); return 0;

Wstawianie elementu int ins_el(int key, bn **root) { bn *p; p = (bn*)malloc(sizeof(bn)); if (!p) return -1; /* brak pamięci */ p->data = key; p->left = p->right = NULL; return insert(p,root);

Poszukiwanie minimum struct bstel* min(struct bstel *node) { if (!node) return NULL; /* błąd */ while (node->left) node = node->left; return node;

Poszukiwanie maksimum struct bstel* max(struct bstel *node) { if (!node) return NULL; /* błąd */ while (node->right) node = node->right; return node;

Znajdowanie poprzednika i następnika Wartość succ(17)=19 Jak znaleźć taki węzeł: jeśli węzeł ma prawe poddrzewo, zwróć minimalny wierzchołek w prawym poddrzewie jeśli węzeł nie ma prawego poddrzewa, znajdź wierzchołek, do którego lewego poddrzewa należy dany węzeł jeśli warunki nie są spełnione, węzeł nie posiada następnika (posiada maksymalną wartość) 4 15 6 19 12 17 22 9 20 25

Znajdowanie następnika struct bstel* succ(struct bstel *node) { bn* y; if (!node) return NULL; /* błąd */ if (node->right) return min(node->right); y = parent(node); /* zaimplementować */ while (y && node==y->right) { node = y; y = parent(y); return y;

Usuwanie elementów Załóżmy, że należy usunąć x Jeśli x ma obydwa poddrzewa, znajdź succ(x) i przesuń go na miejsce x 15 Jeśli x ma tylko jedno poddrzewo, zastąp x tym poddrzewem Jeśli x jest liściem, po prostu usuń x 4 6 19 12 17 22 9 20 25

Wydruk całego drzewa void print_tree(bn *node) { if (node) { print_tree(node->left); printf("%d ",node->data); print_tree(node->right);

Wykorzystanie main() { bn *root = NULL; /* na początku puste drzewo */ ins_el(10,&root); /* budowanie drzewa */ ins_el( 6,&root);... ins_el( 7,&root); ins_el(23,&root); ins_el(11,&root); print_tree(root); /* powinno być posortowane! */ printf( \n %d \n", min(root)->data); printf("find(%d)=%d\n",13,find(13,root)); return 0;