Binární halda (= binary heap)

Podobné dokumenty
Prioritní fronta, halda

Dynamické datové struktury III.

Amortizovaná složitost. Prioritní fronty, haldy (binární, d- regulární, binomiální, Fibonacciho), operace nad nimi a jejich složitost

Dynamické datové struktury IV.

Základní datové struktury III: Stromy, haldy

Stromy, haldy, prioritní fronty

Stromy. Jan Hnilica Počítačové modelování 14

5 Rekurze a zásobník. Rekurzivní volání metody

DobSort. Úvod do programování. DobSort Implementace 1/3. DobSort Implementace 2/3. DobSort - Příklad. DobSort Implementace 3/3

Prioritní fronta, halda (heap), řazení

TGH07 - Chytré stromové datové struktury

TGH07 - Chytré stromové datové struktury

2 Datové struktury. Pole Seznam Zásobník Fronty FIFO Haldy a prioritní fronty Stromy Hash tabulky Slovníky

Datové struktury. alg12 1

1. Téma 12 - Textové soubory a výjimky

A4B33ALG 2010/05 ALG 07. Selection sort (Select sort) Insertion sort (Insert sort) Bubble sort deprecated. Quicksort.

součet cvičení celkem. známka. Úloha č.: max. bodů: skut. bodů:

Bubble sort. příklad. Shaker sort

Pokročilé haldy. prof. Ing. Pavel Tvrdík CSc. Fakulta informačních technologií České vysoké učení technické v Praze c Pavel Tvrdík, 2010

Zásobník (Stack), Fronta (Queue), Kruhový buffer, Spojový seznam, Množina

Intervalové stromy. Představme si, že máme posloupnost celých čísel p 0, p 1,... p N 1, se kterou budeme. 1. Změna jednoho čísla v posloupnosti.

Dynamické datové struktury I.

bfs, dfs, fronta, zásobník, prioritní fronta, halda

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Kolekce, cyklus foreach

přirozený algoritmus seřadí prvky 1,3,2,8,9,7 a prvky 4,5,6 nechává Metody řazení se dělí:

Náplň. v Jednoduché příklady na práci s poli v C - Vlastnosti třídění - Způsoby (algoritmy) třídění

Vyvažování a rotace v BVS, všude se předpokládá AVL strom

Datové struktury Úvod

bfs, dfs, fronta, zásobník, prioritní fronta, halda

Šablony, kontejnery a iterátory

NPRG030 Programování I, 2018/19 1 / :03:07

V případě jazyka Java bychom abstraktní datový typ Time reprezentující čas mohli definovat pomocí třídy takto:

Algoritmy a datové struktury

Datový typ prioritní fronta Semestrální práce z předmětu 36PT

Abstraktní datové typy: zásobník

Stromy. Strom: souvislý graf bez kružnic využití: počítačová grafika seznam objektů efektivní vyhledávání výpočetní stromy rozhodovací stromy

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Řazení. Uspořádat množinu prvků obsahujících klíč podle definovaného kriteria.

Rekurze a zásobník. Jak se vypočítá rekurzivní program? volání metody. vyšší adresy. main(){... fa(); //push ret1... } ret1

Binární Vyhledávací Stromy, u kterých je. složitost operací v nejhorším. rovná O(log n)

Konstruktory a destruktory

AVL stromy. pro každý uzel u stromu platí, že rozdíl mezi výškou jeho levého a pravého podstromu je nejvýše 1 stromy jsou samovyvažující

TGH05 - Problém za milion dolarů.

Red Black strom (Red Black Tree) Úvod do programování. Rotace. Red Black strom. Rotace. Rotace

bin arn ı vyhled av an ı a bst Karel Hor ak, Petr Ryˇsav y 23. bˇrezna 2016 Katedra poˇ c ıtaˇ c u, FEL, ˇ CVUT

Základní pojmy. Úvod do programování. Základní pojmy. Zápis algoritmu. Výraz. Základní pojmy

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Šablony, kontejnery a iterátory

IAJCE Přednáška č. 9. int[] pole = new int[pocet] int max = pole[0]; int id; for(int i =1; i< pole.length; i++) { // nikoli 0 if (Pole[i] > max) {

Principy objektově orientovaného programování

DSA, První krok: máme dokázat, že pro left = right vrátí volání f(array, elem, left, right)

a) b) c) Radek Mařík

Binární vyhledávací strom pomocí směrníků Miroslav Hostaša L06620

Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem

Základy řazení. Karel Richta a kol.

Sada 1 - Základy programování

R zné algoritmy mají r znou složitost

Rozklad problému na podproblémy

Pokročilá algoritmizace amortizovaná složitost, Fibonacciho halda, počítačová aritmetika

Zadání k 2. programovacímu testu

Dynamické programování. Optimální binární vyhledávací strom

Fronta (Queue) Úvod do programování. Fronta implementace. Fronta implementace pomocí pole 1/4. Fronta implementace pomocí pole 3/4

ABSTRAKTNÍ DATOVÉ TYPY (ADT)

Programování v C++ 1, 17. cvičení

Složitosti základních operací B + stromu

Adresní vyhledávání (přímý přístup, zřetězené a otevřené rozptylování, rozptylovací funkce)

ADT prioritní fronta. Haldy. Další operace nad haldou. Binární halda. Binomické stromy. Časová složitost jednotlivých operací.

Úvod do programovacích jazyků (Java)

Algoritmizace prostorových úloh

Třídící algoritmy. Insert Sort. Bubble Sort. Select Sort. Shell Sort. Quick Sort. Merge Sort. Heap Sort.

Časová složitost algoritmů

Datové struktury. Obsah přednášky: Definice pojmů. Abstraktní datové typy a jejich implementace. Algoritmizace (Y36ALG), Šumperk - 12.

Generické programování

Abstraktní datové typy

Maturitní téma: Programovací jazyk JAVA

Spojové struktury. Spojová struktura (linked structure):

Programování v C++ 2, 4. cvičení

Programování 3. hodina. RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015

Stromy. Příklady. Rekurzivní datové struktury. Základní pojmy

Předmět: Algoritmizace praktické aplikace

KTE / ZPE Informační technologie

3 Algoritmy řazení. prvku a 1 je rovněž seřazená.

ˇ razen ı rychlejˇ s ı neˇ z kvadratick e Karel Hor ak, Petr Ryˇsav y 20. dubna 2016 Katedra poˇ c ıtaˇ c u, FEL, ˇ CVUT

ALG 09. Radix sort (přihrádkové řazení) Counting sort. Přehled asymptotických rychlostí jednotlivých řazení. Ilustrační experiment řazení

Základy algoritmizace c2005, 2007 Michal Krátký, Jiří Dvorský1/39

Volné stromy. Úvod do programování. Kořenové stromy a seřazené stromy. Volné stromy

autoři: Rudolf Bayer, Ed McCreight všechny vnější uzly (listy) mají stejnou hloubku ADS (abstraktní datové struktury)

Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz

IRAE 07/08 Přednáška č. 7. Začátek (head)

Algoritmizace řazení Bubble Sort

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Algoritmy I, složitost

Programování v C++ 1, 16. cvičení

Algoritmizace prostorových úloh

IRAE 07/08 Přednáška č. 2. atr1 atr2. atr1 atr2 -33

Algoritmizace prostorových úloh

Select sort: krok 1: krok 2: krok 3: atd. celkem porovnání. výběr nejmenšího klíče z n prvků vyžaduje 1 porovnání

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Transkript:

Binární halda (= binary heap) je binární strom, kde platí, že každý potomek vrcholku má nižší (vyšší) nebo stejnou hodnotu nežli vrcholek sám vlastnost tvar = má tvar stromu, který je buď úplně vyváženým binárním stromem nebo, pokud je poslední úroveň stromu nekompletní, uzly se plní zleva do prava vlastnost h = "býti haldou" = každý uzel je menší/větší nebo roven svým potomkům jde o nejjednodušší typ haldy, tzn. MIN nebo MAX je na vrcholu v případě, že není poslední hladina haldy zaplněna, jsou uzly ukládány do haldy zleva je in place složitost nejhorší = O(n logn) nejmenší strom = pouze kořen pokud indexujeme (od 0) prvky haldy od shora dolů, zleva doprava a rodič je na indexu i, pak potomci jsou na indexech levý syn = L(i) = 2i + 1 pravý syn = R(i) = 2i + 2 rodič = P(i) = (i-1)/2 = dolní celá část např. 9/2=4 tato vlastnost je zajištěna tím, že v haldě nevynecháváme mezery. Graficky si tedy haldu můžeme představit jako pyramidu s useknutou základnou. vlastnost býti haldou je rekurzivní - všechny podstromy haldy jsou také haldy. Díky této vlastnosti máme zajištěno, že se halda chová jako prioritní fronta - na vrcholek haldy vždy musí vystoupit prvek s MIN/MAX prioritou (čehož se využívá u heapsortu = řazení haldou). pokud považujeme za vyšší prioritu nižší hodnotu klíče, hovoříme o min-heap, při opačném uspořádání o max-heap Funkce hepify - volá se na jeden prvek, který umístí na správné místo a přitom dodrží h vlastnost - umístí zadaný prvek na správné místo v haldě (resp. ještě ve stromu, protože v danou chvíli ještě strom nemusí být haldou) tzv. zajišťuje vlastnost býti haldou - rekurzivní funkce, která opravuje vnitřní strukturu haldy - algoritmus začíná od shora - vždy porovná otce s oběma potomky, a pokud má otec nižší prioritu než některý ze synů (případně než oba synové), tak jej prohodí s vyšším z nich - dál postupuje větví, kde se prohazovalo a pokud dojde k přenesení nerovnováhy o úroveň níže, tak algoritmus musí opravit i tuto podhaldu. Celá procedura terminuje v okamžiku, kdy buď příslušný otec již nemá žádné potomky, nebo je vlastnost býti haldou zaručena (tzn. otec má vyšší prioritu než oba synové). - složitost O(log n) Funkce build heap - procedura, která zkonstruuje v zadaném poli haldu tím, že od zdola zavolá na všechny vnitřní uzly funkci heapify - rekurzivní fce - pro vytvoření haldy se volá na každý uzel - první krok haldového řazení spočívá v postupném prodlužování haldy z rozsahu (n/2 n) na (1 n). Halda je vytvořena po provedení n/2 kroků. - začíná se vždy od spodu zprava, aby se nahoru dostal max/min prvek - nejhorší složitost = O(n) Tato metoda je volána na začátku při vytvoření původní struktury halda. To se děje rychle, protože struktura halda je poněkud vágní. Jedinou podmínkou je, že každý kořenový uzel musí být větší než podřízené uzly. Funkce heapsort = řazení haldou - jeden z nejlepších obecných algoritmů řazení založený na porovnání prvků - je nestabilní - nahoře je max, dole min = znám první a poslední prvek - je in place - nejhorší složitost = O(n log n) - složitost je zaručena, proto je lepší než rychlejší quicksort s O(n 2 ) Princip Základem heapsortu je binární halda, jejíž základní vlastností je, že se chová jako prioritní fronta. Pokud z prioritní fronty postupně odebíráme prvky, tak je zřejmé, že tím dochází k jejich řazení. Celý postup se skládá z následujících kroků: 1. Postavme haldu nad zadaným polem.

2. Utrhněme vrchol haldy (prvek s nejvyšší prioritou - nejvyšší nebo nejnižší prvek dle způsobu řazení). 3. Prohoďme utržený prvek s posledním prvkem haldy. 4. Zmenšeme haldu o 1 (prvky řazené dle priority na konci pole jsou již seřazené). 5. Opravme haldu tak, aby splňovala požadované vlastnosti (přestaly platit v momentě prohození prvků). 6. Dokud má halda prvky GOTO: 2. 7. Pole je seřazené v opačném pořadí, než je priorita prvků. Funkce delete - mazání prvku - složitost O (log n) - z vrcholu (= z kořene) - vezmu předposlední prvek a vyměním s kořenem - provedu heapify, aby zase byla halda - odjinud (= z vnitřního uzlu) - uzel zvětšíme na hodnotu vyšší než je kořen (tzn. prohodíme kořen a uzel) - dál viz delete z kořene Vložení Operace vkládání (insert) funguje přesně naopak než operace repairtop. Nový prvek je přidán na konec haldy a probublává vzhůru tak dlouho, dokud má vyšší prioritu než jeho otec. Asymptotická složitost vkládání je O(log n). Top Operace top vrátí hodnotu prvku s MIN/MAX prioritou tj. vrcholu. Jelikož se jedná o návrat prvního prvku pole, tak má operace top konstantní asymptotickou složitost O (1). Merge Operace merge sloučí dvě haldy do jedné vytvoří nové pole, do nějž nakopíruje obsah obou hald a na toto nové pole zavolá operaci heapify. Asymptotická složitost tohoto postupu je O(m + n), kde m je velikost první haldy a n je velikost druhé haldy. /* PrioritniFrontaImplementovanaHeapem public class PrioritniFrontaImplementovanaHeapemOdNuly { /* Binarni halda (min-heap) // pole prvku fronty-haldy, private double[] array; // // index posledniho prvku v poli private int lastelemindex = -1; // Verejne metody, ktere vidi uzivatel prioritni fronty /* Konstruktor vytvori prazdnou frontu-haldu pripravenou pojmout az maxsize prvku public PrioritniFrontaImplementovanaHeapemOdNuly(int maxsize) { this.array = new double[maxsize]; public boolean isempty() { return size() == 0; public boolean isfull() { return size() == array.length; public final void clear() { lastelemindex = -1; public int size() { return lastelemindex + 1;

/* Vlozi prvek do fronty-haldy public void insert(double element) { if (isfull()) { throw new IllegalStateException("fronta-halda je plna"); int slotindex = ++lastelemindex; // index volneho mista int parentslotindex = parentindex(slotindex); // index rodice volneho mista while (parentslotindex < slotindex && // dokud nejsem na vrcholu element < array[parentslotindex]) { //dokud je vkladany prvek mensi nez otec slotu array[slotindex] = array[parentslotindex]; //presun rodice o uroven niz slotindex = parentslotindex; // tim se slot posune vis parentslotindex = parentindex(slotindex); array[slotindex] = element; /* vrati, ale nevyjme, prvni (nejmensi) prvek public double first() { // if (isempty()) { throw new IllegalStateException("fronta-halda je prazdna"); return array[0]; /*vyjme a vrati prvni (nejmensi) prvek public double removefirst() { if (isempty()) { throw new IllegalStateException("fronta-halda je prazdna"); double min = array[0]; array[0] = array[lastelemindex]; // posledni prvek na vrchol lastelemindex--; repairtop(0, array, lastelemindex); // opravi haldu return min; /*Slouceni tuto frontu-haldu s jinou public void merge(prioritnifrontaimplementovanaheapemodnuly heap) { double[] newarray = new double[size() + heap.size()]; System.arraycopy(array, 0, newarray, 0, size()); System.arraycopy(heap.array, 0, newarray, size(), heap.size()); array = newarray; lastelemindex = newarray.length - 1; buildheap(array); @Override public String tostring() { StringBuilder builder = new StringBuilder(); for (int i = 0; i <= lastelemindex; i++) { builder.append(array[i]).append(" "); return builder.tostring(); // Pomocne metody private static void swap(double[] array, int i, int j) { double tmp = array[i]; array[i] = array[j]; array[j] = tmp;

private static int parentindex(int childindex) { return (childindex - 1) / 2; private static int leftchildindex(int parentindex) { return (parentindex + 1) * 2-1; /* Prohazi prvky pole array aby melo h-vlastnost. Metoda je staticka, aby mohla byt volana ve staticke metode heapsort private static void buildheap(double[] array) { for (int parentindex = parentindex(array.length - 1); parentindex >= 0; parentindex--) { repairtop(parentindex, array, array.length - 1); // resp. repairtopiterativne(parentindex, array, lastelementindex); /* Opravi haldu, jejiz koren neni na spravnem miste. Metoda je staticka, aby mohla byt volana ve staticke metode buildheap private static void repairtop(int parentindex, double[] array, int lastelementindex) { int minchildindex = leftchildindex(parentindex); // index mensiho potomka if (minchildindex > lastelementindex) { return; // nema potomky int rightchildindex = minchildindex + 1; // index praveho potomka if (rightchildindex <= lastelementindex && // ma druheho potomka array[rightchildindex] < array[minchildindex]) { minchildindex = rightchildindex; // pravy potomek je mensi if (array[parentindex] > array[minchildindex]) { // rodic je vetsi nez mensi potomek swap(array, parentindex, minchildindex); repairtop(minchildindex, array, lastelementindex); // oprava podstromu mensiho potomka private static void repairtopiterativne(int parentindex, double[] array, int lastelementindex) { double tmp = array[parentindex]; int minchildindex = leftchildindex(parentindex); if (minchildindex > lastelementindex) { return; // nema potomky if (minchildindex < lastelementindex && array[minchildindex] > array[minchildindex + 1]) { minchildindex++; while (minchildindex <= lastelementindex && tmp > array[minchildindex]) { array[parentindex] = array[minchildindex]; parentindex = minchildindex; minchildindex = leftchildindex(minchildindex); if (minchildindex < lastelementindex && array[minchildindex] > array[minchildindex + 1]) { minchildindex++; array[parentindex] = tmp;

// HeapSort public static void heapsort(double[] array) { buildheap(array); for (int i = array.length - 1; i >= 0; i--) { swap(array, 0, i); repairtop(0, array, i - 1); // Testovani public static void main(string[] args) { PrioritniFrontaImplementovanaHeapemOdNuly pf1 = new PrioritniFrontaImplementovanaHeapemOdNuly(1000); pf1.insert(1); pf1.insert(13); pf1.insert(10); PrioritniFrontaImplementovanaHeapemOdNuly pf2 = new PrioritniFrontaImplementovanaHeapemOdNuly(1000); pf2.insert(6); pf2.insert(8); pf2.insert(2); pf1.merge(pf2); System.out.println(pf1); while (!pf1.isempty()) { System.out.println(pf1.removeFirst()); // vypise: 1.0 6.0 8.0 13.0 double[] x = {10, 5, 2, 8, -3, 1000, 1, 3, 5, 9; heapsort(x); System.out.println(Arrays.toString(x)); // vypise: [1000.0, 10.0, 9.0, 8.0, 5.0, 5.0, 3.0, 2.0, 1.0, -3.0] Implementace binarni haldy (min-heap) public class BinaryHeap { private int[] array; private int size; //velikost haldy...je treba mit na pameti, ze indexujeme od 1 * Konstruktor * @param arraysize velikost haldy public BinaryHeap(int arraysize) { this.array = new int[arraysize + 1]; this.size = 0; //na prvnim miste nebude nic * Konstruktor * @param arraysize velikost haldy public BinaryHeap(int[] source) { this.array = new int[source.length + 1]; //na prvnim miste nebude nic System.arraycopy(source, 0, array, 1, source.length); this.size = 0; * Provede operaci slouceni hald * @param heap halda, ktera bude sloucena s touto haldou

public void merge(binaryheap heap) { int[] newarray = new int[this.size + heap.size + 1]; System.arraycopy(array, 1, newarray, 1, this.size); System.arraycopy(heap.array, 1, newarray, this.size + 1, heap.size); size = this.size + heap.size; array = newarray; heapify(newarray); * Vrati pole vsech prvku v halde * @return pole vsech prvku v halde public int[] getall() { return Arrays.copyOfRange(array, 1, this.size + 1); * Vlozi prvek do haldy * @param i prvek k vlozeni public void insert(int i) { size++; int index = this.size; while (i < array[index / 2] && index!= 0) { //dokud je nas prvek mensi nez jeho otec array[index] = array[index / 2]; //pak otce posuneme o uroven niz (cimz se nam mezera na vlozeni posune o patro) index /= 2; //a opakujeme o uroven vys array[index] = i; //o patro vys je jiz prvek nizsi, proto vlozime prvek prave sem, vlastnost haldy byla obnovena public int top() { if (getsize() == 0) { throw new IllegalStateException("halda je prazdna"); return array[1]; * Odstrani vrchol a vrati ho * @return vraceny vrchol public int returntop() { if (getsize() == 0) { throw new IllegalStateException("halda je prazdna"); int tmp = array[1]; array[1] = array[this.size]; size--; repairtop(this.size, 1); return tmp; * @return the size public int getsize() { return size;

* Vytvor haldu ze zdrojoveho pole * @param array pole private void heapify(int[] array) { for (int i = array.length / 2; i > 0; i--) { repairtop(this.size, i); * Umisti vrchol haldy na korektni misto v halde (opravi haldu) * @param bottom posledni index pole, na ktery se jeste smi sahnout * @param topindex index vrsku haldy private void repairtop(int bottom, int topindex) { int tmp = array[topindex]; int succ = topindex * 2; if (succ < bottom && array[succ] > array[succ + 1]) { succ++; while (succ <= bottom && tmp > array[succ]) { array[topindex] = array[succ]; topindex = succ; succ = succ * 2; if (succ < bottom && array[succ] > array[succ + 1]) { succ++; array[topindex] = tmp;