Præsentation er lastning. Vent venligst

Præsentation er lastning. Vent venligst

1 Fundamentale datastrukturer 2 * Definitioner: abstrakt datatype, datastruktur *Elementære datastrukturer og abstrakte datatyper: arrays, hægtede lister,

Lignende præsentationer


Præsentationer af emnet: "1 Fundamentale datastrukturer 2 * Definitioner: abstrakt datatype, datastruktur *Elementære datastrukturer og abstrakte datatyper: arrays, hægtede lister,"— Præsentationens transcript:

1

2 1 Fundamentale datastrukturer

3 2 * Definitioner: abstrakt datatype, datastruktur *Elementære datastrukturer og abstrakte datatyper: arrays, hægtede lister, stakke, køer *Træer: terminologi, egenskaber, repræsentation, gennemgang Plan

4 3 Definitioner En type er en samling af værdier. Eks. typen boolean omfatter værdierne true og false En abstrakt datatype er en datatype, der udelukkende er specificeret ved hjælp af typen og de tilknyttede operationer. Kun operationernes input/output-relationer er specificeret - ikke deres konkrete realisering. Hverken datarepræsentation eller algoritmer må medtages i specifikationen. En abstrakt datatype specificerer ”hvad”, men ikke ”hvordan”. En datatype er en type tilknyttet en mængde af operationer på typen. Eks. typen int er en datatype. Addition er et eksempel på en tilknyttet operation.

5 4 Abstrakte datatyper En ADT skjuler den konkrete implementation fra anvenderen (klienten). Fordele: (1) Det er lettere at bruge noget, hvis det ikke kræver internt kendskab til virkemåden. Tænk f.eks. på en radio eller en vaskemaskine (2) Den konkrete implementation kan ændres, uden at klienten behøver at få det at vide. Realisering i Java: En ADT kan realiseres som en klasse, hvor data er private. Brug “ set ters” and “ get ters” til at ændre og tilgå data.

6 5 En datastruktur er en samling variabler, muligvis af forskellig type, der er indbyrdes forbundet på en eller anden måde. Realisering i Java: ved simple variabler, arrays og klasseobjekter Datastruktur

7 6 (1) Datastruktur: Et array er en sammenhængende blok af lagerceller, hvor hver lagercelle indeholder et dataelement af en fast længde. Arrays (to perspektiver) cellearray

8 7 (2) Abstrakt datatype: Et array er en samling af dataelementer af samme type, hvor hvert dataelement kan identificeres med et heltal, kaldet indeks. Med dette perspektiv kan et array implementeres på mange måder.

9 8 Datastrukturen array Realisering i Java: Oprettelse: int a[] = new int[100]; eller int[] a = new int[100]; opretter et array med 100 elementer af typen int : a[0], a[1],..., a[99] Tilgang til et element: a[27] Aflæsning af arrayets længde: a.length (= 100)

10 9 Vigtig egenskab Tilgangstiden til ethvert element er konstant. a[0] a[1] a[2] a[3] a[4] a[5] a[6] 0: 1: 2: 3: 4: 5: 6: adresse( a[i] ) = adresse( a[0] ) + i *længde(type) adresse( a[0] )

11 10 Eratosthenes si (Eratosthenes, cirka 300 f. Kr.) Et primtal er et positivt heltal ≥ 2, som ikke er deleligt med andre tal end 1 og sig selv, f.eks. 2, 3, 5, 7, 11. Ide til algoritme: Opret et boolean array isPrime med alle elementer sat til true. Gennemløb herefter alle tal mellem 2 og N, som er produktet af to tal (begge > 1), og sæt isPrime til false for disse. Herefter udskrives de tal, i, hvor isPrime[i] stadig er true. Problem: udskriv alle primtal ≤ N 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50

12 11 public class Eratosthenes { final static int N = 100000000; public static void main(String args[]) { boolean isPrime[] = new boolean[N+1]; int i, j; for (i = 2; i <= N; i++) isPrime[i] = true; for (i = 2; i <= N/2; i++) for (j = 2; j <= N/i; j++) IsPrime[i*j] = false; for (i = 2; i <= N; i++) if (IsPrime[i]) IO.print(i + " "); IO.println(); } Vi skal gennemløbe alle tal i*j, hvor i ≥ 2, j ≥ 2 og i*j ≤ N. Hvis j ≥ 2 og i *j ≤ N, så må i ≤ N/2. Hvis i *j ≤ N, så må j ≤ N/i. Dette giver nedenstående Java-program. Vanskeligheden ligger i gennemløbet.

13 12 Koden kan effektiviseres ved at indsætte testen if (isPrime[i]) før j -løkken. Hvorfor? I j -løkkens itialiseringsdel kan j = 2 erstattes med j = i. Hvorfor? I i -løkkens betingelsesdel kan i <= N/2 erstattes med i*i <= N. Hvorfor? for (i = 2; i <= N/2; i++) for (j = 2; j <= N/i; j++) IsPrime[i*j] = false; Effektivisering for (i = 2; i*i <= N; i++) if (isPrime[i]) for (j = i; j <= N/i; j++) IsPrime[i*j] = false;

14 13 Version 1: for (i = 2; i <= N/2; i++) for (j = 2; j <= N/i; j++) IsPrime[i*j] = false; Version 2: for (i = 2; i <= N/2; i++) if (isPrime[i]) for (j = 2; j <= N/i; j++) IsPrime[i*j] = false; Version 3: for (i = 2; i <= N/2; i++) if (isPrime[i]) for (j = i; j <= N/i; j++) IsPrime[i*j] = false; Version 4: for (i = 2; i*i <= N; i++) if (isPrime[i]) for (j = i; j <= N/i; j++) IsPrime[i*j] = false; Version 5: for (i = 2; i*i <= N; i++) if (isPrime[i]) for (p = i*i; p <= N; p += i) IsPrime[p] = false; Måling af programeffektivitet Version j / p -iterationer Tid (sek) 1 1,657,511,569 491.0 2 309,275,826 74.2 3 242,570,204 48.2 4 242,570,204 44.7 5 242,570,204 44.7 N = 100,000,000 Mac G3, 233 MHz

15 14 Måling af tidsforbrug i Java double startTime = System.currentTimeMillis(); Kode IO.println("Time: " + (System.currentTimeMillis() - startTime)/1000 + "seconds");

16 15 Realisering i Java: Oprettelse: int a[][] = new int[5][4]; opretter et array med 5*4 = 20 heltallige elementer: a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] a[3][0] a[3][1] a[3][2] a[3][3] a[4][0] a[4][1] a[4][2] a[4][3] 2-dimensionale arrays Tilgang til element: a[3][2] Aflæsning af antal rækker: a.length (= 5) Aflæsning af antal søjler: a[0].length (= 4)

17 16 int karakter[][] = new int[100][10]; // 100 elever, 10 fag float gennemsnit(int elev, int k[][]) { int sum = 0; for (int f = 0; f < k[elev].length; f++) sum += k[elev][f]; return ((float) sum)/k[elev].length; } Eksempel på anvendelse For en mængde elever er oplyst deres karakterer i en række fag. Programmér en metode i Java, der kan beregner karaktergennemsnittet for en given elev. Beregning af gennemsnittet for elev nummer 3: gennemsnit(3, karakter);

18 17 public class TriangularMatrix { private int a[][]; public TriangularMatrix(int n) { a = new int[n][]; for (int i = 0; i < n; i++) a[i] = new int[i+1];} public int get(int i, int j) { return i >= j ? a[i-1][j-1] : a[j-1][i-1];} public void set(int i, int j, int value) { if (i >= j) a[i-1][j-1] = value; else a[j-1][i-1] = value;} } Kompakt repræsentation af symmetrisk matrix 1 n 1n a ij = a ji for alle 1≤i≤n og 1≤j≤n

19 18 En hægtet liste er en mængde at dataelementer, der er organiseret sekventielt, således at hvert element (kaldet en knude) indeholder en peger (kaldet en hægte) til det næste element. Hægtede lister ALI S T z head A L I S T Bemærk: enhver knude indeholder en hægte, også listens sidste. I lærebogen benyttes konsekvent følgende konvention ( head og z er ekstraknuder):

20 19 Operationer på hægtede lister (1) Indsættelse A L I S T z head X (2) Sletning Tidsforbrug: Konstant. Kun 2 hægter skal ændres (uafhængigt af listens længde) Tidsforbrug: Konstant. Kun 1 hægte skal ændres (uafhængigt af listens længde) X z A L I S T head

21 20 Arrays og hægtede lister (pro et contra) Visse operationer er mere effektive for en liste end for et array, f.eks. indsættelse og sletning. Men visse operationer er mere effektive for et array, f.eks. bestemmelse af det k´te element. En array-repræsentation fylder mindre (der spares plads til hægterne).

22 21 Implementering af hægtede lister i Java zhead Oprettelse af en tom liste: Node head = new Node(), z = new Node(); head.next = z.next = z; class Node { Node next; } class ListItem extends Node { String key; // eller int key; ListItem(String k) { key = k; } }

23 22 class Node { Node next; public void insertAfter(Node t) { next = t.next; t.next = this; } public void deleteAfter(Node t) { t.next = next; } Implementering af indsættelse og sletning t t.next this

24 23 int N = IO.readInt(), M = IO.readInt(); Node t = new ListItem(1), x = t; for (int i = 2; i <= N; i++) t = t.next = new ListItem(i); t.next = x; while (t != t.next) { for (int i = 1; i < M; i++) t = t.next; x = t.next; t.next = x.next; } IO.println(((ListItem) t).key); Problem. N personer står i en rundkreds. Den M´te person i rundkredsen begår selvmord, indtil alle er døde. Hvem begår selvmord sidst? Cirkulær hægtet liste (Josephus problem) t x next

25 24 eller ved parallelle arrays: integer next[] = new int[2+N]; String key[] = new String[2+N]; int z = 0, head = 1; next[head] = next[z] = z; Array repræsentation af lister Objektreferencer erstattes af indices. Enten ved class Node { int next; String key; } Node table[] = new Node[2+N]; int z = 0, head = 1; table[head].next = table[z].next = z;

26 25 Dermed kan programmøren selv håndtere automatisk lagerallokering: Allokering: (svarer til x = new... ) x = free; free = next[free]; Frigivelse: (af x ) next[x] = free; free = x; Fri liste Flere lister kan være repræsenteret i et og samme array, bl.a. en liste over ubenyttede knuder, en såkaldt fri liste. int z = 0, head = 1, free; next[head] = next[z] = z; for (free = 2; free < N; free++) next[free] = free+1; next[N] = z; free = 2;

27 26 Dobbelthægtede lister Problemer med enkelthægtede lister: En knude kan ikke fjernes effektivt fra en liste, med mindre forgængerknuden er kendt. Listen kan kun gennemløbes i én retning. Løses med en dobbelthægtet liste. I det følgende præsenteres en Java-pakke til håndtering af tovejslister. Pakken svarer helt til Simulas indbyggede pakke SIMSET. A L I S T

28 27 Klasserne Link og Head fra en klients synspunkt Head: Listehovedet Link: Et listeelement first() last() suc() null suc() pred() Head Link

29 28 public class Link { public Link pred(); public Link suc(); public void out(); public void into(Head h); public void follow(Link_eller_Head p); public void precede(Link_eller_Head p); } Pakken simset package simset; public class Head { public Link first(); public Link last(); public boolean empty(); public int cardinal(); public void clear(); }

30 29 Eksempel på anvendelse (oprettelse og udskrivning af en liste af tal) import simset.*; import IO.*; class Number extends Link { int value; Number(int v) { value = v; } } Head list = new Head(); for (int i = 1; i <= 10; i++) new Number(i).into(list); Number n = (Number) list.first(); while (n != null) { IO.println(n.value); n = (Number) n.suc(); } while (!list.empty()) { n = (Number) list.first(); IO.println(n.value); n.out(); }

31 30 Skabeloner for listegennemløb eller: (2) for (e = list.first(); e != null; e = e.suc()) process(e); (1) e = list.first(); while (e != null) { process(e); e = e.suc(); }

32 31 Implementationen af klasserne i simset SUC PRED SUC PRED Head extends Linkage Link extends Linkage Link extends Linkage Link extends Linkage

33 32 Class Linkage (fælles overklasse for Head og Link) public class Linkage { public Link pred() { return PRED instanceof Link ? (Link) PRED : null; } public Link suc() { return SUC instanceof Link ? (Link) SUC : null; } public Linkage prev() { return PRED; } Linkage PRED, SUC; }

34 33 class Head public class Head extends Linkage { public Head() { PRED = SUC = this; } public Link first() { return suc(); } public Link last() { return pred(); } public boolean empty() { return SUC == this; } public int cardinal() { int i = 0; Link p; for (p = first(); p != null; p = p.suc()) i++; return i; } public void clear() { while (first() != null) first().out(); } }

35 34 class Link public class Link extends Linkage { public void out() { if (SUC != null) { SUC.PRED = PRED; PRED.SUC = SUC; SUC = PRED = null; } public void follow(Linkage p) { out(); if (p != null && p.SUC != null) { PRED = p; SUC = p.SUC; SUC.PRED = p.SUC = this; } public void precede(Linkage p) { out(); if (p != null && p.SUC != null) { SUC = p; PRED = p.PRED; PRED.SUC = p.PRED = this; } public void into(Head h) { precede(h); } }

36 35 public void out() { if (SUC != null) { SUC.PRED = PRED; PRED.SUC = SUC; SUC = PRED = null; } this SUC PRED SUC PRED SUC PRED Metoden out

37 36 public void follow(Linkage p) { out(); if (p != null && p.SUC != null) { PRED = p; SUC = p.SUC; SUC.PRED = p.SUC = this; } SUC PRED SUC PRED SUC PRED this p Metoden follow

38 37 En stak (LIFO = LastInFirstOut) En stak er en sekvens af dataelementer af samme type, som muliggør følgende to operationer: push(v): Læg dataelementet v øverst på stakken (dvs. i begyndelsen af stakken) pop: Fjern det øverste element på stakken Stak poppush

39 38 En stak er en abstrakt datatype public class Stack { public Stack(int max); public Stack(); public void push(ItemType v); public ItemType pop(); public boolean empty(); } Itemtype skal erstattes af en type, f.eks. char eller Object.

40 39 Repræsentation af stak ved hjælp af array public class Stack { private char stack[]; private int p; public Stack(int max) { stack = new char[max]; p = 0; } public Stack() { this(100); } public void push(char v) { stack[p++] = v; } public char pop() { return stack[--p]; } public boolean empty() { return p == 0; } } Itemtype er her char. Kan noget gå galt?

41 40 Repræsentation af stak ved hjælp af hægtet liste class Node { char key; Node next; } public class Stack { private Node head, z; public Stack() { head = new Node(); z = new Node(); head.next = z; z.next = head; } public Stack(int max) { this(); } public void push(char v) { Node t = new Node(); t.key = v; t.next = head.next; head.next = t; } public char pop() { Node t = head.next; head.next = t.next; return t.key; } public boolean empty() { return head.next == z; } }

42 41 Anvendelse af stakke Beregning af aritmetiske udtryk Udførelse af metodekald

43 42 Eksempel på stakanvendelse (evaluering af postfix-udtryk) Infix-notation: Operatorer imellem operander, f.eks. a + b Postfix-notation (omvendt polsk): Operatorer efter operander, f.eks. a b + Fra infix til postfix: (a + b) -> a b + x + y * z -> x y z * + x + y - z ->x y + z - OBS: postfix-notation er parentesfri!

44 43 Evaluering af postfix-udtryk infix: ( 5 * ( ( ( 9 + 8 ) * ( 4 * 6 ) ) + 7 ) ) postfix:5 9 8 + 4 6 * * 7 + * p p 5 p 5 9 p 5 9 8 p 5 17 p 5 4 p 5 4 6p 5 24 p 5 408 p 5 7 p 5 415 p 2075

45 44 Et Java-program til evaluering af postfix-udtryk public class Program { static char get() throws IOException { return (char) System.in.read(); } public static void main(String[] args) throws IOException { char c; Stack acc = new Stack(50); while ((c = get()) != (char) (-1)) { while (c == ' ') c = get(); int x = 0; if (c == '+') x = acc.pop() + acc.pop(); if (c == '*') x = acc.pop() * acc.pop(); while (c >= '0' && c <= '9') { x = 10*x + (c-'0'); c = get(); } acc.push(x); } System.out.println(acc.pop()); }

46 45 Konvertering af infix-udtryk til postfix-udtryk (Dijkstras vigesporsalgoritme) Infix-streng Postfix-streng operander operatorer Operatorstak

47 46 Konvertering af infixudtryk, der er “mættet” med parenteser. infix: ( 5 * ( ( ( 9 + 8 ) * ( 4 * 6 ) ) + 7 ) ) 5 p * 5 9 p * 5 p p * 5 9 8 + 5 9 8 + 4 * * p 5 9 8 p * + 5 9 p * + p * 5 9 8 + * 5 9 8 + 4 6 * * p * p 5 9 8 + 4 6 * * * p * + 5 9 8 + 4 6 * * 7 p + *

48 47 public class Program { static char get() throws IOException { return (char) System.in.read(); } static void put(char c) { System.out.print(c); } public static void main(String[] args) throws IOException { char c; Stack save = new Stack(50); while ((c = get()) != (char) (-1)) { if (c == ')') put(save.pop()); if (c == '+' || c == '*') save.push(c); while (c >= '0' && c <= '9') { put(c); c = get(); } if (c != '(') put(' '); } put('\n'); } Et Java-program til konvertering af infix-udtryk til postfix-udtryk

49 48 Brug af stak til håndtering af metodekald int f(int a1, int a2, int a3) { int b1, b2, b3; }

50 49 En kø (FIFO = FirstInFirstOut) En kø er en sekvens af dataelementer af samme type, som muliggør følgende to operationer: put(v): Sæt dataelementet v bagest i køen get: Fjern det første element fra køen get put Kø

51 50 v1v1 v2v2 v3v3 v4v4 v5v5 head tail v2v2 v3v3 v4v4 v5v5 head tail get v2v2 v3v3 v4v4 v5v5 head tail put(v 6 ) v6v6 Repræsentation af kø ved hjælp af array (cirkulær buffer)

52 51 public class Queue { private char queue[]; private int head, tail, size; public Queue(int max) { size = max; queue = new char[max + 1]; head = tail = 0; } public Queue() { this(100); } public void put(char v) { queue[tail++] = v; if (tail > size) tail = 0; } public char get() { char t = queue[head++]; if (head > size) head = 0; return t; } public boolean empty() { return head == tail; } } Hvad er betingelsen for at køen er fuld? Svar: (tail+1)%size == head

53 52 Implementation af kø ved hjælp af pakken simset import simset.*; class Node extends Link { char key; Node(char key) { this.key = key; } } public class Queue { private Head q; public Queue() { q = new Head(); } public void put(char v) { new Node(v).into(q); } public char get() { Node t = (Node) q.first(); t.out(); return t.key; } public boolean empty() { return q.empty(); } }

54 53 Java-klassen Vector (en klasse til håndtering af dynamiske tabeller) class Vector { Object elementAt(int index); void setElementAt(Object obj, int index); void insertElementAt(Object obj, int index); void removeElementAt(int index); void addElement(Object obj); void removeElement(Object obj); boolean contains(Object obj); boolean isEmpty(); int size(); int indexOf(Object obj); Object firstElement(); Object lastElement(); }

55 54 Java-klassen Stack (implementeret ved hjælp af class Vector) class Stack extends Vector { Object push(Object obj) { addElement(obj); return obj; } Object pop() { Object obj = peek(); removeElementAt(size() - 1); return obj; } Object peek() { int len = size(); if (len == 0) throw new EmptyStackException(); return elementAt(len - 1); } public boolean empty() { return size() == 0; } }

56 55 Træer Et træ er en samling af knuder og kanter, (V, E), som opfylder visse krav: En knude, v, er et simpelt dataobjekt, der kan have et navn og en tilknyttet information. En af knuderne er udpeget som rod i træet. En kant, (v 1,v 2 ), er en forbindelse imellem to knuder, v 1 og v 2. En vej er en liste af knuder, (v 1,v 2,...,v k ), hvor alle successive knuder, v i og v i+1, er indbyrdes forbundne (dvs. tilhører E). For at udgøre et træ skal der mellem roden og enhver anden knude findes præcis én vej.

57 56 Terminologi Rod: R X er far til Y Y er søn til X Y er barn af X U, V og W er børn af T S er bedstefar til Z S er forgænger til Y S er over Y Y er efterkommer af S Y er under S Terminale knuder (blade): Y, Z, U, V, W Ikke-terminale knuder: R, S, X, T Rod R S X Y Z T U VW Terminal (blad) Ikke-terminal Niveau 0 Niveau 1 Niveau 2 Niveau 3

58 57 Terminologi (fortsat) En knudes niveau er antallet af knuder på vejen fra knuden til roden (minus knuden selv). Et træs højde er det maksimale niveau for alle knuder i træet.

59 58 Terminologi (fortsat) Enhver knude i et træ er rod for et undertræ bestående af knuden selv og alle knuder under den. Et træ kaldes ordnet, hvis rækkefølgen af sønnerne for enhver knude er specificeret. En mængde af træer kaldes en skov.

60 59 For enhver knude i et træ er der præcis én vej, der fører fra roden til knuden. Et træ er sammenhængende, dvs. der er en vej fra enhver knude til enhver anden knude. Et træ har ingen cykler, dvs. enhver vej indeholder en knude højst én gang. Nyttig definition: Et tomt træ er et træ uden kanter og knuder. Egenskaber ved træer

61 60 Anvendelser af træer Repræsentation af hierarkier indholdsfortegnelse organisationsstruktur klassehierarki blokstruktur Søgning Sortering Syntaksanalyse

62 61 Binære træer Et flervejstræ er et træ, hvor hver knude har et bestemt antal sønner (eller ingen). I et flervejstræ er det ofte hensigtsmæssigt at definere specielle eksterne knuder, der ikke har nogen sønner og ikke har tilknyttet nogen information (dummy-knuder). Et binært træ er et ordnet træ bestående af to typer af knuder: interne knuder med præcis to sønner, og eksterne knuder, der er uden sønner. Rekursiv definition: Et binært træ er enten et tomt træ, eller en knude, som har et venstre og et højre binært undertræ.

63 62 Eksempel på binært træ P’s venstre søn er M P’s højre søn er L P M S A A L E R E E T

64 63 Fulde binære træer Et fuldt binært træ er et binært træ, hvor de interne knuder fuldstændigt udfylder ethvert niveau, eventuelt med undtagelse af det sidste. Højden af et fuldt binært træ med N knuder er cirka log 2 N. Faktisk lig med | log 2 N |. Udtrykt i Java: Math.ceil(log(N)/log(2))

65 64 Et komplet binært træ er et fuldt binært træ, hvor de interne knuder på det sidste niveau er til venstre for alle de eksterne knuder på dette niveau. Komplette binære træer Alternativ definition: Et komplet binært træ er et binært træ med blade på kun et eller to successive niveauer, og bladene på det nederste niveau er placeret så langt til venstre som muligt.

66 65 class Node { Node l, r; char info; } Repræsentation af binære træer * A + F * * E D + BC Eksempel på anvendelse: konstruktion af parsetræer. Parsetræ for udtrykket A * ( ( ( B + C ) * ( D * E ) ) + F) postfix: A B C + D E * * F + *

67 66 Node z = new Node(); z.l = z.r = z; Stack stack = new Stack(50); char c; while ((c = get()) != (char) (-1)) { while (c == ' ') c = get(); Node x = new Node(); x.info = c; x.l = z; x.r = z; if (c == '+' || c == '*') { x.r = stack.pop(); x.l = stack.pop(); } stack.push(x); } Et parsetræ konstrueres ved følgende rekursive regel: Læg operatoren i roden. Lad rodens venstre undertræ være parsetræet for den del af udtrykket, der svarer til venstre operand, og lad rodens højre undertræ være parsetræet for den del af udtrykket, der svarer til højre operand. Java-kode til opbygning af et parsetræ ud fra et postfix-udtryk

68 67 * + * * + A BC D E F A B C + D E * * F + * while ((c = get()) != (char) (-1)) { while (c == ' ') c = get(); Node x = new Node(); x.info = c; x.l = z; x.r = z; if (c == '+' || c == '*') { x.r = stack.pop(); x.l = stack.pop(); } stack.push(x); }

69 68 (1) Preorder (far-først): Besøg roden. Besøg venstre undertræ. Besøg højre undertræ. Gennemgang af binære træer (traversering: besøg alle knuder i et træ) P M S A A L E R E E T (2) Inorder (symmetrisk): Besøg venstre undertræ. Besøg roden. Besøg højre undertræ. (3) Postorder (far-sidst): Besøg venstre undertræ. Besøg højre undertræ. Besøg roden. PMSAALERTEE ASAMPLETREE AASMTEERELP

70 69 Preorder-traversering ved hjælp af eksplicit stak void traverse(Node t) { stack.push(t); while (!stack.empty()) { t = stack.pop(); visit(t); if (t.r != z) stack.push(t.r); if (t.l != z) stack.push(t.l); } Stakken bruges til at udsætte et “besøg” til en senere lejlighed.

71 70 Traversering i niveauorden (4) Niveauorden: Besøg knuderne efter stigende niveau, og fra venstre mod højre på hvert niveau. P M S A A L E R E E T void traverse(Node t) { queue.put(t); while (!queue.empty()) { t = queue.get(); visit(t); if (t.l != z) queue.put(t.l); if (t.r != z) queue.put(t.r); } PMLSEAARTEE

72 71 Repræsentation af flervejstræer (1) Far-referencer class Node { Node dad; } (2) Binært træ class Node { Node firstSon, nextBrother; }

73 72 Ugeseddel 2 23. september - 29. september Læs kapitel 5, 6 og 7 i lærebogen (side 51-87) Løs følgende opgaver 1. Opgave 3.2 og 3.3 (idet “ struct node *t ” i begge opgaver erstattes med “ node t ”). 2. Opgave 3.5. 3. Opgave 4.1 og 4.3. 4. Java indeholder en klasse, class Stack, der kan benyttes til at repræsentere en stak af objekter. Klassen er implementeret ved hjælp af Java-klassen Vector. Derimod findes der i Javas klassebiblioteker ingen klasse til repræsentation af køer. (a) Implementer ved hjælp af class Vector en klasse, Queue, til repræsentation af køer. (b) Angiv hvilke af de implementerede metoder i Queue, der er konstant i tid, og hvilke der har en udførelsestid, der afhænger af den aktuelle kølængde. Se her bort fra eventuelt tidsforbrug til ekspansion af den anvendte vektor.

74 73 Reasoning About Programs E. W. Dijkstra Video vises i biografen torsdag den 30. september Start: 14 45 Varighed: cirka 40 minutter


Download ppt "1 Fundamentale datastrukturer 2 * Definitioner: abstrakt datatype, datastruktur *Elementære datastrukturer og abstrakte datatyper: arrays, hægtede lister,"

Lignende præsentationer


Annoncer fra Google