Datastrukturer, algoritmer och programkonstruktion (DVA104, HT 2014) Föreläsning 5?
FORTSÄTTNING TRÄD
RECAP (förra föreläsningen)
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier Ett träd är en samling element som sparas i noder, vilka är sammankopplade i en trädstruktur
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier Ett träd är en samling element som sparas i noder, vilka är sammankopplade i en trädstruktur Toppen på trädet kallas rot och varje träd (delträd) har en ensam rot
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier Ett träd är en samling element som sparas i noder, vilka är sammankopplade i en trädstruktur Toppen på trädet kallas rot och varje träd (delträd) har en ensam rot Binära träd En speciell kategori av träd Varje förgrening går till högst två noder
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier Ett träd är en samling element som sparas i noder, vilka är sammankopplade i en trädstruktur Toppen på trädet kallas rot och varje träd (delträd) har en ensam rot Binära träd En speciell kategori av träd Varje förgrening går till högst två noder Begrepp: Nod, Barn, Löv, Förälder
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier Ett träd är en samling element som sparas i noder, vilka är sammankopplade i en trädstruktur Toppen på trädet kallas rot och varje träd (delträd) har en ensam rot Binära träd En speciell kategori av träd Varje förgrening går till högst två noder Begrepp: Nod, Barn, Löv, Förälder ADT:ns interface och operationer pekare till vänster barn data pekare till höger barn
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier Ett träd är en samling element som sparas i noder, vilka är sammankopplade i en trädstruktur Toppen på trädet kallas rot och varje träd (delträd) har en ensam rot Binära träd En speciell kategori av träd Varje förgrening går till högst två noder Begrepp: Nod, Barn, Löv, Förälder ADT:ns interface och operationer Implementation av en trädnod (BTree) i C pekare till vänster barn data pekare till höger barn
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier Ett träd är en samling element som sparas i noder, vilka är sammankopplade i en trädstruktur Toppen på trädet kallas rot och varje träd (delträd) har en ensam rot Binära träd En speciell kategori av träd Varje förgrening går till högst två noder Begrepp: Nod, Barn, Löv, Förälder ADT:ns interface och operationer Implementation av en trädnod (BTree) i C pekare till vänster barn Kod för InsertSorted - mindre till vänster och större till höger data pekare till höger barn
RECAP (förra föreläsningen) Träd är icke-linjära datastrukturer som ofta används för att beskriva hierarkier Ett träd är en samling element som sparas i noder, vilka är sammankopplade i en trädstruktur Toppen på trädet kallas rot och varje träd (delträd) har en ensam rot Binära träd En speciell kategori av träd Varje förgrening går till högst två noder Begrepp: Nod, Barn, Löv, Förälder ADT:ns interface och operationer Implementation av en trädnod (BTree) i C Kod för InsertSorted - mindre till vänster och större till höger Traversering av binära träd (preorder, inorder och postorder) pekare till vänster barn data pekare till höger barn
RECAP (förra föreläsningen) A: B: C: Toppen på trädet kallas rot och varje träd (delträd) har en ensam rot C utgör roten i ett delträd C: D: D: E: F: E: F:
RECAP (förra föreläsningen) TRAVERSERING De metoder som brukar användas kallas: Preorder: behandlar data före besök av barnträden Inorder: behandlar data mellan besöken av barnträden Postorder: behandla data efter att barnträden besökts?
TRAVERSERING ÖVNING Hur ser funktionerna för att traversera med dessa tre metoder ut? Preorder: behandla data före besök av barnträden Inorder: behandla data mellan besöken av barnträden Postorder: behandla data efter att barnträden besökts Skriv en funktion för vardera traverseringsmetod Använd rekursion
ÖVNING EN LÖSNING PreOrder(BTreeNode root) //root till delträd (första gången - hela trädet) If root!= null then //om ej tomt träd Print(root) //gör något med noden PreOrder(root.left) //gå till vänster barnträd PreOrder(root.right) //gå till höger barnträd end if InOrder(BTreeNode root) If root!= null then InOrder(root.left) Print(root) InOrder(root.right) end if //root till delträd (första gången - hela trädet) //om ej tomt träd //gå till vänster barnträd //gör något med noden //gå till höger barnträd PostOrder(BTreeNode root) //root till delträd (första gången - hela trädet) If root!= null then //om ej tomt träd PostOrder(root.left) //gå till vänster barnträd PostOrder(root.right) //gå till höger barnträd Print(root) //gör något med noden end if
REMOVE Ta bort godtycklig nod från det sorterade binära trädet Trädet ska fortfarande vara sorterat efter bortagningen
REMOVE Ta bort godtycklig nod från det sorterade binära trädet Trädet ska fortfarande vara sorterat efter bortagningen Tre fall: Ta bort löv Ta bort nod med höger ELLER vänsterbarn Ta bort en nod med höger OCH vänsterbarn
REMOVE Ta bort löv root 10 6 Remove( ) 8 20 5 15 30 6
REMOVE Ta bort löv root 10 6 Remove( ) 8 20 Leta reda på noden som ska tas bort, (se till att komma åt dess förälder på något sätt) 5 15 30 6
REMOVE Ta bort löv root 10 6 Remove( ) 8 20 Leta reda på noden som ska tas bort, (se till att komma åt dess förälder på något sätt) 5 15 30 Sätt förälderns pekare (som pekar på noden som ska tas bort) till null 6
REMOVE Ta bort löv root 10 6 Remove( ) 8 20 Leta reda på noden som ska tas bort, (se till att komma åt dess förälder på något sätt) 5 15 30 Sätt förälderns pekare (som pekar på noden som ska tas bort) till null Lövet är borttaget 6
REMOVE Ta bort löv parent remove root 10 sätt remove till samma som rooten. Låt parent vara NULL 6 Remove( ) 8 20 Leta reda på noden som ska tas bort, (se till att komma åt dess förälder på något sätt) 5 15 30 Sätt förälderns pekare (som pekar på noden som ska tas bort) till null Lövet är borttaget 6
REMOVE Ta bort löv remove parent 8 root 10 Sätt parent till remove och flytta remove till vänster barn - 6 är mindre än 10 20 6 Remove( ) Leta reda på noden som ska tas bort, (se till att komma åt dess förälder på något sätt) 5 15 30 Sätt förälderns pekare (som pekar på noden som ska tas bort) till null Lövet är borttaget 6
REMOVE Ta bort löv parent root 10 Sätt parent till remove och flytta remove till vänster barn - 6 är mindre än 8 6 Remove( ) 8 20 Leta reda på noden som ska tas bort, (se till att komma åt dess förälder på något sätt) 5 remove 15 30 Sätt förälderns pekare (som pekar på noden som ska tas bort) till null Lövet är borttaget 6
REMOVE Ta bort löv root 10 Sätt parent till remove och flytta remove till höger barn - 6 är större än 5 6 Remove( ) 8 20 Leta reda på noden som ska tas bort, (se till att komma åt dess förälder på något sätt) 5 parent 15 30 Sätt förälderns pekare (som pekar på noden som ska tas bort) till null 6 remove Noden är hittad! Lövet är borttaget
REMOVE Ta bort löv root 10 6 Remove( ) 8 20 Leta reda på noden som ska tas bort, (se till att komma åt dess förälder på något sätt) 5 parent 15 30 Sätt förälderns pekare (som pekar på noden som ska tas bort) till null 6 remove sätt parent s högerlänk till NULL - för att länka bort 6 Lövet är borttaget glöm inte att frigöra minnet för remove
REMOVE Ta bort nod med ett barn Nu är det fyra saker vi måste testa Noden som skall tas bort kan ha ett vänsterbarn Noden som skall tas bort kan ha ett högerbarn Noden som ska tas bort kan vara ett vänsterbarn Noden som ska tas bort kan vara ett högerbarn
REMOVE Ta bort nod med ett barn Generell Algoritm Om noden som ska tas bort har ett vänsterbarn Om noden är ett vänsterbarn Förälderns vänsterpekare ska peka på nodens vänsterbarn Annars (om noden är ett högerbarn) Förälderns högerpekare ska peka på nodens vänsterbarn Annars (om noden har ett högerbarn) Om noden är ett vänsterbarn Förälderns vänsterpekare ska peka på nodens högerbarn Annars (om noden är ett högerbarn) Förälderns högerpekare ska peka på nodens högerbarn
REMOVE Ta bort nod med ett barn root 10 5 Remove( ) 8 20 5 15 30 6
REMOVE Ta bort nod med ett barn root 10 5 Remove( ) 8 20 Har ett högerbarn 5 15 30 6
REMOVE Ta bort nod med ett barn root 10 5 Remove( ) 8 20 Har ett högerbarn Är ett vänsterbarn 5 15 30 6
REMOVE Ta bort nod med ett barn root 10 5 Remove( ) 5 8 20 15 30 Har ett högerbarn Är ett vänsterbarn Förälderns vänsterpekare ska peka på nodens högerbarn 6
REMOVE Ta bort nod med ett barn root parent 10 5 Remove( ) 8 20 Har ett högerbarn Är ett vänsterbarn remove 5 15 30 Förälderns vänsterpekare ska peka på nodens högerbarn 6
REMOVE Ta bort nod med ett barn root parent 10 5 Remove( ) 8 20 Har ett högerbarn Är ett vänsterbarn remove 5 15 30 Förälderns vänsterpekare ska peka på nodens högerbarn glöm inte att frigöra minnet för remove 6
REMOVE Ta bort nod med ett barn root 10 8 Remove( ) 8 20 6 15 30
REMOVE Ta bort nod med ett barn root 10 8 Remove( ) 8 20 Har ett vänsterbarn 6 15 30
REMOVE Ta bort nod med ett barn root 10 8 Remove( ) 8 20 Har ett vänsterbarn Är ett vänsterbarn 6 15 30
REMOVE Ta bort nod med ett barn root 10 8 20 6 15 30 8 Remove( ) Har ett vänsterbarn Är ett vänsterbarn Förälderns vänsterpekare ska peka på nodens vänsterbarn
REMOVE Ta bort nod med ett barn parent root 10 remove 8 20 6 15 30 8 Remove( ) Har ett vänsterbarn Är ett vänsterbarn Förälderns vänsterpekare ska peka på nodens vänsterbarn
REMOVE Ta bort nod med ett barn parent root 10 remove 8 20 6 15 30 8 Remove( ) Har ett vänsterbarn Är ett vänsterbarn Förälderns vänsterpekare ska peka på nodens vänsterbarn glöm inte att frigöra minnet för remove
REMOVE Ta bort nod med två barn 45 Nod att ta bort 52 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 Nod att ta bort Vi kan inte bara flytta delträdet (som vi gjorde när noden har ett barn), vart ska vi då sätta nod 49 med delträd? 52 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 Nod att ta bort 52 49 54 Hur skulle en algoritm för att ta bort en nod med två barn kunna se ut? Fundera en stund! 46 50 53 55
REMOVE Ta bort nod med två barn Generell Algoritm 1. Hitta det minsta värdet i höger delträd eller det största värdet i vänster delträd 2. Kopiera detta värde till den nod som ska tas bort 3. Ta bort den nod som kopierades
REMOVE Ta bort nod med två barn 45 Nod att ta bort 52 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 Hitta minsta värdet i höger delträd 52 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 53 Hitta minsta värdet i höger delträd Kopiera 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 53 Hitta minsta värdet i höger delträd Kopiera Ta bort 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 49 53 Hitta minsta värdet i höger delträd Kopiera Ta bort 54 Observera att noden som tas bort kan ha ett högerbarn och att vi då måste hantera borttagning av nod med ett barn! 46 50 53 55
REMOVE Ta bort nod med två barn 45 49 53 Hitta minsta värdet i höger delträd Kopiera Ta bort 54 Är detta fortfarande ett sorterat binärt träd? 46 50 55
REMOVE Ta bort nod med två barn 45 Nod att ta bort 52 Eller... 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 Hitta största värdet i vänster delträd 52 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 50 Hitta största värdet i vänster delträd Kopiera 49 54 46 50 53 55
REMOVE Ta bort nod med två barn 45 49 50 Hitta största värdet i vänster delträd Kopiera Ta bort 54 Observera att noden som tas bort kan ha ett vänsterbarn och att vi då måste hantera borttagning av nod med ett barn! 46 50 53 55
REMOVE Ta bort nod med två barn 45 49 50 Hitta största värdet i vänster delträd Kopiera Ta bort 54 Är detta fortfarande ett sorterat binärt träd? 46 53 55?
HÖJDEN PÅ ETT FULLT TRÄD Höjd = 1, n = 1 Höjd = 2, n = 3 Höjd = 3, n = 7 Höjd = 4, n = 15 Den höjd trädet bör ha om det är balanserat Så att n = 2 h - 1 Eller h = log2(n + 1)
BALANSERING Trädets höger och vänster delträd ska vara lika stora (så gott det går) Ej balanserat Balanserat höjd = 3 höjd = 4
BALANSERING Hur tar vi reda på om ett träd är balanserat eller inte? Jämför det faktiska nivådjupet med det teoretiska nivådjupet, är det faktiska djupare så är trädet obalanserat. Hur gör vi själva balanseringen? Fundera på hur en algoritm skulle kunna se ut. Tips, använd en array för mellanlagring
BALANSERING Algoritm för att balansera ett binärt träd Vi kan använda rotation, om vi hinner hanterar vi detta senare i kursen annars läser ni på själva (AVL träd) En mer hands on algoritm är: Skriv hela trädet till en array i sorterad ordning (inorder). Töm trädet (frigör allt minne och sätt rooten till NULL) Bygg trädet rekursivt från arrayen enligt nedan: Vänster del av arrayen/delarrayen till vänster delträd Höger del av arrayen/delarrayen till höger delträd Tills alla element i arrayen är inlagda i trädet
ÖVNING Balansera följande träd med föregående algoritm 10 Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 5 20 30 40 50 60
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 Bygg upp trädet rekursivt:
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 Bygg upp trädet rekursivt: 30 root mittersta blir root
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 vänster delarray bildar vänster delträd - mittersta i delarrayen blir vänster delträds root root i delträd Bygg upp trädet rekursivt: 10 30 root
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 Bygg upp trädet rekursivt: 30 root vänster delarray bildar vänster delträd - mittersta i delarrayen blir vänster delträds root root i delträd 5 10
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 höger delarray bildar höger delträd - mittersta i delarrayen blir höger delträds root Bygg upp trädet rekursivt: 30 10 root i delträd 5 20 root
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 höger delarray bildar höger delträd - mittersta i delarrayen blir höger delträds root Bygg upp trädet rekursivt: 10 5 20 30 50 root root i delträd
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 Bygg upp trädet rekursivt: 30 root vänster delarray bildar vänster delträd - mittersta i delarrayen blir vänster delträds root 5 10 20 40 50 root i delträd
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 Bygg upp trädet rekursivt: 30 root höger delarray bildar höger delträd - mittersta i delarrayen blir höger delträds root 5 10 20 50 40 60 root i delträd
ÖVNING EN LÖSNING Antal noder = 7 Faktiskt djup/höjt = 6 Teoretiskt djup/höjd = log2(7+1) = 3 Inorder till array: 5 10 20 30 40 50 60 Bygg upp trädet rekursivt: 30 root Hela arrayen är behandlad - Trädet är byggt! 10 5 20 50 40 60? Sorterat och Balanserat Binärt Träd
BINÄRT TRÄD (linjärt minne) Ett binärt träd kan lagras i ett enda sammanhängande minne - t.ex. en array Roten har index 1 Vänster barn till nod i har index 2*i Höger barn till nod i har index 2*i + 1 Föräldern till nod i har index = heltalsdelen av i/2
1 H Roten har index 1 2 D 3 K 4 5 B F 6 7 J L 8 9 10 11 12 A C E G I 0 1 2 3 4 5 6 7 8 9 10 11 12 H D K B F J L A C E G I Vänster barn till nod i har index 2*i Höger barn till nod i har index 2*i + 1 Föräldern till nod i har index i/2 (int)
LINJÄRT MINNE Sammanhängande minne är ej flexibelt Om trädet inte är fullt reserveras onödigt mycket minne - man måste veta hur stort trädet ska vara från början Borttagning och insättning av noder kan kräva kopiering Effektivt Traversering (goda cache-effekter) Vet man storleken innan och den inte ändras så elimineras problemen...återkommer i samband med sortering
INFÖR LABBEN Läs labbspecen noggrant och flera gånger bryt ut vad det är som ska göras samt vilka krav som finns Gör ett interface (på papper eller direkt i datorn) - diskutera med en kompis Skapa noden och själva trädet samt ett enklare huvudprogram Gör en funktion i taget (i den mån det går) - och TESTA! När du tror att du är färdig - läs labbspecen igen...?