exercise-2.69-huffman-trees-3.rkt 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #lang racket
  2. ; racket -l errortrace -t exercise-...
  3. (require rackunit)
  4. (define (Mb-to-B n) (* n 1024 1024))
  5. (define MAX-BYTES (Mb-to-B 64))
  6. (define nil '())
  7. (custodian-limit-memory (current-custodian) MAX-BYTES)
  8. ;; a general print function
  9. (define (printline elems #:sep [sep " "] #:end [end "\n"] #:element-converter [element-converter identity])
  10. (define (iter remaining-elements result-string)
  11. (cond
  12. [(empty? remaining-elements) (string-append result-string end)]
  13. [(empty? (rest remaining-elements))
  14. (iter (rest remaining-elements)
  15. (string-append result-string
  16. (element-converter (first remaining-elements))))]
  17. [else
  18. (iter (rest remaining-elements)
  19. (string-append result-string
  20. (element-converter (first remaining-elements))
  21. sep))]))
  22. (cond
  23. [(empty? elems) (display end)]
  24. [(not (list? elems)) (display (string-append (element-converter elems) end))]
  25. [else (display (iter elems ""))]))
  26. (provide (all-defined-out))
  27. ;; EXERCISE 2.67
  28. ;; GIVEN CODE
  29. (define (make-leaf symbol weight)
  30. (list 'leaf symbol weight))
  31. (define (leaf? object)
  32. (eq? (car object) 'leaf))
  33. (define (symbol-leaf x)
  34. (second x))
  35. (define (weight-leaf x)
  36. (third x))
  37. (define (left-branch tree)
  38. (first tree))
  39. (define (right-branch tree)
  40. (second tree))
  41. (define (symbols tree)
  42. (cond
  43. [(leaf? tree) (list (symbol-leaf tree))]
  44. [else (caddr tree)]))
  45. (define (weight tree)
  46. (cond
  47. [(leaf? tree) (weight-leaf tree)]
  48. [else (cadddr tree)]))
  49. (define (combine-subtrees left right)
  50. (list left
  51. right
  52. (append (symbols left) (symbols right))
  53. (+ (weight left) (weight right))))
  54. (define (choose-branch bit branch)
  55. (cond [(= bit 0) (left-branch branch)]
  56. [(= bit 1) (right-branch branch)]
  57. [else (error "bad bit: CHOOSE-BRANCH" bit)]))
  58. (define (decode bits tree)
  59. (define (decode-1 bits current-branch)
  60. (cond
  61. [(empty? bits) nil]
  62. [else (let ([next-branch (choose-branch (first bits) current-branch)])
  63. (cond
  64. [(leaf? next-branch) (cons (symbol-leaf next-branch)
  65. (decode-1 (rest bits) tree))]
  66. [else (decode-1 (rest bits) next-branch)]))]))
  67. (decode-1 bits tree))
  68. ;; creates a sorted list of nodes by inserting an element at the right place
  69. ;; (insertion sort like)
  70. ;; This is stable. Means that first element with a specific weight value will count as lower than the second element with the same weight value. "First means first."
  71. (define (adjoin-set x set)
  72. (cond
  73. [(empty? set) (list x)]
  74. [(< (weight x) (weight (first set))) (cons x set)]
  75. [else (cons (first set) (adjoin-set x (rest set)))]))
  76. (define (make-leaf-set pairs)
  77. (cond
  78. ;; if there are no pairs, there are no leaves ...
  79. [(empty? pairs) nil]
  80. ;; otherwise get the first pair and insert it in the ordered list
  81. ;; created from the rest of the pairs (recursively)
  82. [else (let ([pair (first pairs)])
  83. (adjoin-set (make-leaf (first pair) (second pair))
  84. (make-leaf-set (rest pairs))))]))
  85. ;; The behavior of cons is different from append.
  86. ;; append appends elements of a list to another list.
  87. ;; cons appends lists to a list of element, which results in a list of lists.
  88. ;; One would need another procedure (flatten) to get the correct result.
  89. (define (encode message tree)
  90. (define (iter message tree result)
  91. (cond
  92. [(empty? message) (reverse result)]
  93. [else (iter (rest message)
  94. tree
  95. (cons (encode-symbol (car message) tree)
  96. result))]))
  97. (flatten (iter message tree nil)))
  98. ;; This is the encode procedure from the book.
  99. ;(define (encode message tree)
  100. ; (if (null? message)
  101. ; nil
  102. ; (append (encode-symbol (first message) tree)
  103. ; (encode (rest message) tree))))
  104. (define (encode-symbol a-symbol huffman-tree)
  105. (define (encode-iter a-symbol subtree path)
  106. ;; (display "took path: ") (display path) (newline)
  107. (cond
  108. ;; If the subtree is a leaf, compare the symbols.
  109. ;; If the symbols are equal, return the path taken so far.
  110. [(leaf? subtree)
  111. ;(display "subtree is a leaf") (newline)
  112. ;(display "subtree") (display subtree) (newline)
  113. ;(display "searching: ") (display a-symbol) (newline)
  114. ;(display "symbol in leaf: ") (display (symbol-leaf subtree)) (newline)
  115. (if (eq? (symbol-leaf subtree) a-symbol)
  116. (reverse path)
  117. false)]
  118. ;; Each symbol can only be once encoded in the tree.
  119. ;; A path is unique amongst the encodings of symbols.
  120. ;; Since we return false when a leaf does not contain the symbol we searched for,
  121. ;; the or expressions will all but one return false.
  122. ;; Only for the correct path we will get a list of bits.
  123. ;; That is the list we will return.
  124. ;; However, this produces 2 procedure calls for each recursion step.
  125. ;; Evaluation is depth first so we will have height of tree elements in form of procedure calls in memory. We reach a leaf first, then one procedure's context can be taken from the stack, but we enter another branch down to a leaf again.
  126. [else
  127. (or
  128. (encode-iter a-symbol
  129. (left-branch subtree) ; need to check this
  130. (cons 0 path))
  131. (encode-iter a-symbol
  132. (right-branch subtree)
  133. (cons 1 path)))]))
  134. ;; at the beginning the whole tree and an empty list is given as a result
  135. (let
  136. ([encoded-message (encode-iter a-symbol huffman-tree nil)])
  137. (if encoded-message
  138. encoded-message
  139. (error "Symbol not found in tree." a-symbol))))
  140. ;; given in exercise 2.69
  141. (define (generate-huffman-tree ordered-pairs)
  142. (successive-merge (make-leaf-set ordered-pairs)))
  143. ;; TASK: write successive-merge
  144. ;; The procedure shall combine subtrees with the lowest frequency according to Huffman's algorithm.
  145. (define (successive-merge ordered-nodes-set)
  146. (display ordered-nodes-set) (newline)
  147. (cond
  148. ;; For an empty set of nodes, we return the empty set.
  149. [(empty? ordered-nodes-set) nil]
  150. ;; If there are less than 2 (1) elements in the set of nodes to merge, we are done.
  151. [(< (length ordered-nodes-set) 2) (first ordered-nodes-set)]
  152. ;; Otherwise merge the first two elements into a subtree, since they are the ones with lowest weight.
  153. [else
  154. (let*
  155. ([new-node (combine-subtrees (first ordered-nodes-set)
  156. (second ordered-nodes-set))]
  157. [updated-ordered-nodes-set (adjoin-set new-node
  158. (cddr ordered-nodes-set))])
  159. (successive-merge updated-ordered-nodes-set))]))