Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Huffman Encoding in Racket #823

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions contents/huffman_encoding/code/racket/huffman.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#lang racket

(require data/heap)

(struct branch (freq left right))
(struct leaf (sym freq))

(define (weight node)
(if (branch? node)
(branch-freq node)
(leaf-freq node)))

(define (make-huffman-tree leaves)
(define (combine x y)
(branch (+ (weight x) (weight y)) x y))

(define hp (make-heap
(lambda (x y)
(<= (weight x) (weight y)))))

(heap-add-all! hp leaves)

(define (merge)
(if (= (heap-count hp) 1)
;; if there's only one node in the heap then return that element
(heap-min hp)

;; else merge the two smallest nodes
(let ((a (heap-min hp)))
;; get the smallest node and remove it
(heap-remove-min! hp)

(let ((b (heap-min hp)))
;; get the second smallest node and remove it
(heap-remove-min! hp)

;; add the combined node to the heap
(heap-add! hp (combine a b))
(merge)))))
(merge))

(define (make-codebook tree)
(define ht (make-hash))

(define (dfs node path)
(if (leaf? node)
;; if node is a leaf then add the symbol to the codebook
(hash-set! ht (leaf-sym node) path)
(begin (dfs (branch-left node) (append path (list 0)))
(dfs (branch-right node) (append path (list 1))))))

(dfs tree null)
ht)

(define (encode codebook msg)
(if (null? msg)
null
(append (hash-ref codebook (car msg))
(encode codebook (cdr msg)))))

(define (decode tree msg)
(define (dfs node bits)
(if (leaf? node)
(cons (leaf-sym node) (decode tree bits))
(if (= (car bits) 0)
(dfs (branch-left node) (cdr bits))
(dfs (branch-right node) (cdr bits)))))

(if (null? msg)
null
(dfs tree msg)))

(define (generate-leaves msg)
(define ht (make-hash))
(for ([ch msg])
(hash-update! ht ch add1 (lambda () 0)))
(for/list ([(k v) (in-hash ht)])
(leaf k v)))

;; test
(define message (string->list "bibbity bobbity"))
(define leaves (generate-leaves message))
(define huffman-tree (make-huffman-tree leaves))
(define codebook (make-codebook huffman-tree))

(define encoded (encode codebook message))
(define decoded (list->string (decode huffman-tree encoded)))

(println encoded)
(println decoded)
2 changes: 2 additions & 0 deletions contents/huffman_encoding/huffman_encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ Whether you use a stack or straight-up recursion also depends on the language, b
[import, lang:"asm-x64"](code/asm-x64/huffman.s)
{% sample lang="scala" %}
[import, lang:"scala"](code/scala/huffman_encoding.scala)
{% sample lang="racket" %}
[import, lang:"lisp"](code/racket/huffman.rkt)
{% sample lang="scratch" %}
The code snippet was taken from this [scratch project](https://scratch.mit.edu/projects/389604255/)
<p>
Expand Down