Algorytmy i Struktury Danych. Podstawowe struktury danych. Wykład na podstawie ksiażki Roberta Sedgewicka i Kevina Wayne: Algorithms. Furth Edition. Princeton University dr hab. Bożena Woźna-Szcześniak Jan Długosz University, Poland Wykład 6 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 1 / 76
Plan Motywacja Motto Abstarkcyjne struktury danych Liniowe struktury danych Struktury danych modyfikuja świat, w którym realizowany jest algorytm, usprawniaja działanie, ułatwiaja zrozumienie algorytmu. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 2 / 76
Motywacja 2 0 5 3 4 1 Do tej pory zajmowaliśmy się tylko jednym typem struktur danych: tablicami (jedno-i wielowymiarowymi). Ich długość się nie zmienia, czyli jest to statyczna struktura danych. Statyczność oznacza, że albo konieczna wielkość tablicy jest znana z góry, albo tracimy ogromna ilość pamięci. W wielu przypadkach chcemy mieć dynamiczna strukturę danych, której długość zmienia się zgodnie z potrzebami. Dlatego też potrzebujemy struktury, która pozwala na przechowywanie elementów w fizycznie różnym porzadku. 2 5 4 0 3 1 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 3 / 76
Struktury danych Struktury danych, sa zaawansowanymi pojemnikami na dane, które gromadza je i układaja w odpowiedni sposób. Różnorodność struktury danych jest ogromna, a dla każdej znaleziono wiele zastosowań oraz interesujacych algorytmów. Struktury danych stosuje się do przetwarzania informacji zgromadzonych w innych strukturach. Struktury danych sa fundamentalnym narzędziem programisty i ich znajomość jest niezbędna. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 4 / 76
programy = algorytmy + struktury danych Uczac się algorytmiki nie wolno zapomnieć o strukturach danych!!! Informatyk szwajcarski, profesor Niklaus Wirth (twórca języka Pascal i Modula-2). Źródło:https: //pl.wikipedia.org/wiki/ Niklaus_Wirth Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 5 / 76
Abstrakcyjna struktura danych a struktura danych Abstrakcyjna struktura danych (ASD), to zbiór danych elementarnych wraz z dobrze zdefiniowanym na nich zbiorem operacji. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 6 / 76
Abstrakcyjna struktura danych a struktura danych Abstrakcyjna struktura danych (ASD), to zbiór danych elementarnych wraz z dobrze zdefiniowanym na nich zbiorem operacji. Różnica pomiędzy struktura danych a abstrakcyjna struktura danych: Struktura danych jest pewna implementacja konkretnej abstrakcyjnej struktury danych przeznaczonej do pracy na konkretnym komputerze (chodzi o jego architekturę) i systemie operacyjnym. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 6 / 76
Abstarkcyjne struktury danych Liniowe abstrakcyjne struktury danych: Stos Kolejka Listy: jednokierunkowe listy niecykliczne, dwukierunkowe listy niecykliczne, jednokierunkowe listy cykliczne (pierścienie jednokierunkowe), dwukierunkowe listy cykliczne (pierścienie dwukierunkowe). Tablice haszujace Drzewiaste struktury danych Drzewa poszukiwań binarnych Kopce Drzewa AVL Drzewa Czerwono-Czarne... Grafy Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 7 / 76
Stos Stos (ang pushdown stack, lub stack)jest struktura liniowo uporzadkowanych danych, z których tylko ostatni element, zwany wierzchołkiem lub szczytem stosu, jest w danym momencie dostępny. Cecha charakterystyczna stosujest to, że dane sa zapisywane i pobierane metoda Last-In-First-Out (LIFO) (pierwszy wchodzi, ostatni wychodzi) tj.: nowe elementy odkładamy tylko na szczyt stosu, usuwamy jedynie szczyt stosu (czyli element ostatnio dodany). Działanie stosu jest często porównywane do stosu talerzy: nie można usunać talerza znajdujacego się na dnie stosu nie usuwajac wcześniej wszystkich innych. nie można także dodać nowego talerza gdzieś indziej, niż na sama górę. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 8 / 76
Stos - operacje Niech S = (d 1, d 2,..., d n ) oznacza stos, wtedy: Odkładanie elementu na stos: push(s, d) = (d, d 1, d 2,..., d n ) Pobieranie elementu ze stosu: pop(s) = (d 2,..., d n ), o ile n > 1 Pobieranie elementu ze szczytu stosu bez jego usuwania: peek(s) = d 1 Sprawdzanie niepustości stosu: isempty(s) wtw., gdy n = 0 Pop i Push d 1 Szczyt stosu d 2 d 3 d 4 d 5 NULL Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 9 / 76
Stos liczb całkowitych kod Java I import java.util.nosuchelementexception; import java.util.scanner; public class Stos { private Node top; // szczyt stosu private int n; // rozmiar stosu // klasa pomocnicza private static class Node { private int item; private Node next; //Inicjalizuje pusty stos public Stos() { top = null; n = 0; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 10 / 76
Stos liczb całkowitych kod Java II //Zwraca true, gdy stos jest pusty. public boolean isempty() { return top == null; //Zwraca liczbe elementow w stosie. public int size() { return n; //Dodaje element do stosu. public void push(int item) { Node oldtop = top; top = new Node(); top.item = item; top.next = oldtop; n++; //Usuwa i zwraca szczyt stosu Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 11 / 76
Stos liczb całkowitych kod Java III public int pop() { if (isempty()) throw new NoSuchElementException("Stos pusty"); int item = top.item; // element do zwrotu top = top.next; n--; return item; // usuwa szczyt stosu // zwraca zachowany element //zwraca szczyt stosu, ale go nie usuwa public int peek() { if (isempty()) throw new NoSuchElementException("Stos pusty"); return top.item; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 12 / 76
Zastosowanie stosu - postać binarna danej liczby całkowitej I // zalezy od klasy Stos public class Binarna { public static void main(string[] args) { Stos stack = new Stos(); Scanner in = new Scanner(System.in); System.out.println("Podaj liczbe"); int n = in.nextint(); int m = n; while (n > 0) { stack.push(n % 2); n = n / 2; System.out.println("Postac binarna "+m+": "); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 13 / 76
Zastosowanie stosu - postać binarna danej liczby całkowitej II while (!stack.isempty()) System.out.print(stack.pop()); System.out.println(); in.close(); $ java Stos Podaj liczbę 9 Postac binarna liczby: 9 1001 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 14 / 76
Zastosowanie stosu I Odwracanie danych Poniższa klasa Reverse odwraca kolejność liczb całkowitych wprowadzanych ze standardowego wejścia, bez konieczności wcześniejszego określania ich liczby. // zalezna od klasy Stos import java.util.scanner; public class Reverse { public static void main(string[] args) { Stos stack = new Stos(); Scanner in = new Scanner(System.in); System.out.println("Podaj dana!= 0"); int n = in.nextint(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 15 / 76
Zastosowanie stosu II while (n!=0){ stack.push(n); n = in.nextint(); while (!stack.isempty()){ System.out.print( stack.pop() + " "); System.out.println(); in.close(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 16 / 76
Zastosowanie stosu III.../stos-java$ javac Reverse.java Stos.java.../stos-java$ java Reverse Podaj dane!= 0 1 2 3 4 5 6 7 8 9 10 0 10 9 8 7 6 5 4 3 2 1 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 17 / 76
Stos liczb typu double kod Java I import java.util.nosuchelementexception; import java.util.scanner; public class StosDouble { private Node top; private int n; private static class Node { private double item; private Node next; public StosDouble() { top = null; n = 0; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 18 / 76
Stos liczb typu double kod Java II public boolean isempty() { return top == null; public int size() { return n; public void push(double item) { Node oldtop = top; top = new Node(); top.item = item; top.next = oldtop; n++; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 19 / 76
Stos liczb typu double kod Java III public double pop() { if (isempty()) throw new NoSuchElementException("Stos pusty"); double item = top.item; top = top.next; n--; return item; public double peek() { if (isempty()) throw new NoSuchElementException("Stos pusty"); return top.item; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 20 / 76
Stos łańcuchów znaków kod Java I import java.util.nosuchelementexception; import java.util.scanner; public class StosStringow { private Node top; private int n; // klasa pomocnicza private static class Node { private String item; private Node next; public StosStringow() { top = null; n = 0; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 21 / 76
Stos łańcuchów znaków kod Java II public boolean isempty() { return top == null; public int size() { return n; public void push(string item) { Node oldtop = top; top = new Node(); top.item = item; top.next = oldtop; n++; public String pop() { Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 22 / 76
Stos łańcuchów znaków kod Java III if (isempty()) throw new NoSuchElementException( "Stos pusty"); String item = top.item; top = top.next; n--; return item; public String peek() { if (isempty()) throw new NoSuchElementException( "Stos pusty"); return top.item; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 23 / 76
Obliczanie wyrażeń arytmetycznych Definicja rekurencyjna Wyrażenie arytmetyczne jest albo liczba albo lewym nawiasem, po którym następuje wyrażenie arytmetyczne, po którym następuje operator, po którym następuje kolejne wyrażenie arytmetyczne, po którym następuje prawy nawias. Powyższa definicja dla uproszczenia dotyczy tylko w pełni nawiasowanych wyrażeń arytmetycznych, które precyzyjnie określaja, które operatory maja zastosowanie do których argumentów. Przykłady w pełni nawiasowanych wyrażeń arytmetycznych w postaci infiksowej ( ( 1 + 5.0 ) / 2 ) ( ( 1 + sqrt ( 5.0 ) ) / 2.0 ) Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 24 / 76
Algorytm Dijkstry z dwoma stosami do obliczania wyrażeń arytmetycznych w postaci infiksowej I Najprostszy algorytm przeznaczony do obliczania wyrażeń arytmetycznych w postaci infiksowej został opracowany przez E. W. Dijkstrę w latach 60. XX wieku i wykorzystuje dwa stosy: jeden dla operandów i jeden dla operatorów. Założenia pokazanego rozwiazania Dla uproszczenia obsługiwane sa tylko następujace operatory binarne: mnożenia ( ), dodawania(+), odejmowania( ), dzielenie(/), oraz potęgowanie(ˆ) i operator pierwiastka kwadratowego sqrt, który przyjmuje tylko jeden argument. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 25 / 76
Algorytm Dijkstry z dwoma stosami do obliczania wyrażeń arytmetycznych w postaci infiksowej II Idea algorytmu Wyrażenie składa się z nawiasów, operatorów i argumentów (liczb). Przechodzac od lewej do prawej i biorac te elementy pojedynczo, manipulujemy stosami według czterech możliwych przypadków, w następujacy sposób: Odłóż operandy (argumenty) na stos operandów. Odłóż operatory na stos operatorów. Ignoruj lewe nawiasy. Po napotkaniu prawego nawiasu, zdejmij operator, zdejmij wymagana liczbę argumentów i odłóż na stos operandów obliczony wynik. Po przetworzeniu końcowego prawego nawiasu na stosie operandów znajduje się tylko jedna wartość, która jest wartościa obliczanego wyrażenia. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 26 / 76
Algorytm Dijkstry z dwoma stosami - kod w Javie I // zalezy od klasy StosDouble.java i // od klasy StosStringow.java public class Dijkstra2StackAlgorithm { public static void main(string[] args) { StosStringow operator = new StosStringow(); StosDouble val = new StosDouble(); String str = "( ( 1 + sqrt ( 5.0 ) ) / 2.0 )"; String[] tokens = str.split(" "); for (String s : tokens) { if (s.equals("(")) ; else if (s.equals("+")) operator.push(s); else if (s.equals("-")) operator.push(s); else if (s.equals("*")) operator.push(s); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 27 / 76
Algorytm Dijkstry z dwoma stosami - kod w Javie II else if (s.equals("/")) operator.push(s); else if (s.equals("^")) operator.push(s); else if (s.equals("sqrt")) operator.push(s); else if (s.equals(")")) { String op = operator.pop(); double v = val.pop(); if (op.equals("+")) v = val.pop() + v; else if (op.equals("-")) v = val.pop() - v; else if (op.equals("*")) v = val.pop() * v; else if (op.equals("/")) v = val.pop() / v; else if (op.equals("^")) v = Math.pow(val. pop(), v); else if (op.equals("sqrt")) v=math.sqrt(v); val.push(v); else val.push(double.parsedouble(s)); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 28 / 76
Algorytm Dijkstry z dwoma stosami - kod w Javie III System.out.println(val.pop()); Przykłady wykonania $java Dijkstra2StackAlgorithm ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) 101.0 $java Dijkstra2StackAlgorithm ( ( 1 + sqrt ( 5.0 ) ) / 2.0 ) 1.618033988749895 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 29 / 76
Notacja Prefiksowa lub Postfiksowa I Dwie najbardziej znane alternatywy do infiksowego zapisu wyrażenia arytmetycznego, to beznawiasowa notacja: prefiksowa operator jest pisany przed jego operandami. postfiksowa operator jest pisany po jego operandach. Prefiksowa reprezentacja wyrażenia arytmetycznego nazywana jest notację polska, gdyż opracował ja polski logik Jan Łukasiewicz w latach 20-tych XX wieku. Postfiksowa reprezentacja wyrażenia arytmetycznego nazywana jest odwrotna notacja polska(onp, ang. Reverse Polish Notation RPN), gdyż została opracowana przez australijskiego naukowca Charlesa Hamblina jako odwrócenie notacji polskiej na potrzeby zastosowań informatycznych. Zaleta odwrotnej notacji polskiej jest to, że priorytety operatora moga być reprezentowane przez kolejność ich występowania nie potrzeba nawiasów, aby reprezentować wyrażenie RPN Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 30 / 76
Notacja Prefiksowa lub Postfiksowa II Odwrotna notacja polska jest powszechnie stosowana w kompilatorach języków wysokiego poziomu do obliczania wartości wyrażeń arytmetycznych. Przykłady: Notacja infiksowa ONP ( 3 + 2 ) 3 2 + ( 3 + ( 2 * 5 ) ) 3 2 5 * + ( ( ( ( 2 + 3 ) * 5 ) - 7 ) / 6 ) 2 3 + 5 * 7-6 / ( 2 * ( 5 + 2 ) ) 2 5 2 + * ( ( 7 + 3 ) * ( ( 5-2 ) ^2 ) ) 7 3 + 5 2-2 ^* ( 4 / ( ( 3-1) ^( 2 * 3 ) ) ) 4 3 1-2 3 * ^/ Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 31 / 76
Zamiana postaci infiksowej wyrażenia w pełni nawiasowanego do postaci ONP kod Java I import java.util.scanner; public class InfixToPostfix { public static void main(string[] args) { StosStringow stack = new StosStringow (); Scanner in = new Scanner(System.in); System.out.print("Podaj wyrazenie "); System.out.print("arytmetyczne zakonczone"); System.out.println(" q "); String s = in.next(); while (!s.equals("q")) { s = in.next(); if (s.equals("+")) stack.push(s); else if (s.equals("-")) stack.push(s); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 32 / 76
Zamiana postaci infiksowej wyrażenia w pełni nawiasowanego do postaci ONP kod Java II else if (s.equals("*")) stack.push(s); else if (s.equals("/")) stack.push(s); else if (s.equals(")")) System.out.print(stack.pop() + " "); else if (s.equals("(")) System.out.print(""); else System.out.print(s + " "); System.out.println(); in.close(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 33 / 76
Zamiana postaci infiksowej wyrażenia w pełni nawiasowanego do postaci ONP kod Java III $ java InfixToPostfix Podaj wyrażenie arytmetyczne zakonczone q ( ( x + ( 3 * z ) ) - ( ( 2 * 3 ) / k ) ) q x 3 z * + 2 3 * k / - q $ java InfixToPostfix Podaj wyrażenie arytmetyczne zakonczone q ( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) ) q 2 3 4 + 5 6 * * + q Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 34 / 76
Postać infiks na postać postfix (ONP) I Badane wyrażenie: ((x + (3 z)) ((2 3)/k)) Wynikowe wyrażenie zapisane w ONP: x 3 z * + 2 3 * k / - Krok Wejście Stos Wyjście 1 ( 2 ( 3 x x 4 + + 5 ( 6 3 + 3 7 * +* 8 z +* z 9 ) + * Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 35 / 76
Postać infiks na postać postfix (ONP) II ((x + (3 z)) ((2 3)/k)) 9 ) + 10 - - 11 ( 12 ( 13 2-2 14 * -* 15 3 -* 3 16 ) - * 17 / -/ 18 k -/ k 19 ) - / 20 ) - Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 36 / 76
Przekształcanie wyrażeń arytmetycznych na ONP 1 Analizuj wyrażenie po jednym elemencie (stałej, zmiennej lub ograniczniku). 2 Jeśli element jest stała lub nazwa zmiennej, przekaż go na wyjście. 3 Jeśli element jest operatorem, to: (a) jeśli priorytet badanego operatora jest wyższy od priorytetu operatora zajmujacego szczyt stosu lub jeśli stos jest pusty - dopisz go na stos; (b) jeśli na szczycie stosu znajduje się operator o wyższym lub równym priorytecie - odczytaj ze stosu i prześlij na wyjście wszystkie operatory o priorytecie wyższym badź równym, aż do wystapienia na szczycie stosu operatora o priorytecie niższym od priorytetu operatora nadchodzacego z wejścia; element badany dopisz na stos; 4 Jeśli element jest nawiasem, to: (a) jeśli trafiłeś na nawias otwierajacy, dopisz go na stos; (b) jeśli trafiłeś na nawias zamykajacy: zdejmij wszystkie operatory ze stosu i przekaż je na wyjście, aż do trafienia na nawias otwierajacy; nawiasów nie wypisuj na wyjście. 5 Jeśli badane wyrażenie nie zostało wyczerpane - wróć do punktu pierwszego; 6 Jeśli badane wyrażenie zostało wyczerpane, odczytaj wszystkie operatory ze stosu i przekaż je na wyjście automatu. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 37 / 76
Przekształcanie wyrażeń na ONP Badane wyrażenie: x + 3 z 2 3/k Krok Wejście Stos Wyjście 1 x x 2 + + 3 3 + 3 4 * +* 5 z +* z 6 - - *+ 7 2-2 8 * -* 9 3 -* 3 10 / -/ * 11 k -/ k 12 /- Wyrażenie zapisane w ONP: x3z +23 k/ Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 38 / 76
Przekształcanie wyrażeń na ONP Badane wyrażenie: (15 3)ˆ(3 + 2) 6/3 Krok Wejście Stos Wyjście 1 ( ( 2 15 ( 15 3 - (- 4 3 (- 3 5 ) - 6 ^ ^ 7 ( ^( 8 3 ^( 3 9 + ^(+ 10 2 ^(+ 2 11 ) ^ + 12 * * ^ 13 6 * 6 14 / / * 15 3 / 3/ Wyrażenie zapisane w ONP: 15 3 32 + ˆ6 3/ Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 39 / 76
Algorytm obliczania wartości wyrażenia w ONP 1 Analizuj wyrażenie po jednym elemencie (stałej, zmiennej lub ograniczniku). 2 Jeśli element ten jest: 1 stała lub nazwa zmiennej dopisz go na stos; 2 operatorem zdejmij ze stosu właściwa dla danego operatora ilość argumentów, wykonaj na nich obliczenia, a uzyskany wynik dopisz na stos; 3 Jeśli badane wyrażenie nie zostało wyczerpane - wróć do punktu pierwszego; 4 Jeśli badane wyrażenie zostało wyczerpane - wartość znajdujaca się na stosie to wynik obliczeń. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 40 / 76
Obliczania wartości wyrażenia w ONP kod Java I import java.util.scanner; public class EvaluatePostfix { public static void main(string[] args) { StosD stack = new StosD(); Scanner in = new Scanner(System.in); System.out.println("Podaj wyrazenie arytmetyczne w ONP zakonczone q "); String s = in.next(); Double a, b; while (!s.equals("q")) { if (s.equals("+")) stack.push(stack.pop() + stack.pop()); else if (s.equals("-")) { a = stack.pop() ; b = stack.pop(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 41 / 76
Obliczania wartości wyrażenia w ONP kod Java II stack.push(b - a); else if (s.equals("*")) stack.push(stack.pop() * stack.pop()); else if (s.equals("/")) { a = stack.pop() ; b = stack.pop(); stack.push(b / a); else stack.push(double.parsedouble(s)); s = in.next(); System.out.println(stack.pop()); in.close(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 42 / 76
Obliczania wartości wyrażenia w ONP kod Java III $ java EvaluatePostfix Podaj wyrażenie arytmetyczne w ONP zakończone q 6 3 / 2 5 + * q 14.0 $ java EvaluatePostfix Podaj wyrażenie arytmetyczne w ONP zakończone q 3 4 5 + * q 27 $ java InfixToPostfix Podaj wyrażenie arytmetyczne zakonczone q ( ( 2 * ( 10-2 ) ) + ( 8 / 2 ) ) q 2 10 2 - * 8 2 / + q $ java EvaluatePostfix Podaj wyrażenie arytmetyczne w ONP zakończone q 2 10 2 - * 8 2 / + q 20.0 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 43 / 76
Algorytm obliczania wartości wyrażenia w ONP - przykład Badane wyrażenie: 6 3 / 2 5 + * Krok Wejście Operacja Stos 1 6 6 2 3 63 3 / 6/3 2 4 2 22 5 5 225 6 + 2+5 27 7 * 2*7 14 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 44 / 76
Stos jako typ generyczny I import java.util.nosuchelementexception; import java.util.scanner; public class Stack<Item> { private Node<Item> first; private int n; // prywatna klasa pomocnicza private static class Node<Item> { private Item item; private Node<Item> next; //Inicjalizacja pustego stosu. public Stack() { first = null; n = 0; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 45 / 76
Stos jako typ generyczny II // Zwraca true, gdy stos jest pusty public boolean isempty() { return first == null; //Zwraca liczbe elementow na stosie. public int size() { return n; // Dodaje element do stosu public void push(item item) { Node<Item> oldfirst = first; first = new Node<Item>(); first.item = item; first.next = oldfirst; n++; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 46 / 76
Stos jako typ generyczny III //Usuwa element ze stosu public Item pop() { if (isempty()) throw new NoSuchElementException("Stos pusty"); Item item = first.item; first = first.next; n--; return item; //Zwraca szczyt stosu, ale go nie usuwa public Item peek() { if (isempty()) throw new NoSuchElementException("Stos pusty"); return first.item; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 47 / 76
Stos jako typ generyczny IV public static void main(string[] args) { Scanner in = new Scanner(System.in); Stack<Integer> stacki = new Stack<Integer>(); System.out.println("Podaj liczbe"); Integer n = in.nextint(); Integer m=n; while (n > 0) { stacki.push(n % 2); n = n / 2; System.out.println("Reprezentacja binarna liczby : "+m); while (!stacki.isempty()){ System.out.print(stackI.pop()); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 48 / 76
Stos jako typ generyczny V System.out.println(); in.close(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 49 / 76
Stos - implementacja tablicowa, założenia Wykorzystuje tablicę A złożona z n elementów A[i], gdzie n jest maksymalna liczba spodziewanych elementów. Operacje polegaja na manipulacji indeksami tablicy. top[s] numer ostatniego elementu wstawionego do stosu. Stos składa się z elementów S[1],..., S[top[S]]. S[1] jest elementem na dnie stosu. S[top[S]] jest elementem na szczycie stosu. Jeżeli top[s] = 0, to stos jest pusty. Do sprawdzenia, czy stos jest pusty używana jest operacja Stack Empty. Próba zdjęcia elementu ze stosu sygnalizowana jest błędem niedomiaru. Jeżeli top[s] jest większe niż ustalony z góry rozmiar tablicy, to stos jest przepełniony. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 50 / 76
Stos - implementacja tablicowa Push(S, x) 1: if top[s] = length[s] then 2: error przepełnienie 3: end if 4: top[s] = top[s] + 1 5: S[top[S]] = x 1 5 2 3 Kierunek top wstawiania Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 51 / 76
Stos - implementacja tablicowa Stack-Empty(S) 1: if top[s] = 0 then 2: return true 3: else 4: return false 5: end if Pop(S) 1: if Stack-Empty(S) then 2: error niedomiar 3: end if 4: top[s] = top[s] 1 5: return S[top[S] + 1] 1 5 2 3 Kierunek top wstawiania Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 52 / 76
Stos - implementacja tablicowa I import java.util.nosuchelementexception; import java.util.scanner; import java.util.arrays; public class ArrayStack<Item> { private Item [] a; private int N; //Inicjalizacja pustego stosu. public ArrayStack(int size) { // a = new Item[size]; nie jest dozwolone // potrzebne jest rzutowanie /*generuje ostrzezenie: *Note: ArrayStack.java uses unchecked or unsafe operations. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 53 / 76
Stos - implementacja tablicowa II *Note: Recompile with -Xlint:unchecked for details. *ale mozna je zignorowac*/ a = (Item[]) new Object[size]; // Zwraca true, gdy stos jest pusty public boolean isempty() { return N == 0 ; //Zwraca liczbe elementow na stosie. public int size() { return N; // Dodaje element do stosu public void push(item item) { if (N >= a.length) throw new NoSuchElementException("Stos pelny"); a[n++] = item; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 54 / 76
Stos - implementacja tablicowa III //Usuwa element ze stosu public Item pop() { if (isempty()) throw new NoSuchElementException("Stos pusty"); Item item = a[--n]; // pozwala na zapobieganie wyciekom poamieci a[n] = null; return item; //Zwraca szczyt stosu, ale go nie usuwa public Item peek() { if (isempty()) throw new NoSuchElementException("Stos pusty"); return a[n]; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 55 / 76
Stos - implementacja tablicowa IV public static void main(string[] args) { ArrayStack<Integer> s = new ArrayStack<Integer >(32); int i=0; while (i < 32) { s.push(i); i++; while (!s.isempty()){ System.out.print(s.pop()+" "); System.out.println(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 56 / 76
Kolejka Kolejka FIFO (First In First Out) jest struktura liniowo uporzadkowanych danych, w której dołaczać nowe dane można jedynie na koniec, a usuwać z poczatku. Procedura usunięcia danych z końca kolejki jest taka sama, jak w przypadku stosu, z ta różnica, że usuwamy dane od poczatku a nie od końca. Działanie na kolejce jest intuicyjnie jasne, gdy skojarzymy ja z kolejka ludzi np. w sklepie. Każdy nowy klient staje na jej końcu, obsługa odbywa się jedynie na poczatku. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 57 / 76
Kolejka - operacje Niech K = (d 1, d 2,..., d n ) oznacza kolejkę, wtedy: Wstawianie elementu do kolejki: enqueuq(k, d) = (d 1, d 2,..., d n, d) Pobieranie elementu z kolejki: dequeuq(k ) = (d 2,..., d n ), o ile n > 1 Obsługiwanie pierwszego elementu z kolejki bez jego usuwania : first(k ) = d 1 Sprawdzanie niepustości kolejki: empty(k ) wtw., gdy n = 0 Poczatek kolejki d 1 d 2 d 3 d 4 d 5 Koniec kolejki Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 58 / 76
Kolejka - implementacja tablicowa n 1 elementowa kolejka jest impelementowana za pomoca n-elementowej tablicy Q, tj. Q = Q[0]...Q[n 1]. Atrybut head[q] wskazuje na głowę, czyli poczatek kolejki. Atrybut tail[q] wyznacza następna wolna pozycję, na która można wstawić nowy element. Poczatkowo head[q] = tail[q] = 0. Elementy kolejki znjduja się na pozycjach: head[q], head[q] + 1,..., tail[q] 1. Zakładmy, że tablica jest cykliczna, tzn. że pozycja o numerze 0 jest bezpośrednim następnikiem pozycji n 1. Jeżeli head[q] = tail[q], to kolejka jest pusta. Jeżeli head[q] = (tail[q] + 1) mod length(q), to kolejka jest pełna. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 59 / 76
Kolejka - implementacja tablicowa Enqueue(Q, x) 1: if head[q] = (tail[q] + 1) mod length(q) then 2: error Kolejka pełna 3: end if 4: Q[tail[Q]] = x 5: if tail[q] = length[q] then 6: tail[q] = 1 7: else 8: tail[q] = tail[q] + 1 9: end if 1 5 - - 2 3 0 tail head Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 60 / 76
Kolejka - implementacja tablicowa Dequeue(Q) 1: if head[q] = tail[q] then 2: error Kolejka pusta 3: end if 4: x = Q[head[Q]] 5: if head[q] = length[q] then 6: head[q] = 1 {Założenie o cykliczności 7: else 8: head[q] = head[q] + 1 9: end if 10: return x 1 5 - - 2 3 0 tail head Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 61 / 76
Kolejka - implementacja tablicowa I import java.util.nosuchelementexception; import java.util.scanner; import java.util.arrays; public class ArrayQueue<Item> { private Item [] a; private int N; // liczba elementow w kolejce private int head; // poczatek kolejki private int tail; // koniec kolejki //Inicjalizacja pustej kolejki. public ArrayQueue(int size) { a = (Item[]) new Object[size]; head = tail = 0; N = 0; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 62 / 76
Kolejka - implementacja tablicowa II // Zwraca true, gdy kolejka jest pusta public boolean isempty() { return N==0 ; //Zwraca liczbe elementow w kolejce. public int size() { return N; // Dodaje element do stosu public void enqueue(item item) { if (head == (tail+1)%a.length) throw new NoSuchElementException("Kelejka pelna"); a[tail++] = item; if (tail == a.length) tail=0; N++; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 63 / 76
Kolejka - implementacja tablicowa III //Usuwa element z kolejki public Item dequeue() { if (isempty()) throw new NoSuchElementException("Kolejka pusta"); Item item = a[head]; a[head++]=null; // kontrola wycieku pamieci if(head >= a.length) head=0; N--; return item; //Zwraca poczatek kolejki, ale go nie usuwa public Item peek() { if (isempty()) throw new NoSuchElementException("Kolejka pusta"); return a[head]; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 64 / 76
Kolejka - implementacja tablicowa IV public static void main(string[] args) { ArrayQueue<Integer> s = new ArrayQueue<Integer >(32); int i=0, j = 0; while (i < 31) s.enqueue(i++); System.out.println("Elementy obsluzone: "); while (j < 10){ System.out.print(s.dequeue() + " "); j++; System.out.println(); j = 0; while (j < 8) { s.enqueue(2*j); j++; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 65 / 76
Kolejka - implementacja tablicowa V System.out.println("Elementow w kolejce: " + s.size()); System.out.println("Elementy obsluzone: "); while (!s.isempty()){ System.out.print(s.dequeue() + " "); System.out.println(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 66 / 76
Kolejka - implementacja tablicowa VI $ java ArrayQueue Elementy obsluzone: 0 1 2 3 4 5 6 7 8 9 Elementow w kolejce: 29 Elementy obsluzone: 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 0 2 4 6 8 10 12 14 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 67 / 76
Problem Józefa Flawiusza Nazwa nawiazuje do postaci Józefa Flawiusza, rzymsko-żydowskiego historyka żyjacego w I wieku n.e. Miał on zostać wraz z grupa powstańców otoczony w jaskini w trakcie oblężenia Jotopaty. Żołnierze woleli samobójstwo od pojmania, a że żydowskie prawo religijne zabrania odbierania sobie życia, zdecydowali się losować, kto zabije poprzednio wylosowanego, tak długo, dopóki nie pozostanie jeden, który będzie musiał się zabić sam. Gdy, zrzadzeniem losu, przy życiu pozostali Flawiusz wraz z jednym z towarzyszy, zdecydowali się oni poddać Rzymianom. Sformułowanie: https://pl.wikipedia.org/wiki/ Problem_Józefa_Flawiusza W ogólnej wersji problem brzmi następujaco: w okręgu ustawiamy n obiektów, następnie eliminujemy co k-ty obiekt, tak długo, aż zostanie tylko jeden. Należy wskazać obiekt, który pozostanie. Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 68 / 76
Rozwiazanie problemu Józefa Flawiusza I public class Josephus { public static void main(string[] args) { int n = Integer.parseInt(args[0]); int k = Integer.parseInt(args[1]); ArrayQueue<Integer> queue = new ArrayQueue< Integer>(n+1); for (int i = 0; i < n; i++) queue.enqueue(i); while (!queue.isempty()) { for (int i = 0; i < k-1; i++) queue.enqueue(queue.dequeue()); System.out.print(queue.dequeue() + " "); System.out.println(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 69 / 76
Rozwiazanie problemu Józefa Flawiusza II $ java Josephus 7 2 1 3 5 0 4 2 6 Pierwszym, który przekształcił tę historię w problem matematyczny, miał być szesnastowieczny francuski matematyk Claude Gaspard Bachet de Méziriac. Według niego, ustawieni w okrag żołnierze mieli eliminować co trzeciego spośród siebie i że było ich 41. $ java Josephus2 41 3 2 5 8 11 14 17 20 23 26 29 32 35 38 0 4 9 13 18 22 27 31 36 40 6 12 19 25 33 39 7 16 28 37 10 24 1 21 3 34 15 30 Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 70 / 76
Kolejka dynamiczna implementacja generyczna I import java.util.nosuchelementexception; import java.util.scanner; public class Queue<Item> { private Node<Item> first; // glowa kolejki private Node<Item> last; // ogon kolejki private int n; // liczba elementow w kolejce // helper linked list class private static class Node<Item> { private Item item; private Node<Item> next; //Inicjalizacja pustej kolejki. public Queue() { first = null; last = null; n = 0; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 71 / 76
Kolejka dynamiczna implementacja generyczna II // Zwraca true, gdy kolejka jest pusta public boolean isempty() { return first == null; //Zwraca liczbe elementow w kolejce. public int size() { return n; //Zwraca poczatek kolejki, ale go nie usuwa public Item peek() { if (isempty()) throw new NoSuchElementException("Kolejka pusta"); return first.item; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 72 / 76
Kolejka dynamiczna implementacja generyczna III // Dodaje element do kolejki public void enqueue(item item) { Node<Item> oldlast = last; last = new Node<Item>(); last.item = item; last.next = null; if (isempty()) first = last; else oldlast.next = last; n++; //Usuwa element z kolejki public Item dequeue() { if (isempty()) throw new NoSuchElementException("Kolejka pusta"); Item item = first.item; first = first.next; Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 73 / 76
Kolejka dynamiczna implementacja generyczna IV n--; if (isempty()) last = null; return item; public static void main(string[] args) { Queue<String> queue = new Queue<String>(); System.out.println("Podaj ciag znakow zakonczony q"); Scanner in = new Scanner(System.in); String item = in.next(); while (!item.equals("q")) { if (!item.equals("-")) queue.enqueue( item); else if (!queue.isempty()) System.out.print(queue.dequeue() + " "); item = in.next(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 74 / 76
Kolejka dynamiczna implementacja generyczna V System.out.println("(" + queue.size() + " sa w kolejce)"); in.close(); $ java Queue Podaj ciąg znaków zakończony q ala ma kota - psa q ala (3 sa w kolejce) Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 75 / 76
Rozwiazanie problemu Józefa Flawiusza public class Josephus { public static void main(string[] args) { int n = Integer.parseInt(args[0]); int k = Integer.parseInt(args[1]); Queue<Integer> queue = new Queue<Integer>(); for (int i = 0; i < n; i++) queue.enqueue(i); while (!queue.isempty()) { for (int i = 0; i < k-1; i++) queue.enqueue(queue.dequeue()); System.out.print(queue.dequeue() + " "); System.out.println(); Bożena Woźna-Szcześniak (AJD) Algorytmy i Struktury Danych. Wykład 6 76 / 76