;;; Konstruktion, Vorlesung vom 16.11. und 21.11.2000 ;;; K7 Rekursive Datenstrukturen ;;; K7.2 Bäume ; Ein "btree" ist entweder ; 1. empty ; oder ; 2. (make-branch l x r) ; mit l, r : btree und x : scheme-value ; definiert durch [ auch Knoten des Baums ] ; (define-struct branch (left elem right)) ; Elemente von btree heissen "Binärbäume mit Marken" (define t0 empty) (define t1 (make-branch empty 5 empty)) (define t2 (make-branch t1 6 (make-branch empty 10 empty))) (define t3 (make-branch t2 12 (make-branch empty 20 empty))) ; SIGNATUR ; btree-size : btree -> number ; ERKLÄRUNG ; bestimmt die Anzahl der Knoten (make-branch ...) im Baum ; BEISPIEL ; (btree-size empty) == 0 ; (btree-size (make-branch (make-branch empty 1 empty) 0 empty)) == 2 ; MUSTER (define btree-size (lambda (t) (cond ((empty? t) ...) ((branch? t) (... (btree-size (branch-left t)) ... (branch-elem t) ... ... (btree-size (branch-right t)) ...))))) ; DEFINITION (define btree-size (lambda (t) (cond ((empty? t) 0) ((branch? t) (+ 1 (btree-size (branch-left t)) (btree-size (branch-right t))))))) ; btree-size ist POLYMORPH im Typ der Datenelemente im Baum. ; SIGNATUR ; btree-add : btree(number) number -> btree(number) ; ERKLÄRUNG ; (btree-add t x) addiert x zu jedem Element von t ; BEISPIEL ; (btree-add (make-branch (make-branch empty 1 empty) 0 empty) 41) ; == (make-branch (make-branch empty 42 empty) 41 empty) ; MUSTER (define btree-add (lambda (t x) (cond ((empty? t) ...) ((branch? t) (... (btree-add (branch-left t) x) ... (branch-elem t) ... (btree-add (branch-right t) x) ...))))) ; DEFINITION (define btree-add (lambda (t x) (cond ((empty? t) empty) ((branch? t) (make-branch (btree-add (branch-left t) x) (+ (branch-elem t) x) (btree-add (branch-right t) x)))))) ; SIGNATUR ; btree-inorder : btree -> list ; ERKLÄRUNG ; liefert die Liste der Elemente des Baums von links nach rechts ; BEISPIEL ; (btree-inorder empty) == empty ; (btree-inorder (make-branch (make-branch empty 1 empty) 0 empty)) ; == (list 1 0) ; (btree-inorder (make-branch (make-branch empty 5 (make-branch empty 10 empty)) ; 11 empty)) ; == (list 5 10 11) ; MUSTER (define btree-inorder (lambda (t) (cond ((empty? t) ...) ((branch? t) (... (btree-inorder (branch-left t)) ... (branch-elem t) ... ... (btree-inorder (branch-right t)) ...))))) ; DEFINITION (define btree-inorder (lambda (t) (cond ((empty? t) empty) ((branch? t) (append (btree-inorder (branch-left t)) (cons (branch-elem t) (btree-inorder (branch-right t)))))))) ; K7.2.1 Es gilt für alle t : btree, für alle x : number, ; (*) (list-add (btree-inorder t) x) ; == (btree-inorder (btree-add t x)) ; Beweis: Induktion über die Definition von "btree" ;;; 1. Induktionsanfang ;;; (*) gilt für empty ; (list-add (btree-inorder empty) x) ; == (list-add empty x) ; == empty ; == (btree-inorder empty) ; == (btree-inorder (btree-add empty x)) ;;; 2. Induktionsschritt ;;; Falls (*) gilt für l und r, ;;; dann gilt (*) für (make-branch l y r), für alle y ; (list-add (btree-inorder (make-branch l y r)) x) ; == (list-add (list-append (btree-inorder l) (cons y (btree-inorder r))) x) ; { siehe Lemma } ; == (list-append (list-add (btree-inorder l) x) ; (list-add (cons y (btree-inorder r)) x)) ; == (list-append (list-add (btree-inorder l) x) ; (cons (+ y x) (list-add (btree-inorder r) x))) ; { nach Induktionsvoraussetzung für l und r } ; == (list-append (btree-inorder (btree-add l x)) ; (cons (+ y x) (btree-inorder (btree-add r x)))) ; == (btree-inorder (make-branch (btree-add l x) (+ y x) (btree-add r x)) ; == (btree-inorder (btree-add (make-branch l y r) x)) ; SIGNATUR ; btree-min, btree-max : btree(number) -> number* ; ERKLÄRUNG ; liefert das minimale (maximale) Element aus einem Binärbaum ; MUSTER (define btree-min/max (lambda (t) (cond ((empty? t) ...) ((branch? t) (... (btree-min/max (branch-left t)) ... (branch-elem t) ... (btree-min/max (branch-right t)) ...))))) ; DEFINITION (define btree-min (lambda (t) (cond ((empty? t) #t) ((branch? t) (number*-min (btree-min (branch-left t)) (number*-min (branch-elem t) (btree-min (branch-right t)))))))) ; DEFINITION (define btree-max (lambda (t) (cond ((empty? t) #f) ((branch? t) (number*-max (btree-max (branch-left t)) (number*-max (branch-elem t) (btree-max (branch-right t)))))))) ; DEFINITION ; t : btree(number) ist "binärer Suchbaum", falls ; für jeden Knoten (make-branch l y r) in t gilt: ; - für alle Knoten (make-branch _ x _) in l gilt: x < y ; - für alle Knoten (make-branch _ z _) in r gilt: y < z ; BEISPIEL ; t0, t1, t2, t3 sind binäre Suchbäume (define t4 (make-branch (make-branch empty 42 empty) 57 (make-branch empty 50 empty))) ; t4 ist kein binärer Suchbaum ; SIGNATUR ; is-searchtree : btree(number) -> boolean ; ERKLÄRUNG ; (is-searchtree t) liefert #t, falls t ein binärer Suchbaum ist ; BEISPIEL ; (is-searchtree t2) == #t ; (is-searchtree t3) == #t ; (is-searchtree t4) == #f ; MUSTER (define is-searchtree (lambda (t) (cond ((empty? t) ...) ((branch? t) (... (is-searchtree (branch-left t)) ... (branch-elem t) ... (is-searchtree (branch-right t)) ...))))) ; DEFINITION (define is-searchtree (lambda (t) (cond ((empty? t) #t) ((branch? t) (let ((left (branch-left t)) (right (branch-right t)) (elem (branch-elem t))) (and (is-searchtree left) (is-searchtree right) (number*-less (btree-max left) elem) (number*-less elem (btree-min right)))))))) ; SIGNATUR ; btree-member : number btree(number) -> boolean ; ERKLÄRUNG ; (btree x t) == #t gdw x kommt in t vor ; VORBEDINGUNG: t ist binärer Suchbaum ; BEISPIEL ; (btree-member x empty) == #f ; (btree-member 5 (make-branch (make-branch empty 5 empty) 10 empty)) == #t ; (btree-member 5 (make-branch empty 2 empty)) == #f ; MUSTER (define btree-member (lambda (x t) (cond ((empty? t) ...) ((branch? t) (... (btree-member x (branch-left t)) ... (branch-elem t) ... (btree-member x (branch-left t)) ...))))) ; DEFINITION (define btree-member (lambda (x t) (cond ((empty? t) #f) ((branch? t) (let ((y (branch-elem t))) (cond ((= x y) #t) ((< x y) (btree-member x (branch-left t))) ((> x y) (btree-member x (branch-right t))))))))) ; SIGNATUR ; btree-insert : number btree(number) -> btree(number) ; ERKLÄRUNG ; Falls t ein binärer Suchbaum ist, so erzeugt ; t' = (btree-insert x t) einen binären Suchbaum, so dass ; (btree-member x t') gilt. ; VORBEDINGUNG: t binärer Suchbaum ; NACHBEDINGUNG: ; * (btree-member x (btree-insert x t)) ; * (btree-insert x t) ist binärer Suchbaum ; BEISPIEL ; (btree-insert x empty) '== (make-branch empty x empty) ; (btree-insert 10 (make-branch (make-branch empty 5 empty) 11 empty)) ; == ; (make-branch (make-branch empty 5 (make-branch empty 10 empty)) 11 empty) ; MUSTER (define btree-insert (lambda (x t) (cond ((empty? t) ...) ((branch? t) (... (branch-elem t) ... (btree-insert x (branch-left t)) ... (btree-insert x (branch-right t)) ...))))) ; DEFINITION (define btree-insert (lambda (x t) (cond ((empty? t) (make-branch empty x empty)) ((branch? t) (let ((y (branch-elem t)) (left (branch-left t)) (right (branch-right t))) (cond ((< x y) (make-branch (btree-insert x left) y right)) ((> x y) (make-branch left y (btree-insert x right))) (else t))))))) ; DEFINITION (Erweiterung von Def K1) ; Der Wert von (cond (b1 e1) ... (bn en) (else e)) wird ermittelt, ; indem zuerst der Wert v1 von b1 ermittelt wird. ; Falls v1 = #t, dann ist der Wert von e1 das Ergebnis. ; Falls v1 = #f, dann ist der Wert von (cond (b2 e2) ... (bn en) (else e)) ; das Ergebnis. ; Der Wert von (cond (else e)) ist der Wert von e. ;;; Gilt die NACHBEDINGUNG? ; dh. gilt für alle t : btree(number) ; (*) t binärer Suchbaum => (btree-member x (btree-insert x t)) ? ; (**) t binärer Suchbaum => (btree-insert x t) binärer Suchbaum ? ; Beweis durch Induktion über die Definition von "btree" ; unter Verwendung der Suchbaum-Eigenschaft ; (nur (*); (**) Übung oder selbst) ; ; 1. Induktionsanfang ; (*) gilt für t == empty ; (btree-member x (btree-insert x empty)) ; == (btree-member x (make-branch empty x empty)) ; == #t ; 2. Induktionsschritt ; Falls (*) gilt für l ; und (*) gilt für r ; und (btree-max l) < y < (btree-min r) ; ==> (*) gilt für (make-branch l y r) ; (btree-member x (btree-insert x (make-branch l y r))) ; == (btree-member ; x ; (cond ; ((empty? (make-branch l y r)) ; (make-branch empty x empty)) ; ((branch? (make-branch l y r)) ; (let ((y (branch-elem (make-branch l y r))) ; (left (branch-left (make-branch l y r))) ; (right (branch-right (make-branch l y r)))) ; (cond ; ((< x y) (make-branch (btree-insert x left) y right)) ; ((> x y) (make-branch left y (btree-insert x right))) ; (else (make-branch l y r))))))) ; == (btree-member ; x ; (let ((y (branch-elem (make-branch l y r))) ; (left (branch-left (make-branch l y r))) ; (right (branch-right (make-branch l y r)))) ; (cond ; ((< x y) (make-branch (btree-insert x left) y right)) ; ((> x y) (make-branch left y (btree-insert x right))) ; (else (make-branch l y r))))) ; == (btree-member ; x ; (cond ; ((< x y) (make-branch (btree-insert x l) y r)) ; ((> x y) (make-branch l y (btree-insert x r))) ; (else (make-branch l y r)))) ;;; 2.1 Falls (< x y) ; (btree-member ; x ; (cond ; ((< x y) (make-branch (btree-insert x l) y r)) ; ((> x y) (make-branch l y (btree-insert x r))) ; (else (make-branch l y r)))) ; == (btree-member x (make-branch (btree-insert x l) y r)) ; { wegen (< x y) } ; == (btree-member x (btree-insert x l)) ; { nach Induktionsvoraussetzung } ; == #t ;;; 2.2 Falls (> x y) ; (btree-member ; x ; (cond ; ((< x y) (make-branch (btree-insert x l) y r)) ; ((> x y) (make-branch l y (btree-insert x r))) ; (else (make-branch l y r)))) ; == (btree-member x (make-branch l y (btree-insert x r))) ; { wegen (> x y) } ; == (btree-member x (btree-insert x r)) ; { nach Induktionsvoraussetzung } ; == #t ;;; 2.3 Falls (= x y) ; (btree-member ; x ; (cond ; ((< x y) (make-branch (btree-insert x l) y r)) ; ((> x y) (make-branch l y (btree-insert x r))) ; (else (make-branch l y r)))) ; == (btree-member x (make-branch l y r)) ; { nach Definition von btree-member } ; == #t ;;; Anwendung: Sortieren einer Liste ; SIGNATUR ; tree-sort : list(number) -> list(number) ; ERKLÄRUNG ; Falls l keine Duplikate enthält, so liefert (tree-sort l) ; eine aufsteigend sortierte Liste mit den gleichen Elementen wie l. ; Vorgehensweise: konstruiere Suchbaum aus l, dann Inorder-Durchlauf. ; DEFINITION (define tree-sort (lambda (l) (btree-inorder (btree-build l)))) ; SIGNATUR ; btree-build : list(number) -> btree(number) ; ERKLÄRUNG ; Falls l keine Duplikate enthält, so liefert (btree-build l) einen ; binären Suchbaum mit den gleichen Elementen wie l. ; BEISPIEL ; (btree-build empty) == empty ; (btree-build (list 5)) == (make-branch empty 5 empty) ; (btree-build (list 5 10 6 20 12)) == t1 ; DEFINITION (define btree-build (lambda (l) (cond ((empty? l) empty) ((cons? l) (btree-insert (first l) (btree-build (rest l))))))) ; SIGNATUR ; btree-build2 : list(number) btree(number) -> btree(number) ; ERKLÄRUNG ; Iterative Variante von btree-build. (btree-build2 l t) liefert binären Suchbaum ; aus den Elementen von l und t. ; MUSTER (define btree-build2 (lambda (l t) (cond ((empty? l) (... t ...)) ((cons? l) (btree-build2 (rest l) (... (first l) ... t ...)))))) ; DEFINITION (define btree-build2 (lambda (l t) (cond ((empty? l) t) ((cons? l) (btree-build2 (rest l) (btree-insert (first l) t)))))) ; tree-sort unter Verwendung von btree-build2: (define tree-sort2 (lambda (l) (btree-inorder (btree-build2 l empty))))