Träd, speciellt binära sökträd. Träd allmänt

Relevanta dokument
Träd - C&P kap. 10 speciellt binära sökträd sid. 452

Föreläsning 7. Träd och binära sökträd

Föreläsning 9 Innehåll

Datastrukturer i kursen. Föreläsning 8 Innehåll. Träd rekursiv definition. Träd

Föreläsning 9 Innehåll

Föreläsning 7. Träd och binära sökträd

Föreläsning 9 Datastrukturer (DAT037)

Inlämningsuppgiften. Föreläsning 9 Innehåll. Träd. Datastrukturer i kursen

Föreläsning Datastrukturer (DAT036)

Föreläsning 10 Innehåll. Diskutera. Inordertraversering av binära sökträd. Binära sökträd Definition

Binära sökträd. Seminarium 9 Binära sökträd Innehåll. Traversering av binära sökträd. Binära sökträd Definition. Exempel på vad du ska kunna

Föreläsning 10 Innehåll

Föreläsning 11 Innehåll. Diskutera. Binära sökträd Definition. Inordertraversering av binära sökträd

Linjärt minne. Sammanhängande minne är ej flexibelt. Effektivt

Föreläsning 10 Datastrukturer (DAT037)

Trädstrukturer och grafer

Föreläsning 5. Träd Binära träd Binärt sökträd som ADT Implementering av binärt sökträd Travestera binärt sökträd Sökning Insättning/borttagning

Träd, binära träd och sökträd. Koffman & Wolfgang kapitel 6, avsnitt 1 4

Föreläsning 13. Träd

Ett generellt träd är. Antingen det tomma trädet, eller en rekursiv struktur: rot /. \ /... \ t1... tn

Datastrukturer, algoritmer och programkonstruktion (DVA104, HT 2014) Föreläsning 5

Föreläsning 4 Datastrukturer (DAT037)

Träd Hierarkiska strukturer

Algoritmer och datastrukturer 2012, föreläsning 6

Datastrukturer som passar för sökning. Föreläsning 10 Innehåll. Inordertraversering av binära sökträd. Binära sökträd Definition

Abstrakta datatyper. Primitiva vektorer. Deklarera en vektor

BST implementering, huvudstruktur

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 9 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Självbalanserande AVL-träd Weiss, avsnitt 4.4

Datastrukturer som passar för sökning. Föreläsning 11 Innehåll. Binära sökträd Definition. Inordertraversering av binära sökträd

Träd. Ett träd kan se ut på detta sätt:

Tentamen, Algoritmer och datastrukturer

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 8 Erik Nilsson, Institutionen för Datavetenskap, LiU

Självbalanserande träd AVL-träd. Koffman & Wolfgang kapitel 9, avsnitt 1 2

TENTAMEN: Algoritmer och datastrukturer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

13 Prioritetsköer, heapar

Föreläsning 3 Datastrukturer (DAT037)

Inom datalogin brukar man använda träd för att beskriva vissa typer av problem. Om man begränsar sig till träd där varje nod förgrenar sig högst två

Föreläsning 2. Länkad lista och iterator

Tentamen Programmeringsteknik II Inledning. Anmälningskod:

Föreläsning 14. Träd och filhantering

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren att du har förstått dessa även om detaljer kan vara felaktiga.

Tentamen TEN1 HI

Föreläsning 4 Datastrukturer (DAT037)

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren om att du har förstått dessa även om detaljer kan vara felaktiga.

Lösningsförslag till tentamen Datastrukturer, DAT037,

BINÄRA TRÄD. (X = pekarvärdet NULL): struct int_bt_node *pivot, *ny; X X X 12 X X 12 X X -3 X X

F5: Debriefing OU2, repetition av listor, träd och hashtabeller. Carl Nettelblad

Lösningar Datastrukturer TDA

Lösningsförslag till exempeltenta 1

Tentamen i Algoritmer & Datastrukturer i Java

Lösningsförslag till tentamen i EDA690 Algoritmer och Datastrukturer, Helsingborg

Föreläsning Datastrukturer (DAT036)

Programmering i C++ EDAF30 Dynamiska datastrukturer. EDAF30 (Föreläsning 11) HT / 34

Föreläsning 3 Datastrukturer (DAT037)

Algoritmer och datastrukturer

Föreläsning 10 Innehåll. Prioritetsköer och heapar. ADT Prioritetskö. Interface för Prioritetskö. Exempel på vad du ska kunna

Föreläsning 4 Innehåll. Abstrakta datatypen lista. Implementering av listor. Abstrakt datatypen lista. Abstrakt datatyp

Föreläsning 2. Länkad lista och iterator

Föreläsning Datastrukturer (DAT036)

Programmering i C++ EDA623 Dynamiska datastrukturer. EDA623 (Föreläsning 11) HT / 31

Tentamen Datastrukturer (DAT036/DAT037/DIT960)

ADT Prioritetskö. Föreläsning 13 Innehåll. Prioritetskö vs FIFO-kö. Prioritetskö Exempel på användning. Prioritetsköer och heapar

Interface. Interface. Tobias Wrigstad (baserat på bilder från Tom Smedsaas) 3 december 2010

Länkade strukturer, parametriserade typer och undantag

Tentamen i Algoritmer & Datastrukturer i Java

Tentamen Programmeringsteknik II Skrivtid: Hjälpmedel: Java-bok (vilken som helst) Skriv läsligt! Använd inte rödpenna!

Klassen BST som definierar binära sökträd med tal som nycklar och enda data. Varje nyckel är unik dvs förekommer endast en

Tentamen Programmeringsteknik II Skrivtid: Hjälpmedel: Java-bok (vilken som helst) Skriv läsligt! Använd inte rödpenna!

Träd. Rot. Förgrening. Löv

Datastrukturer. föreläsning 10. Maps 1

Seminarium 13 Innehåll

Lösningsförslag till tentamen i EDAA01 programmeringsteknik fördjupningkurs

ADT Prioritetskö. Föreläsning 12 Innehåll. Prioritetskö. Interface för Prioritetskö. Prioritetsköer och heapar

DAI2 (TIDAL) + I2 (TKIEK)

Upplägg. Binära träd. Träd. Binära träd. Binära träd. Antal löv på ett träd. Binära träd (9) Binära sökträd (10.1)

Föreläsning 4 Innehåll

Lösningsförslag till tentamen Datastrukturer, DAT037,

Lösningsförslag till tentamen Datastrukturer, DAT037 (DAT036), Tiden det tar att utföra en iteration av loopen är oberoende av värdet på

Föreläsning 3: Abstrakta datastrukturer, kö, stack, lista

Programmering för Språkteknologer II. Innehåll. Associativa datastrukturer. Associativa datastrukturer. Binär sökning.

Tentamen Programmeringsteknik II

Programkonstruktion och. Datastrukturer

Tentamen Datastrukturer (DAT036)

TDIU01 Programmering i C++

Tentamen Datastrukturer, DAT037 (DAT036)

Innehåll. Föreläsning 12. Binärt sökträd. Binära sökträd. Flervägs sökträd. Balanserade binära sökträd. Sökträd Sökning. Sökning och Sökträd

Datastrukturer. Föreläsning 5. Maps 1

Algoritmer och datastrukturer 2012, fo rela sning 8

Tentamen i Algoritmer & Datastrukturer i Java

Föreläsning 5 TDDC91,TDDE22,725G97: DALG. Föreläsning i Datastrukturer och algoritmer 18 september 2018

Föreläsning 6: Introduktion av listor

Symboliska konstanter const

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

Grundläggande programmering, STS 1, VT Sven Sandberg. Föreläsning 14

Tentamen Datastrukturer, DAT037 (DAT036)

Tommy Färnqvist, IDA, Linköpings universitet

Tentamen Programmeringsteknik 2 och MN Skrivtid: Inga hjälpmedel.

Tentamen, EDA690 Algoritmer och Datastrukturer, Helsingborg

Hitta k största bland n element. Föreläsning 13 Innehåll. Histogramproblemet

Transkript:

Datalogi gk 2I1027 - Föreläsning 10 Träd, speciellt binära sökträd presenteras av Jozef Swiatycki, DSV Litteratur: Main, kap. 9 Jozef Swiatycki DSV Bild 1 Träd allmänt Länkad, hierarkisk (icke-linjär) struktur. Består av noder förbundna med kanter. Varje nod har exakt en förälder (utom roten som har ingen). Noder utan barn kallas löv. rot ancestor förälder varelser (förfader) subträd barn syskon fiskar fåglar fyrfota djur kräldjur människor förälder löv löv barn syskon descendent tamdjur syskon vilda djur lärare studenter (ättling) löv löv en nods nivå = antalet steg till roten trädets höjd = maximala nodnivån rotens nivå = 0 tomt träds höjd = -1 (!) Jozef Swiatycki DSV Bild 2 1

Generella träd - en möjlig implementering Varje nod har en array med referenser till sina barn (alternativt kan varje nod ha en länkad lista med referenser till barnen) rot varelse fisk fågel fyrfota djur kräldjur människa tamdjur vilddjur lärare student Jozef Swiatycki DSV Bild 3 Binära träd Maximal utgreningsgrad = 2, dvs varje nod har högst 2 barn Brukar kallas vänster- resp. högerbarn (-subträd). 21 14 21 19 11 15 19 23 31 31 70 70 10 10 22 Jozef Swiatycki DSV Bild 4 2

Binära träd Fullständigt binärt träd: alla påbörjade nivåer är helt fyllda, dvs varje löv har samma nivå och varje icke-löv har två barn 14 21 11 15 19 23 Komplett binärt träd: alla nivåer utom det nedersta är helt fyllda, på den nedersta nivån ligger noderna till vänster 14 21 11 15 19 23 45 13 77 Jozef Swiatycki DSV Bild 5 Binära träd - användningsexempel Beslutsträd Är du hungrig? Ja Nej Gillar du pasta? Ja Nej Vill du gå på bio? Ja Nej Binära sökträd noder i vänstra subträdet har värden som < är mindre än eller lika med förälderns, 14 21 noder i högra subträdet har större < < värden än föräldern 11 15 23 Heap barnens noder har värden som är lägre än eller lika med förälderns, måste vara komplett 47 15 23 15 11 21 Jozef Swiatycki DSV Bild 6 3

Arrayimplementering av kompletta binära träd 47 0 1 2 15 23 3 4 5 15 11 21 data antal 47 15 23 15 11 21 0 1 2 3 4 5 6 7 6 roten finns i data[0] i-te nodens vänstra barn finns i data[2*i+1] (om 2*i+1 < antal) i-te nodens högra barn finns i data[2*i+2] (om 2*i+2 < antal) i-te nodens förälder finns i data[(i-1)/2] (om i > 0) (med i-te nod menar jag noden i data[i]) Jozef Swiatycki DSV Bild 7 Länkad implementering av binära träd Exempel: binärt sökträd find insert BinarySearchTree root 29 Beatrice 47 Stefan 73 Jozef print delete Anna 61 Harald 97 Eskel 8 Urban 52 Mats 67 Tobbe 85 Alex 103 Peter 80 Doris 83 Mia Jozef Swiatycki DSV Bild 8 4

Rekursiv definition av binära träd Ett binärt träd är tomt eller består av en nod och dess vänstersubträd och dess högersubträd och båda subträden är binära träd 47 Stefan Jozef Swiatycki DSV Bild 9 Höjden av ett fullt binärt träd 18 14 25 11 16 20 28 10 13 15 19 23 26 29 Antal noder i trädet 1 3 7 15 Höjd 0 1 2 3 På varje nivå får vi plats med dubbelt så många noder än på nivån ovanför. Antalet noder i ett fullt binärt träd = 2 (höjd+1) -1 Vid ett visst antal noder n blir alltså höjden av ett binärt träd = log 2 (n+1) -1 Vid sökningar och många andra operationer vandrar man ner genom trädet med början i roten och väljer väg (till vänster eller höger) vid varje nod. Trädets höjd blir det maximala antalet steg man behöver vandra - sökoperationerna blir alltså logaritmiskt beroende av antalet noder i trädet. Detta är mycket snabb sökning jämfört med sökning i arrayer eller länkade listor (som är linjärt beroende av antalet element). Jozef Swiatycki DSV Bild 10 5

Nodklass för ett binärt träd (ej återanvändbar) class Node{ int id; String data; Node left, right; Node(int i, String d){ id=i; data=d; left=right=null; // Konstruktor Dataattributen är inte skyddade för att få tydligare kod i metodexemplen, de borde givetvis vara deklarerade som private och avläsas med get-metoder public String tostring(){ return id + ": " + data; // tostring // Node Jozef Swiatycki DSV Bild 11 Klassen BinSearchTree (ej återanvändbar) public Node find(int sought){... public void insert(int id, String data){... public void print(){... void delete(int sought){... // BinSearchTree Jozef Swiatycki DSV Bild 12 6

Rekursiv sökfunktion Node findnode(node node, int sought){ if (node == null) return null; else if (node.id == sought) return node; else if (node.id > sought) return findnode(node.left, sought); else return findnode(node.right, sought); // findnode Jozef Swiatycki DSV Bild 13 Gränssnittsmetoder och privata hjälpmetoder Antag deklarationen BinSearchTree tree = new BinSearchTree(); Antag även att några noder har skapats och lagts till trädet tree. Ett anrop av den rekursiva metoden findnode skulle behöva se ut så här: Node tn = tree.findnode(tree.root, 73); Men en tillämpning har inte åtkomst till tree.root, dessutom känns det ondödigt att behöva ange tree.root vid varje anrop av metoden. Man brukar därför skapa publika gränssnittsmetoder som bara är till för att starta rekursionen och privata rekursiva metoder som gör jobbet: public Node find(int sought){ return findnode(root, sought); private Node findnode(node node, int sought){ // som tidigare Jozef Swiatycki DSV Bild 14 7

Iterativ implementering av sökfunktionen Sökning, insättning och borttag (men inte traversering) i binära sökträd kan även implementeras iterativt, varvid de kan bli mer effektiva. Koden blir dock lite grötig varför jag väljer att visa de elegantare rekursiva lösningarna. Nedan dock ett exempel på iterativ implementering av sökfunktionen: Node findnode(int sought){ Node temp = root; while (temp!= null && temp.id!=sought) if (temp.id > sought) temp=temp.left; else temp=temp.right; return temp; // findnode Jozef Swiatycki DSV Bild 15 Insättning av ny nod i trädet BinarySearchTree 47 Stefan find insert root 29 Beatrice 73 Jozef print delete Anna 61 Harald 97 Eskel 8 Urban 52 Mats 67 Tobbe 85 Alex 103 Peter newnode 50 Ola 80 Doris 83 Mia Jozef Swiatycki DSV Bild 16 8

Kod för insättning av ny nod i trädet public void insert(int id, String data){ Node newnode = new Node(id, data); root=insertnode(root, newnode); private Node insertnode(node node, Node newnode){ if (node == null) node = newnode; else if (node.id > newnode.id) node.left = insertnode(node.left, newnode); else node.right = insertnode(node.right, newnode); return node; Jozef Swiatycki DSV Bild Traversering (genomgång) av trädet Exempel: utskrift i sorteringsordning public void print(){ printtree(root); private void printtree(node node){ if (node!= null){ printtree(node.left); System.out.println(node); printtree(node.right); Jozef Swiatycki DSV Bild 18 9

Träd - traverseringsordning inorder - vänstra subträdet, noden själv, högra subträdet I binära sökträd ger detta traversering i sorteringsordning preorder - noden själv, vänstra subträdet, högra subträdet private void preorderprint(node node){ if (node!= null){ System.out.println(node); preorderprint(node.left); preorderprint(node.right); postorder - vänstra subträdet, högra subträdet, noden själv Jozef Swiatycki DSV Bild 19 Effektivisering av traverseringen På nedersta nivån i trädet finns lika många noder som i hela trädet i övrigt. Med något grötigare kod kan man därför halvera antalet metodanrop: public void print(){ if (root!= null) printtree(root); private void printtree(node node){ if (node.left!= null) printtree(node.left); System.out.println(node); if (node.right!= null) printtree(node.right); Jozef Swiatycki DSV Bild 20 10

Borttagning av en nod från trädet Tre fall: 1 - noden har inget vänsterbarn - ersätt den med dess högerbarn (täcker även fallet inget barn) 2 - noden har inget högerbarn - ersätt den med vänsterbarn 3 - noden har båda barnen - ersätt den med den vänstraste noden i dess högra subträd (eller högraste noden i vänstra subträdet) BinarySearchTree 47 Stefan find insert root 2 29 Beatrice 73 Jozef print delete Anna 1 61 Harald 3 ersätt 97 Eskel 28 Urban 52 Mats 67 Tobbe 85 Alex 103 Peter Jozef Swiatycki DSV Bild 21 Kod för borttagning av en nod från trädet private Node deletenode(node node, int sought){ if (node == null) return null; else if (node.id > sought) node.left = deletenode(node.left, sought); else if (node.id < sought) node.right = deletenode(node.right, sought); else if (node.left == null) node = node.right; else if (node.right == null) node = node.left; else { Node tmp=findleftmost(node.right); node.id = tmp.id; node.data = tmp.data; node.right = deleteleftmost(node.right); return node; Jozef Swiatycki DSV Bild 22 11

Borttagning av en nod från trädet (forts.) public void delete(int sought){ root = deletenode(root, sought); private Node findleftmost(node node){ if (node.left == null) return node; else return findleftmost(node.left); private Node deleteleftmost(node node){ if (node.left == null) return node.right; else { node.left = deleteleftmost(node.left); return node; Jozef Swiatycki DSV Bild 23 Generalisering Om det binära sökträdet ska kunna användas av godtyckliga tillämpningar uppstår det några problem som behöver lösas: strukturen med left/right-referenser i varje nod är en intern angelägenhet för trädklassen, tillämpningar borde inte behöva känna till dem eller få åtkomst till dem. Lösning: separera left/right-referenser från tillämpningens data genom att för varje tillämpningsobjekt skapa ett internt litet objekt, innehållande en referens till det instoppade objektet och left/right-referenser till andra interna objekt. det måste framgå på något sätt hur tillämpningens objekt identifieras. Lösning: separera id-värdet och datavärdet, d.v.s. tillämpningen får lov att stoppa in två värden: referensen till id-objektet och referensen till data-objektet id-värdena måste kunna jämföras (definiera en total ordning) Lösning: kräv att id-värdena uppfyller gränssnittet Comparable och alltså innehåller metoden compareto som tar ett annat objekt som argument och returnerar negativt om det egna objektet är mindre än, noll om det är lika med och positivt om det är större än argumentet tillämpningen måste få iterera över alla sina instoppade objekt för att utföra operationer på dem. Lösning: skapa en iteratorklass som ger tillgång till dataobjekten i sorteringsordning Jozef Swiatycki DSV Bild 24 12

Generalisering, forts. BinarySearchTree find insert iterator root compareto delete compareto compareto compareto compareto Jozef Swiatycki DSV Bild 25 Nodklass för ett återanvändbart binärt sökträd class Node{ Comparable id; Object data; Node left, right; Node(Comparable i, Object d){ id=i; data=d; left=right=null; // Konstruktor public String tostring(){ return id.tostring() + + data.tostring(); // tostring // Node Jozef Swiatycki DSV Bild 26 13

Fragment av återanvändbart binärt sökträd public Object find(comparable sought){ Node node = findnode(root, sought); if (node == null) return null; else return node.data; private Node findnode(node node, Comparable sought){ if (node == null) return null; else { int cmp = node.id.compareto(sought); if (cmp == 0) return node; else if (cmp > 0) return findnode(node.left, sought); else return findnode(node.right, sought); // findnode Jozef Swiatycki DSV Bild 27 Iterator för återanvändbart binärt sökträd Iteratorn för ett återanvändbart sökträd skapas med en kö av nodreferenser som fylls genom en inorder-genomgång av trädet. Varje anrop av iteratorns next-metod tar ut nästa nod ur kön och ger tillämpningen tillgång till nodens data-objekt. Metoden hasnext ger true så länge det finns noder kvar. next hasnext find insert BinarySearchTree root 29 Beatrice 47 Stefan 73 Jozef iterator delete Anna 61 Harald 97 Eskel Jozef Swiatycki DSV Bild 28 14

Användningsexempel class Pers{ String namn, telnr; Person(String n, String t) { namn=n; telnr=t; String getnamn() { return namn; String gettel() { return telnr; class Appl{ public static void main(string[] args){ BinSearchTree tellista = new BinSearchTree(); tellista.insert( Joz, new Pers( Joz, 1616 )); tellista.insert( Bea, new Pers( Bea, 164988 )); Pers p1 = (Pers)tellista.find( Bea ); Iterator iter = tellista.iterator(); while (iter.hasnext()){ Pers p2=(pers)iter.next(); System.out.println(p2.getNamn() + p2.gettel()); Jozef Swiatycki DSV Bild 29 Balansering De presenterade algoritmerna för sökning, insättning och borttag av en nod i ett binärt sökträd har en tidskomplexitet som är beroende av trädets höjd. De blir logaritmiska om trädet är balanserat, d.v.s. skillnaden mellan den minsta nivån för en lövnod och den största nivån för en lövnod är högst 1. Även om trädet bara är någorlunda balanserat (noderna är någorlunda jämt fördelade mellan höger- och vänstersubträden) blir algoritmerna logaritmiska. Men om noderna läggs in t.ex. i sorteringsordning degenererar tidskomplexiteten till att bli linjär. Det finns därför varianter av binära sökträd som automatiskt balanserar sig för varje insättning eller borttag (AVL-träd, black-red-träd). Det finns andra (än binära) självbalanserande trädstrukturer, viktigast av dessa är B-träd (Balanserade träd eller Bayer-träd efter deras skapara Rudolf Bayer). Dessa faller dock utanför ramen för denna presentation. Jozef Swiatycki DSV Bild 30 15