Data update
This commit is contained in:
parent
5150844a7d
commit
4bb20c9b71
7735 changed files with 38060 additions and 199180 deletions
|
|
@ -1,83 +0,0 @@
|
|||
with Ada.Containers.Indefinite_Ordered_Maps;
|
||||
with Ada.Containers.Ordered_Maps;
|
||||
with Ada.Finalization;
|
||||
generic
|
||||
type Symbol_Type is private;
|
||||
with function "<" (Left, Right : Symbol_Type) return Boolean is <>;
|
||||
with procedure Put (Item : Symbol_Type);
|
||||
type Symbol_Sequence is array (Positive range <>) of Symbol_Type;
|
||||
type Frequency_Type is private;
|
||||
with function "+" (Left, Right : Frequency_Type) return Frequency_Type
|
||||
is <>;
|
||||
with function "<" (Left, Right : Frequency_Type) return Boolean is <>;
|
||||
package Huffman is
|
||||
-- bits = booleans (true/false = 1/0)
|
||||
type Bit_Sequence is array (Positive range <>) of Boolean;
|
||||
Zero_Sequence : constant Bit_Sequence (1 .. 0) := (others => False);
|
||||
-- output the sequence
|
||||
procedure Put (Code : Bit_Sequence);
|
||||
|
||||
-- type for freqency map
|
||||
package Frequency_Maps is new Ada.Containers.Ordered_Maps
|
||||
(Element_Type => Frequency_Type,
|
||||
Key_Type => Symbol_Type);
|
||||
|
||||
type Huffman_Tree is private;
|
||||
-- create a huffman tree from frequency map
|
||||
procedure Create_Tree
|
||||
(Tree : out Huffman_Tree;
|
||||
Frequencies : Frequency_Maps.Map);
|
||||
-- encode a single symbol
|
||||
function Encode
|
||||
(Tree : Huffman_Tree;
|
||||
Symbol : Symbol_Type)
|
||||
return Bit_Sequence;
|
||||
-- encode a symbol sequence
|
||||
function Encode
|
||||
(Tree : Huffman_Tree;
|
||||
Symbols : Symbol_Sequence)
|
||||
return Bit_Sequence;
|
||||
-- decode a bit sequence
|
||||
function Decode
|
||||
(Tree : Huffman_Tree;
|
||||
Code : Bit_Sequence)
|
||||
return Symbol_Sequence;
|
||||
-- dump the encoding table
|
||||
procedure Dump_Encoding (Tree : Huffman_Tree);
|
||||
private
|
||||
-- type for encoding map
|
||||
package Encoding_Maps is new Ada.Containers.Indefinite_Ordered_Maps
|
||||
(Element_Type => Bit_Sequence,
|
||||
Key_Type => Symbol_Type);
|
||||
|
||||
type Huffman_Node;
|
||||
type Node_Access is access Huffman_Node;
|
||||
-- a node is either internal (left_child/right_child used)
|
||||
-- or a leaf (left_child/right_child are null)
|
||||
type Huffman_Node is record
|
||||
Frequency : Frequency_Type;
|
||||
Left_Child : Node_Access := null;
|
||||
Right_Child : Node_Access := null;
|
||||
Symbol : Symbol_Type;
|
||||
end record;
|
||||
-- create a leaf node
|
||||
function Create_Node
|
||||
(Symbol : Symbol_Type;
|
||||
Frequency : Frequency_Type)
|
||||
return Node_Access;
|
||||
-- create an internal node
|
||||
function Create_Node (Left, Right : Node_Access) return Node_Access;
|
||||
-- fill the encoding map
|
||||
procedure Fill
|
||||
(The_Node : Node_Access;
|
||||
Map : in out Encoding_Maps.Map;
|
||||
Prefix : Bit_Sequence);
|
||||
|
||||
-- huffman tree has a tree and an encoding map
|
||||
type Huffman_Tree is new Ada.Finalization.Controlled with record
|
||||
Tree : Node_Access := null;
|
||||
Map : Encoding_Maps.Map := Encoding_Maps.Empty_Map;
|
||||
end record;
|
||||
-- free memory after finalization
|
||||
overriding procedure Finalize (Object : in out Huffman_Tree);
|
||||
end Huffman;
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
with Ada.Text_IO;
|
||||
with Ada.Unchecked_Deallocation;
|
||||
with Ada.Containers.Vectors;
|
||||
package body Huffman is
|
||||
package Node_Vectors is new Ada.Containers.Vectors
|
||||
(Element_Type => Node_Access,
|
||||
Index_Type => Positive);
|
||||
|
||||
function "<" (Left, Right : Node_Access) return Boolean is
|
||||
begin
|
||||
-- compare frequency
|
||||
if Left.Frequency < Right.Frequency then
|
||||
return True;
|
||||
elsif Right.Frequency < Left.Frequency then
|
||||
return False;
|
||||
end if;
|
||||
-- same frequency, choose leaf node
|
||||
if Left.Left_Child = null and then Right.Left_Child /= null then
|
||||
return True;
|
||||
elsif Left.Left_Child /= null and then Right.Left_Child = null then
|
||||
return False;
|
||||
end if;
|
||||
-- same frequency, same node type (internal/leaf)
|
||||
if Left.Left_Child /= null then
|
||||
-- for internal nodes, compare left children, then right children
|
||||
if Left.Left_Child < Right.Left_Child then
|
||||
return True;
|
||||
elsif Right.Left_Child < Left.Left_Child then
|
||||
return False;
|
||||
else
|
||||
return Left.Right_Child < Right.Right_Child;
|
||||
end if;
|
||||
else
|
||||
-- for leaf nodes, compare symbol
|
||||
return Left.Symbol < Right.Symbol;
|
||||
end if;
|
||||
end "<";
|
||||
package Node_Vector_Sort is new Node_Vectors.Generic_Sorting;
|
||||
|
||||
procedure Create_Tree
|
||||
(Tree : out Huffman_Tree;
|
||||
Frequencies : Frequency_Maps.Map) is
|
||||
Node_Queue : Node_Vectors.Vector := Node_Vectors.Empty_Vector;
|
||||
begin
|
||||
-- insert all leafs into the queue
|
||||
declare
|
||||
use Frequency_Maps;
|
||||
Position : Cursor := Frequencies.First;
|
||||
The_Node : Node_Access := null;
|
||||
begin
|
||||
while Position /= No_Element loop
|
||||
The_Node :=
|
||||
Create_Node
|
||||
(Symbol => Key (Position),
|
||||
Frequency => Element (Position));
|
||||
Node_Queue.Append (The_Node);
|
||||
Next (Position);
|
||||
end loop;
|
||||
end;
|
||||
-- sort by frequency (see "<")
|
||||
Node_Vector_Sort.Sort (Node_Queue);
|
||||
-- iterate over all elements
|
||||
while not Node_Queue.Is_Empty loop
|
||||
declare
|
||||
First : constant Node_Access := Node_Queue.First_Element;
|
||||
begin
|
||||
Node_Queue.Delete_First;
|
||||
-- if we only have one node left, it is the root node of the tree
|
||||
if Node_Queue.Is_Empty then
|
||||
Tree.Tree := First;
|
||||
else
|
||||
-- create new internal node with two smallest frequencies
|
||||
declare
|
||||
Second : constant Node_Access := Node_Queue.First_Element;
|
||||
begin
|
||||
Node_Queue.Delete_First;
|
||||
Node_Queue.Append (Create_Node (First, Second));
|
||||
end;
|
||||
Node_Vector_Sort.Sort (Node_Queue);
|
||||
end if;
|
||||
end;
|
||||
end loop;
|
||||
-- fill encoding map
|
||||
Fill (The_Node => Tree.Tree, Map => Tree.Map, Prefix => Zero_Sequence);
|
||||
end Create_Tree;
|
||||
|
||||
-- create leaf node
|
||||
function Create_Node
|
||||
(Symbol : Symbol_Type;
|
||||
Frequency : Frequency_Type)
|
||||
return Node_Access
|
||||
is
|
||||
Result : Node_Access := new Huffman_Node;
|
||||
begin
|
||||
Result.Frequency := Frequency;
|
||||
Result.Symbol := Symbol;
|
||||
return Result;
|
||||
end Create_Node;
|
||||
|
||||
-- create internal node
|
||||
function Create_Node (Left, Right : Node_Access) return Node_Access is
|
||||
Result : Node_Access := new Huffman_Node;
|
||||
begin
|
||||
Result.Frequency := Left.Frequency + Right.Frequency;
|
||||
Result.Left_Child := Left;
|
||||
Result.Right_Child := Right;
|
||||
return Result;
|
||||
end Create_Node;
|
||||
|
||||
-- fill encoding map
|
||||
procedure Fill
|
||||
(The_Node : Node_Access;
|
||||
Map : in out Encoding_Maps.Map;
|
||||
Prefix : Bit_Sequence) is
|
||||
begin
|
||||
if The_Node.Left_Child /= null then
|
||||
-- append false (0) for left child
|
||||
Fill (The_Node.Left_Child, Map, Prefix & False);
|
||||
-- append true (1) for right child
|
||||
Fill (The_Node.Right_Child, Map, Prefix & True);
|
||||
else
|
||||
-- leaf node reached, prefix = code for symbol
|
||||
Map.Insert (The_Node.Symbol, Prefix);
|
||||
end if;
|
||||
end Fill;
|
||||
|
||||
-- free memory after finalization
|
||||
overriding procedure Finalize (Object : in out Huffman_Tree) is
|
||||
procedure Free is new Ada.Unchecked_Deallocation
|
||||
(Name => Node_Access,
|
||||
Object => Huffman_Node);
|
||||
-- recursively free all nodes
|
||||
procedure Recursive_Free (The_Node : in out Node_Access) is
|
||||
begin
|
||||
-- free node if it is a leaf
|
||||
if The_Node.Left_Child = null then
|
||||
Free (The_Node);
|
||||
else
|
||||
-- free left and right child if node is internal
|
||||
Recursive_Free (The_Node.Left_Child);
|
||||
Recursive_Free (The_Node.Right_Child);
|
||||
-- free node afterwards
|
||||
Free (The_Node);
|
||||
end if;
|
||||
end Recursive_Free;
|
||||
begin
|
||||
-- recursively free root node
|
||||
Recursive_Free (Object.Tree);
|
||||
end Finalize;
|
||||
|
||||
-- encode single symbol
|
||||
function Encode
|
||||
(Tree : Huffman_Tree;
|
||||
Symbol : Symbol_Type)
|
||||
return Bit_Sequence
|
||||
is
|
||||
begin
|
||||
-- simply lookup in map
|
||||
return Tree.Map.Element (Symbol);
|
||||
end Encode;
|
||||
|
||||
-- encode symbol sequence
|
||||
function Encode
|
||||
(Tree : Huffman_Tree;
|
||||
Symbols : Symbol_Sequence)
|
||||
return Bit_Sequence
|
||||
is
|
||||
begin
|
||||
-- only one element
|
||||
if Symbols'Length = 1 then
|
||||
-- see above
|
||||
return Encode (Tree, Symbols (Symbols'First));
|
||||
else
|
||||
-- encode first element, append result of recursive call
|
||||
return Encode (Tree, Symbols (Symbols'First)) &
|
||||
Encode (Tree, Symbols (Symbols'First + 1 .. Symbols'Last));
|
||||
end if;
|
||||
end Encode;
|
||||
|
||||
-- decode a bit sequence
|
||||
function Decode
|
||||
(Tree : Huffman_Tree;
|
||||
Code : Bit_Sequence)
|
||||
return Symbol_Sequence
|
||||
is
|
||||
-- maximum length = code length
|
||||
Result : Symbol_Sequence (1 .. Code'Length);
|
||||
-- last used index of result
|
||||
Last : Natural := 0;
|
||||
The_Node : Node_Access := Tree.Tree;
|
||||
begin
|
||||
-- iterate over the code
|
||||
for I in Code'Range loop
|
||||
-- if current element is true, descent the right branch
|
||||
if Code (I) then
|
||||
The_Node := The_Node.Right_Child;
|
||||
else
|
||||
-- false: descend left branch
|
||||
The_Node := The_Node.Left_Child;
|
||||
end if;
|
||||
if The_Node.Left_Child = null then
|
||||
-- reached leaf node: append symbol to result
|
||||
Last := Last + 1;
|
||||
Result (Last) := The_Node.Symbol;
|
||||
-- reset current node to root
|
||||
The_Node := Tree.Tree;
|
||||
end if;
|
||||
end loop;
|
||||
-- return subset of result array
|
||||
return Result (1 .. Last);
|
||||
end Decode;
|
||||
|
||||
-- output a bit sequence
|
||||
procedure Put (Code : Bit_Sequence) is
|
||||
package Int_IO is new Ada.Text_IO.Integer_IO (Integer);
|
||||
begin
|
||||
for I in Code'Range loop
|
||||
if Code (I) then
|
||||
-- true = 1
|
||||
Int_IO.Put (1, 0);
|
||||
else
|
||||
-- false = 0
|
||||
Int_IO.Put (0, 0);
|
||||
end if;
|
||||
end loop;
|
||||
Ada.Text_IO.New_Line;
|
||||
end Put;
|
||||
|
||||
-- dump encoding map
|
||||
procedure Dump_Encoding (Tree : Huffman_Tree) is
|
||||
use type Encoding_Maps.Cursor;
|
||||
Position : Encoding_Maps.Cursor := Tree.Map.First;
|
||||
begin
|
||||
-- iterate map
|
||||
while Position /= Encoding_Maps.No_Element loop
|
||||
-- key
|
||||
Put (Encoding_Maps.Key (Position));
|
||||
Ada.Text_IO.Put (" = ");
|
||||
-- code
|
||||
Put (Encoding_Maps.Element (Position));
|
||||
Encoding_Maps.Next (Position);
|
||||
end loop;
|
||||
end Dump_Encoding;
|
||||
end Huffman;
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
with Ada.Text_IO;
|
||||
with Huffman;
|
||||
procedure Main is
|
||||
package Char_Natural_Huffman_Tree is new Huffman
|
||||
(Symbol_Type => Character,
|
||||
Put => Ada.Text_IO.Put,
|
||||
Symbol_Sequence => String,
|
||||
Frequency_Type => Natural);
|
||||
Tree : Char_Natural_Huffman_Tree.Huffman_Tree;
|
||||
Frequencies : Char_Natural_Huffman_Tree.Frequency_Maps.Map;
|
||||
Input_String : constant String :=
|
||||
"this is an example for huffman encoding";
|
||||
begin
|
||||
-- build frequency map
|
||||
for I in Input_String'Range loop
|
||||
declare
|
||||
use Char_Natural_Huffman_Tree.Frequency_Maps;
|
||||
Position : constant Cursor := Frequencies.Find (Input_String (I));
|
||||
begin
|
||||
if Position = No_Element then
|
||||
Frequencies.Insert (Key => Input_String (I), New_Item => 1);
|
||||
else
|
||||
Frequencies.Replace_Element
|
||||
(Position => Position,
|
||||
New_Item => Element (Position) + 1);
|
||||
end if;
|
||||
end;
|
||||
end loop;
|
||||
|
||||
-- create huffman tree
|
||||
Char_Natural_Huffman_Tree.Create_Tree
|
||||
(Tree => Tree,
|
||||
Frequencies => Frequencies);
|
||||
|
||||
-- dump encodings
|
||||
Char_Natural_Huffman_Tree.Dump_Encoding (Tree => Tree);
|
||||
|
||||
-- encode example string
|
||||
declare
|
||||
Code : constant Char_Natural_Huffman_Tree.Bit_Sequence :=
|
||||
Char_Natural_Huffman_Tree.Encode
|
||||
(Tree => Tree,
|
||||
Symbols => Input_String);
|
||||
begin
|
||||
Char_Natural_Huffman_Tree.Put (Code);
|
||||
Ada.Text_IO.Put_Line
|
||||
(Char_Natural_Huffman_Tree.Decode (Tree => Tree, Code => Code));
|
||||
end;
|
||||
end Main;
|
||||
|
|
@ -35,7 +35,7 @@ static void _heap_destroy(heap_t *heap)
|
|||
free(heap);
|
||||
}
|
||||
|
||||
#define swap_(I,J) do { int t_; t_ = a[(I)]; \
|
||||
#define swap_(I,J) do { int t_; t_ = a[(I)]; \
|
||||
a[(I)] = a[(J)]; a[(J)] = t_; } while(0)
|
||||
static void _heap_sort(heap_t *heap)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
#include <string.h>
|
||||
|
||||
typedef struct node_t {
|
||||
struct node_t *left, *right;
|
||||
int freq;
|
||||
char c;
|
||||
struct node_t *left, *right;
|
||||
int freq;
|
||||
char c;
|
||||
} *node;
|
||||
|
||||
struct node_t pool[256] = {{0}};
|
||||
|
|
@ -14,110 +14,110 @@ char *code[128] = {0}, buf[1024];
|
|||
|
||||
node new_node(int freq, char c, node a, node b)
|
||||
{
|
||||
node n = pool + n_nodes++;
|
||||
if (freq) n->c = c, n->freq = freq;
|
||||
else {
|
||||
n->left = a, n->right = b;
|
||||
n->freq = a->freq + b->freq;
|
||||
}
|
||||
return n;
|
||||
node n = pool + n_nodes++;
|
||||
if (freq) n->c = c, n->freq = freq;
|
||||
else {
|
||||
n->left = a, n->right = b;
|
||||
n->freq = a->freq + b->freq;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* priority queue */
|
||||
void qinsert(node n)
|
||||
{
|
||||
int j, i = qend++;
|
||||
while ((j = i / 2)) {
|
||||
if (q[j]->freq <= n->freq) break;
|
||||
q[i] = q[j], i = j;
|
||||
}
|
||||
q[i] = n;
|
||||
int j, i = qend++;
|
||||
while ((j = i / 2)) {
|
||||
if (q[j]->freq <= n->freq) break;
|
||||
q[i] = q[j], i = j;
|
||||
}
|
||||
q[i] = n;
|
||||
}
|
||||
|
||||
node qremove()
|
||||
{
|
||||
int i, l;
|
||||
node n = q[i = 1];
|
||||
int i, l;
|
||||
node n = q[i = 1];
|
||||
|
||||
if (qend < 2) return 0;
|
||||
qend--;
|
||||
while ((l = i * 2) < qend) {
|
||||
if (l + 1 < qend && q[l + 1]->freq < q[l]->freq) l++;
|
||||
q[i] = q[l], i = l;
|
||||
}
|
||||
q[i] = q[qend];
|
||||
return n;
|
||||
if (qend < 2) return 0;
|
||||
qend--;
|
||||
while ((l = i * 2) < qend) {
|
||||
if (l + 1 < qend && q[l + 1]->freq < q[l]->freq) l++;
|
||||
q[i] = q[l], i = l;
|
||||
}
|
||||
q[i] = q[qend];
|
||||
return n;
|
||||
}
|
||||
|
||||
/* walk the tree and put 0s and 1s */
|
||||
void build_code(node n, char *s, int len)
|
||||
{
|
||||
static char *out = buf;
|
||||
if (n->c) {
|
||||
s[len] = 0;
|
||||
strcpy(out, s);
|
||||
code[n->c] = out;
|
||||
out += len + 1;
|
||||
return;
|
||||
}
|
||||
static char *out = buf;
|
||||
if (n->c) {
|
||||
s[len] = 0;
|
||||
strcpy(out, s);
|
||||
code[n->c] = out;
|
||||
out += len + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
s[len] = '0'; build_code(n->left, s, len + 1);
|
||||
s[len] = '1'; build_code(n->right, s, len + 1);
|
||||
s[len] = '0'; build_code(n->left, s, len + 1);
|
||||
s[len] = '1'; build_code(n->right, s, len + 1);
|
||||
}
|
||||
|
||||
void init(const char *s)
|
||||
{
|
||||
int i, freq[128] = {0};
|
||||
char c[16];
|
||||
int i, freq[128] = {0};
|
||||
char c[16];
|
||||
|
||||
while (*s) freq[(int)*s++]++;
|
||||
while (*s) freq[(int)*s++]++;
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
if (freq[i]) qinsert(new_node(freq[i], i, 0, 0));
|
||||
for (i = 0; i < 128; i++)
|
||||
if (freq[i]) qinsert(new_node(freq[i], i, 0, 0));
|
||||
|
||||
while (qend > 2)
|
||||
qinsert(new_node(0, 0, qremove(), qremove()));
|
||||
while (qend > 2)
|
||||
qinsert(new_node(0, 0, qremove(), qremove()));
|
||||
|
||||
build_code(q[1], c, 0);
|
||||
build_code(q[1], c, 0);
|
||||
}
|
||||
|
||||
void encode(const char *s, char *out)
|
||||
{
|
||||
while (*s) {
|
||||
strcpy(out, code[*s]);
|
||||
out += strlen(code[*s++]);
|
||||
}
|
||||
while (*s) {
|
||||
strcpy(out, code[*s]);
|
||||
out += strlen(code[*s++]);
|
||||
}
|
||||
}
|
||||
|
||||
void decode(const char *s, node t)
|
||||
{
|
||||
node n = t;
|
||||
while (*s) {
|
||||
if (*s++ == '0') n = n->left;
|
||||
else n = n->right;
|
||||
node n = t;
|
||||
while (*s) {
|
||||
if (*s++ == '0') n = n->left;
|
||||
else n = n->right;
|
||||
|
||||
if (n->c) putchar(n->c), n = t;
|
||||
}
|
||||
if (n->c) putchar(n->c), n = t;
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
if (t != n) printf("garbage input\n");
|
||||
putchar('\n');
|
||||
if (t != n) printf("garbage input\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
const char *str = "this is an example for huffman encoding";
|
||||
int i;
|
||||
const char *str = "this is an example for huffman encoding";
|
||||
char buf[1024];
|
||||
|
||||
init(str);
|
||||
for (i = 0; i < 128; i++)
|
||||
if (code[i]) printf("'%c': %s\n", i, code[i]);
|
||||
init(str);
|
||||
for (i = 0; i < 128; i++)
|
||||
if (code[i]) printf("'%c': %s\n", i, code[i]);
|
||||
|
||||
encode(str, buf);
|
||||
printf("encoded: %s\n", buf);
|
||||
encode(str, buf);
|
||||
printf("encoded: %s\n", buf);
|
||||
|
||||
printf("decoded: ");
|
||||
decode(buf, q[1]);
|
||||
printf("decoded: ");
|
||||
decode(buf, q[1]);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
(defn huffman-tree [pq]
|
||||
(while (> (.size pq) 1)
|
||||
(let [a (.poll pq) b (.poll pq)
|
||||
new-node {:priority (+ (:priority a) (:priority b)) :left a :right b}]
|
||||
new-node {:priority (+ (:priority a) (:priority b)) :left a :right b}]
|
||||
(.add pq new-node)))
|
||||
(.poll pq))
|
||||
|
||||
|
|
|
|||
|
|
@ -4,29 +4,29 @@
|
|||
(defn init-pq [s]
|
||||
(let [c (count s)]
|
||||
(->> s frequencies
|
||||
(map (fn [[k v]] [k {:sym k :weight (/ v c)}]))
|
||||
(into (priority-map-keyfn-by :weight <)))))
|
||||
(map (fn [[k v]] [k {:sym k :weight (/ v c)}]))
|
||||
(into (priority-map-keyfn-by :weight <)))))
|
||||
|
||||
(defn huffman-tree [pq]
|
||||
(letfn [(build-step
|
||||
[pq]
|
||||
(let [a (second (peek pq)) b (second (peek (pop pq)))
|
||||
nn {:sym (str (:sym a) (:sym b))
|
||||
:weight (+ (:weight a) (:weight b))
|
||||
:left a :right b}]
|
||||
(assoc (pop (pop pq)) (:sym nn) nn)))]
|
||||
[pq]
|
||||
(let [a (second (peek pq)) b (second (peek (pop pq)))
|
||||
nn {:sym (str (:sym a) (:sym b))
|
||||
:weight (+ (:weight a) (:weight b))
|
||||
:left a :right b}]
|
||||
(assoc (pop (pop pq)) (:sym nn) nn)))]
|
||||
(->> (iterate build-step pq)
|
||||
(drop-while #(> (count %) 1))
|
||||
first vals first)))
|
||||
(drop-while #(> (count %) 1))
|
||||
first vals first)))
|
||||
|
||||
(defn symbol-map [m]
|
||||
(letfn [(sym-step
|
||||
[{:keys [sym weight left right] :as m} code]
|
||||
(cond (and left right) #(vector (trampoline sym-step left (str code \0))
|
||||
(trampoline sym-step right (str code \1)))
|
||||
left #(sym-step left (str code \0))
|
||||
right #(sym-step right (str code \1))
|
||||
:else {:sym sym :weight weight :code code}))]
|
||||
[{:keys [sym weight left right] :as m} code]
|
||||
(cond (and left right) #(vector (trampoline sym-step left (str code \0))
|
||||
(trampoline sym-step right (str code \1)))
|
||||
left #(sym-step left (str code \0))
|
||||
right #(sym-step right (str code \1))
|
||||
:else {:sym sym :weight weight :code code}))]
|
||||
(trampoline sym-step m "")))
|
||||
|
||||
(defn huffman-encode [s]
|
||||
|
|
|
|||
|
|
@ -1,188 +1,188 @@
|
|||
class HUFFMAN_NODE[T -> COMPARABLE]
|
||||
inherit
|
||||
COMPARABLE
|
||||
redefine
|
||||
three_way_comparison
|
||||
end
|
||||
COMPARABLE
|
||||
redefine
|
||||
three_way_comparison
|
||||
end
|
||||
create
|
||||
leaf_node, inner_node
|
||||
leaf_node, inner_node
|
||||
feature {NONE}
|
||||
leaf_node (a_probability: REAL_64; a_value: T)
|
||||
do
|
||||
probability := a_probability
|
||||
value := a_value
|
||||
is_leaf := true
|
||||
leaf_node (a_probability: REAL_64; a_value: T)
|
||||
do
|
||||
probability := a_probability
|
||||
value := a_value
|
||||
is_leaf := true
|
||||
|
||||
left := void
|
||||
right := void
|
||||
parent := void
|
||||
end
|
||||
left := void
|
||||
right := void
|
||||
parent := void
|
||||
end
|
||||
|
||||
inner_node (a_left, a_right: HUFFMAN_NODE[T])
|
||||
do
|
||||
left := a_left
|
||||
right := a_right
|
||||
inner_node (a_left, a_right: HUFFMAN_NODE[T])
|
||||
do
|
||||
left := a_left
|
||||
right := a_right
|
||||
|
||||
a_left.parent := Current
|
||||
a_right.parent := Current
|
||||
a_left.is_zero := true
|
||||
a_right.is_zero := false
|
||||
a_left.parent := Current
|
||||
a_right.parent := Current
|
||||
a_left.is_zero := true
|
||||
a_right.is_zero := false
|
||||
|
||||
probability := a_left.probability + a_right.probability
|
||||
is_leaf := false
|
||||
end
|
||||
probability := a_left.probability + a_right.probability
|
||||
is_leaf := false
|
||||
end
|
||||
|
||||
feature
|
||||
probability: REAL_64
|
||||
value: detachable T
|
||||
probability: REAL_64
|
||||
value: detachable T
|
||||
|
||||
|
||||
is_leaf: BOOLEAN
|
||||
is_zero: BOOLEAN assign set_is_zero
|
||||
is_leaf: BOOLEAN
|
||||
is_zero: BOOLEAN assign set_is_zero
|
||||
|
||||
set_is_zero (a_value: BOOLEAN)
|
||||
do
|
||||
is_zero := a_value
|
||||
end
|
||||
set_is_zero (a_value: BOOLEAN)
|
||||
do
|
||||
is_zero := a_value
|
||||
end
|
||||
|
||||
left: detachable HUFFMAN_NODE[T]
|
||||
right: detachable HUFFMAN_NODE[T]
|
||||
parent: detachable HUFFMAN_NODE[T] assign set_parent
|
||||
left: detachable HUFFMAN_NODE[T]
|
||||
right: detachable HUFFMAN_NODE[T]
|
||||
parent: detachable HUFFMAN_NODE[T] assign set_parent
|
||||
|
||||
set_parent (a_parent: detachable HUFFMAN_NODE[T])
|
||||
do
|
||||
parent := a_parent
|
||||
end
|
||||
set_parent (a_parent: detachable HUFFMAN_NODE[T])
|
||||
do
|
||||
parent := a_parent
|
||||
end
|
||||
|
||||
is_root: BOOLEAN
|
||||
do
|
||||
Result := parent = void
|
||||
end
|
||||
is_root: BOOLEAN
|
||||
do
|
||||
Result := parent = void
|
||||
end
|
||||
|
||||
bit_value: INTEGER
|
||||
do
|
||||
if is_zero then
|
||||
Result := 0
|
||||
else
|
||||
Result := 1
|
||||
end
|
||||
end
|
||||
bit_value: INTEGER
|
||||
do
|
||||
if is_zero then
|
||||
Result := 0
|
||||
else
|
||||
Result := 1
|
||||
end
|
||||
end
|
||||
feature -- comparable implementation
|
||||
is_less alias "<" (other: like Current): BOOLEAN
|
||||
do
|
||||
Result := three_way_comparison (other) = -1
|
||||
end
|
||||
is_less alias "<" (other: like Current): BOOLEAN
|
||||
do
|
||||
Result := three_way_comparison (other) = -1
|
||||
end
|
||||
|
||||
three_way_comparison (other: like Current): INTEGER
|
||||
do
|
||||
Result := -probability.three_way_comparison (other.probability)
|
||||
end
|
||||
three_way_comparison (other: like Current): INTEGER
|
||||
do
|
||||
Result := -probability.three_way_comparison (other.probability)
|
||||
end
|
||||
end
|
||||
|
||||
class HUFFMAN
|
||||
create
|
||||
make
|
||||
make
|
||||
feature {NONE}
|
||||
make(a_string: STRING)
|
||||
require
|
||||
non_empty_string: a_string.count > 0
|
||||
local
|
||||
l_queue: HEAP_PRIORITY_QUEUE[HUFFMAN_NODE[CHARACTER]]
|
||||
l_counts: HASH_TABLE[INTEGER, CHARACTER]
|
||||
l_node: HUFFMAN_NODE[CHARACTER]
|
||||
l_left, l_right: HUFFMAN_NODE[CHARACTER]
|
||||
do
|
||||
create l_queue.make (a_string.count)
|
||||
create l_counts.make (10)
|
||||
make(a_string: STRING)
|
||||
require
|
||||
non_empty_string: a_string.count > 0
|
||||
local
|
||||
l_queue: HEAP_PRIORITY_QUEUE[HUFFMAN_NODE[CHARACTER]]
|
||||
l_counts: HASH_TABLE[INTEGER, CHARACTER]
|
||||
l_node: HUFFMAN_NODE[CHARACTER]
|
||||
l_left, l_right: HUFFMAN_NODE[CHARACTER]
|
||||
do
|
||||
create l_queue.make (a_string.count)
|
||||
create l_counts.make (10)
|
||||
|
||||
across a_string as char
|
||||
loop
|
||||
if not l_counts.has (char.item) then
|
||||
l_counts.put (0, char.item)
|
||||
end
|
||||
l_counts.replace (l_counts.at (char.item) + 1, char.item)
|
||||
end
|
||||
across a_string as char
|
||||
loop
|
||||
if not l_counts.has (char.item) then
|
||||
l_counts.put (0, char.item)
|
||||
end
|
||||
l_counts.replace (l_counts.at (char.item) + 1, char.item)
|
||||
end
|
||||
|
||||
create leaf_dictionary.make(l_counts.count)
|
||||
create leaf_dictionary.make(l_counts.count)
|
||||
|
||||
across l_counts as kv
|
||||
loop
|
||||
create l_node.leaf_node ((kv.item * 1.0) / a_string.count, kv.key)
|
||||
l_queue.put (l_node)
|
||||
leaf_dictionary.put (l_node, kv.key)
|
||||
end
|
||||
across l_counts as kv
|
||||
loop
|
||||
create l_node.leaf_node ((kv.item * 1.0) / a_string.count, kv.key)
|
||||
l_queue.put (l_node)
|
||||
leaf_dictionary.put (l_node, kv.key)
|
||||
end
|
||||
|
||||
from
|
||||
until
|
||||
l_queue.count <= 1
|
||||
loop
|
||||
l_left := l_queue.item
|
||||
l_queue.remove
|
||||
l_right := l_queue.item
|
||||
l_queue.remove
|
||||
from
|
||||
until
|
||||
l_queue.count <= 1
|
||||
loop
|
||||
l_left := l_queue.item
|
||||
l_queue.remove
|
||||
l_right := l_queue.item
|
||||
l_queue.remove
|
||||
|
||||
create l_node.inner_node (l_left, l_right)
|
||||
l_queue.put (l_node)
|
||||
end
|
||||
create l_node.inner_node (l_left, l_right)
|
||||
l_queue.put (l_node)
|
||||
end
|
||||
|
||||
root := l_queue.item
|
||||
root.is_zero := false
|
||||
end
|
||||
root := l_queue.item
|
||||
root.is_zero := false
|
||||
end
|
||||
feature
|
||||
root: HUFFMAN_NODE[CHARACTER]
|
||||
leaf_dictionary: HASH_TABLE[HUFFMAN_NODE[CHARACTER], CHARACTER]
|
||||
root: HUFFMAN_NODE[CHARACTER]
|
||||
leaf_dictionary: HASH_TABLE[HUFFMAN_NODE[CHARACTER], CHARACTER]
|
||||
|
||||
encode(a_value: CHARACTER): STRING
|
||||
require
|
||||
encodable: leaf_dictionary.has (a_value)
|
||||
local
|
||||
l_node: HUFFMAN_NODE[CHARACTER]
|
||||
do
|
||||
Result := ""
|
||||
if attached leaf_dictionary.item (a_value) as attached_node then
|
||||
l_node := attached_node
|
||||
from
|
||||
encode(a_value: CHARACTER): STRING
|
||||
require
|
||||
encodable: leaf_dictionary.has (a_value)
|
||||
local
|
||||
l_node: HUFFMAN_NODE[CHARACTER]
|
||||
do
|
||||
Result := ""
|
||||
if attached leaf_dictionary.item (a_value) as attached_node then
|
||||
l_node := attached_node
|
||||
from
|
||||
|
||||
until
|
||||
l_node.is_root
|
||||
loop
|
||||
Result.append_integer (l_node.bit_value)
|
||||
if attached l_node.parent as parent then
|
||||
l_node := parent
|
||||
end
|
||||
end
|
||||
until
|
||||
l_node.is_root
|
||||
loop
|
||||
Result.append_integer (l_node.bit_value)
|
||||
if attached l_node.parent as parent then
|
||||
l_node := parent
|
||||
end
|
||||
end
|
||||
|
||||
Result.mirror
|
||||
end
|
||||
end
|
||||
Result.mirror
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class
|
||||
APPLICATION
|
||||
APPLICATION
|
||||
create
|
||||
make
|
||||
make
|
||||
|
||||
feature {NONE}
|
||||
make -- entry point
|
||||
local
|
||||
l_str: STRING
|
||||
huff: HUFFMAN
|
||||
chars: BINARY_SEARCH_TREE_SET[CHARACTER]
|
||||
do
|
||||
l_str := "this is an example for huffman encoding"
|
||||
make -- entry point
|
||||
local
|
||||
l_str: STRING
|
||||
huff: HUFFMAN
|
||||
chars: BINARY_SEARCH_TREE_SET[CHARACTER]
|
||||
do
|
||||
l_str := "this is an example for huffman encoding"
|
||||
|
||||
create huff.make (l_str)
|
||||
create huff.make (l_str)
|
||||
|
||||
create chars.make
|
||||
chars.fill (l_str)
|
||||
create chars.make
|
||||
chars.fill (l_str)
|
||||
|
||||
from
|
||||
chars.start
|
||||
until
|
||||
chars.off
|
||||
loop
|
||||
print (chars.item.out + ": " + huff.encode (chars.item) + "%N")
|
||||
chars.forth
|
||||
end
|
||||
end
|
||||
from
|
||||
chars.start
|
||||
until
|
||||
chars.off
|
||||
loop
|
||||
print (chars.item.out + ": " + huff.encode (chars.item) + "%N")
|
||||
chars.forth
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -113,20 +113,20 @@ PRIVATE>
|
|||
! { 1 2 3 4 } huffman huffman-print
|
||||
! "this is an example of a huffman tree" huffman huffman-print
|
||||
|
||||
! Element Weight Code
|
||||
! 7 { 0 0 0 }
|
||||
! a 4 { 1 1 1 }
|
||||
! e 4 { 1 1 0 }
|
||||
! f 3 { 0 0 1 0 }
|
||||
! h 2 { 1 0 1 0 }
|
||||
! i 2 { 0 1 0 1 }
|
||||
! m 2 { 0 1 0 0 }
|
||||
! n 2 { 0 1 1 1 }
|
||||
! s 2 { 0 1 1 0 }
|
||||
! t 2 { 0 0 1 1 }
|
||||
! l 1 { 1 0 1 1 1 }
|
||||
! o 1 { 1 0 1 1 0 }
|
||||
! p 1 { 1 0 0 0 1 }
|
||||
! r 1 { 1 0 0 0 0 }
|
||||
! u 1 { 1 0 0 1 1 }
|
||||
! x 1 { 1 0 0 1 0 }
|
||||
! Element Weight Code
|
||||
! 7 { 0 0 0 }
|
||||
! a 4 { 1 1 1 }
|
||||
! e 4 { 1 1 0 }
|
||||
! f 3 { 0 0 1 0 }
|
||||
! h 2 { 1 0 1 0 }
|
||||
! i 2 { 0 1 0 1 }
|
||||
! m 2 { 0 1 0 0 }
|
||||
! n 2 { 0 1 1 1 }
|
||||
! s 2 { 0 1 1 0 }
|
||||
! t 2 { 0 0 1 1 }
|
||||
! l 1 { 1 0 1 1 1 }
|
||||
! o 1 { 1 0 1 1 0 }
|
||||
! p 1 { 1 0 0 0 1 }
|
||||
! r 1 { 1 0 0 0 0 }
|
||||
! u 1 { 1 0 0 1 1 }
|
||||
! x 1 { 1 0 0 1 0 }
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ local c,T
|
|||
T := table()
|
||||
every c := !s do {
|
||||
/T[c] := huffnode(,,0,c)
|
||||
T[c].n +:= 1
|
||||
T[c].n +:= 1
|
||||
}
|
||||
return T
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,99 +1,99 @@
|
|||
class node{
|
||||
constructor(freq, char, left, right){
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.freq = freq;
|
||||
this.c = char;
|
||||
}
|
||||
constructor(freq, char, left, right){
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.freq = freq;
|
||||
this.c = char;
|
||||
}
|
||||
};
|
||||
|
||||
nodes = [];
|
||||
code = {};
|
||||
|
||||
function new_node(left, right){
|
||||
return new node(left.freq + right.freq, -1, left, right);;
|
||||
return new node(left.freq + right.freq, -1, left, right);;
|
||||
};
|
||||
|
||||
function qinsert(node){
|
||||
nodes.push(node);
|
||||
nodes.sort(compareFunction);
|
||||
nodes.push(node);
|
||||
nodes.sort(compareFunction);
|
||||
};
|
||||
|
||||
function qremove(){
|
||||
return nodes.pop();
|
||||
return nodes.pop();
|
||||
};
|
||||
|
||||
function compareFunction(a, b){
|
||||
return b.freq - a.freq;
|
||||
return b.freq - a.freq;
|
||||
};
|
||||
|
||||
function build_code(node, codeString, length){
|
||||
if (node.c != -1){
|
||||
code[node.c] = codeString;
|
||||
return;
|
||||
};
|
||||
/* Left Branch */
|
||||
leftCodeString = codeString + "0";
|
||||
build_code(node.left, leftCodeString, length + 1);
|
||||
/* Right Branch */
|
||||
rightCodeString = codeString + "1";
|
||||
build_code(node.right, rightCodeString, length + 1);
|
||||
if (node.c != -1){
|
||||
code[node.c] = codeString;
|
||||
return;
|
||||
};
|
||||
/* Left Branch */
|
||||
leftCodeString = codeString + "0";
|
||||
build_code(node.left, leftCodeString, length + 1);
|
||||
/* Right Branch */
|
||||
rightCodeString = codeString + "1";
|
||||
build_code(node.right, rightCodeString, length + 1);
|
||||
};
|
||||
|
||||
function init(string){
|
||||
var i;
|
||||
var freq = [];
|
||||
var codeString = "";
|
||||
|
||||
for (var i = 0; i < string.length; i++){
|
||||
if (isNaN(freq[string.charCodeAt(i)])){
|
||||
freq[string.charCodeAt(i)] = 1;
|
||||
} else {
|
||||
freq[string.charCodeAt(i)] ++;
|
||||
};
|
||||
};
|
||||
|
||||
for (var i = 0; i < freq.length; i++){
|
||||
if (freq[i] > 0){
|
||||
qinsert(new node(freq[i], i, null, null));
|
||||
};
|
||||
};
|
||||
|
||||
while (nodes.length > 1){
|
||||
qinsert(new_node(qremove(), qremove()));
|
||||
};
|
||||
|
||||
build_code(nodes[0], codeString, 0);
|
||||
var i;
|
||||
var freq = [];
|
||||
var codeString = "";
|
||||
|
||||
for (var i = 0; i < string.length; i++){
|
||||
if (isNaN(freq[string.charCodeAt(i)])){
|
||||
freq[string.charCodeAt(i)] = 1;
|
||||
} else {
|
||||
freq[string.charCodeAt(i)] ++;
|
||||
};
|
||||
};
|
||||
|
||||
for (var i = 0; i < freq.length; i++){
|
||||
if (freq[i] > 0){
|
||||
qinsert(new node(freq[i], i, null, null));
|
||||
};
|
||||
};
|
||||
|
||||
while (nodes.length > 1){
|
||||
qinsert(new_node(qremove(), qremove()));
|
||||
};
|
||||
|
||||
build_code(nodes[0], codeString, 0);
|
||||
};
|
||||
|
||||
function encode(string){
|
||||
output = "";
|
||||
|
||||
for (var i = 0; i < string.length; i ++){
|
||||
output += code[string.charCodeAt(i)];
|
||||
};
|
||||
|
||||
return output;
|
||||
output = "";
|
||||
|
||||
for (var i = 0; i < string.length; i ++){
|
||||
output += code[string.charCodeAt(i)];
|
||||
};
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
function decode(input){
|
||||
output = "";
|
||||
node = nodes[0];
|
||||
|
||||
for (var i = 0; i < input.length; i++){
|
||||
if (input[i] == "0"){
|
||||
node = node.left;
|
||||
} else {
|
||||
node = node.right;
|
||||
};
|
||||
|
||||
if (node.c != -1){
|
||||
output += String.fromCharCode(node.c);
|
||||
node = nodes[0];
|
||||
};
|
||||
};
|
||||
|
||||
return output
|
||||
output = "";
|
||||
node = nodes[0];
|
||||
|
||||
for (var i = 0; i < input.length; i++){
|
||||
if (input[i] == "0"){
|
||||
node = node.left;
|
||||
} else {
|
||||
node = node.right;
|
||||
};
|
||||
|
||||
if (node.c != -1){
|
||||
output += String.fromCharCode(node.c);
|
||||
node = nodes[0];
|
||||
};
|
||||
};
|
||||
|
||||
return output
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -101,10 +101,10 @@ string = "this is an example of huffman encoding";
|
|||
console.log("initial string: " + string);
|
||||
init(string);
|
||||
for (var i = 0; i < Object.keys(code).length; i++){
|
||||
if (isNaN(code[Object.keys(code)[i]])){
|
||||
} else {
|
||||
console.log("'" + String.fromCharCode(Object.keys(code)[i]) + "'" + ": " + code[Object.keys(code)[i]]);
|
||||
};
|
||||
if (isNaN(code[Object.keys(code)[i]])){
|
||||
} else {
|
||||
console.log("'" + String.fromCharCode(Object.keys(code)[i]) + "'" + ": " + code[Object.keys(code)[i]]);
|
||||
};
|
||||
};
|
||||
|
||||
huffman = encode(string);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
|
||||
@interface HuffmanTree : NSObject {
|
||||
int freq;
|
||||
int freq;
|
||||
}
|
||||
-(instancetype)initWithFreq:(int)f;
|
||||
@property (nonatomic, readonly) int freq;
|
||||
|
|
@ -11,34 +11,34 @@
|
|||
@implementation HuffmanTree
|
||||
@synthesize freq; // the frequency of this tree
|
||||
-(instancetype)initWithFreq:(int)f {
|
||||
if (self = [super init]) {
|
||||
freq = f;
|
||||
}
|
||||
return self;
|
||||
if (self = [super init]) {
|
||||
freq = f;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
const void *HuffmanRetain(CFAllocatorRef allocator, const void *ptr) {
|
||||
return (__bridge_retained const void *)(__bridge id)ptr;
|
||||
return (__bridge_retained const void *)(__bridge id)ptr;
|
||||
}
|
||||
void HuffmanRelease(CFAllocatorRef allocator, const void *ptr) {
|
||||
(void)(__bridge_transfer id)ptr;
|
||||
(void)(__bridge_transfer id)ptr;
|
||||
}
|
||||
CFComparisonResult HuffmanCompare(const void *ptr1, const void *ptr2, void *unused) {
|
||||
int f1 = ((__bridge HuffmanTree *)ptr1).freq;
|
||||
int f2 = ((__bridge HuffmanTree *)ptr2).freq;
|
||||
if (f1 == f2)
|
||||
return kCFCompareEqualTo;
|
||||
else if (f1 > f2)
|
||||
return kCFCompareGreaterThan;
|
||||
else
|
||||
return kCFCompareLessThan;
|
||||
int f1 = ((__bridge HuffmanTree *)ptr1).freq;
|
||||
int f2 = ((__bridge HuffmanTree *)ptr2).freq;
|
||||
if (f1 == f2)
|
||||
return kCFCompareEqualTo;
|
||||
else if (f1 > f2)
|
||||
return kCFCompareGreaterThan;
|
||||
else
|
||||
return kCFCompareLessThan;
|
||||
}
|
||||
|
||||
|
||||
@interface HuffmanLeaf : HuffmanTree {
|
||||
char value; // the character this leaf represents
|
||||
char value; // the character this leaf represents
|
||||
}
|
||||
@property (readonly) char value;
|
||||
-(instancetype)initWithFreq:(int)f character:(char)c;
|
||||
|
|
@ -47,16 +47,16 @@ CFComparisonResult HuffmanCompare(const void *ptr1, const void *ptr2, void *unus
|
|||
@implementation HuffmanLeaf
|
||||
@synthesize value;
|
||||
-(instancetype)initWithFreq:(int)f character:(char)c {
|
||||
if (self = [super initWithFreq:f]) {
|
||||
value = c;
|
||||
}
|
||||
return self;
|
||||
if (self = [super initWithFreq:f]) {
|
||||
value = c;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface HuffmanNode : HuffmanTree {
|
||||
HuffmanTree *left, *right; // subtrees
|
||||
HuffmanTree *left, *right; // subtrees
|
||||
}
|
||||
@property (readonly) HuffmanTree *left, *right;
|
||||
-(instancetype)initWithLeft:(HuffmanTree *)l right:(HuffmanTree *)r;
|
||||
|
|
@ -65,86 +65,86 @@ CFComparisonResult HuffmanCompare(const void *ptr1, const void *ptr2, void *unus
|
|||
@implementation HuffmanNode
|
||||
@synthesize left, right;
|
||||
-(instancetype)initWithLeft:(HuffmanTree *)l right:(HuffmanTree *)r {
|
||||
if (self = [super initWithFreq:l.freq+r.freq]) {
|
||||
left = l;
|
||||
right = r;
|
||||
}
|
||||
return self;
|
||||
if (self = [super initWithFreq:l.freq+r.freq]) {
|
||||
left = l;
|
||||
right = r;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
HuffmanTree *buildTree(NSCountedSet *chars) {
|
||||
|
||||
CFBinaryHeapCallBacks callBacks = {0, HuffmanRetain, HuffmanRelease, NULL, HuffmanCompare};
|
||||
CFBinaryHeapRef trees = CFBinaryHeapCreate(NULL, 0, &callBacks, NULL);
|
||||
|
||||
// initially, we have a forest of leaves
|
||||
// one for each non-empty character
|
||||
for (NSNumber *ch in chars) {
|
||||
int freq = [chars countForObject:ch];
|
||||
if (freq > 0)
|
||||
CFBinaryHeapAddValue(trees, (__bridge const void *)[[HuffmanLeaf alloc] initWithFreq:freq character:(char)[ch intValue]]);
|
||||
}
|
||||
|
||||
NSCAssert(CFBinaryHeapGetCount(trees) > 0, @"String must have at least one character");
|
||||
// loop until there is only one tree left
|
||||
while (CFBinaryHeapGetCount(trees) > 1) {
|
||||
// two trees with least frequency
|
||||
HuffmanTree *a = (__bridge HuffmanTree *)CFBinaryHeapGetMinimum(trees);
|
||||
CFBinaryHeapRemoveMinimumValue(trees);
|
||||
HuffmanTree *b = (__bridge HuffmanTree *)CFBinaryHeapGetMinimum(trees);
|
||||
CFBinaryHeapRemoveMinimumValue(trees);
|
||||
|
||||
// put into new node and re-insert into queue
|
||||
CFBinaryHeapAddValue(trees, (__bridge const void *)[[HuffmanNode alloc] initWithLeft:a right:b]);
|
||||
}
|
||||
HuffmanTree *result = (__bridge HuffmanTree *)CFBinaryHeapGetMinimum(trees);
|
||||
CFRelease(trees);
|
||||
return result;
|
||||
CFBinaryHeapCallBacks callBacks = {0, HuffmanRetain, HuffmanRelease, NULL, HuffmanCompare};
|
||||
CFBinaryHeapRef trees = CFBinaryHeapCreate(NULL, 0, &callBacks, NULL);
|
||||
|
||||
// initially, we have a forest of leaves
|
||||
// one for each non-empty character
|
||||
for (NSNumber *ch in chars) {
|
||||
int freq = [chars countForObject:ch];
|
||||
if (freq > 0)
|
||||
CFBinaryHeapAddValue(trees, (__bridge const void *)[[HuffmanLeaf alloc] initWithFreq:freq character:(char)[ch intValue]]);
|
||||
}
|
||||
|
||||
NSCAssert(CFBinaryHeapGetCount(trees) > 0, @"String must have at least one character");
|
||||
// loop until there is only one tree left
|
||||
while (CFBinaryHeapGetCount(trees) > 1) {
|
||||
// two trees with least frequency
|
||||
HuffmanTree *a = (__bridge HuffmanTree *)CFBinaryHeapGetMinimum(trees);
|
||||
CFBinaryHeapRemoveMinimumValue(trees);
|
||||
HuffmanTree *b = (__bridge HuffmanTree *)CFBinaryHeapGetMinimum(trees);
|
||||
CFBinaryHeapRemoveMinimumValue(trees);
|
||||
|
||||
// put into new node and re-insert into queue
|
||||
CFBinaryHeapAddValue(trees, (__bridge const void *)[[HuffmanNode alloc] initWithLeft:a right:b]);
|
||||
}
|
||||
HuffmanTree *result = (__bridge HuffmanTree *)CFBinaryHeapGetMinimum(trees);
|
||||
CFRelease(trees);
|
||||
return result;
|
||||
}
|
||||
|
||||
void printCodes(HuffmanTree *tree, NSMutableString *prefix) {
|
||||
NSCAssert(tree != nil, @"tree must not be nil");
|
||||
if ([tree isKindOfClass:[HuffmanLeaf class]]) {
|
||||
HuffmanLeaf *leaf = (HuffmanLeaf *)tree;
|
||||
|
||||
// print out character, frequency, and code for this leaf (which is just the prefix)
|
||||
NSLog(@"%c\t%d\t%@", leaf.value, leaf.freq, prefix);
|
||||
|
||||
} else if ([tree isKindOfClass:[HuffmanNode class]]) {
|
||||
HuffmanNode *node = (HuffmanNode *)tree;
|
||||
|
||||
// traverse left
|
||||
[prefix appendString:@"0"];
|
||||
printCodes(node.left, prefix);
|
||||
[prefix deleteCharactersInRange:NSMakeRange([prefix length]-1, 1)];
|
||||
|
||||
// traverse right
|
||||
[prefix appendString:@"1"];
|
||||
printCodes(node.right, prefix);
|
||||
[prefix deleteCharactersInRange:NSMakeRange([prefix length]-1, 1)];
|
||||
}
|
||||
NSCAssert(tree != nil, @"tree must not be nil");
|
||||
if ([tree isKindOfClass:[HuffmanLeaf class]]) {
|
||||
HuffmanLeaf *leaf = (HuffmanLeaf *)tree;
|
||||
|
||||
// print out character, frequency, and code for this leaf (which is just the prefix)
|
||||
NSLog(@"%c\t%d\t%@", leaf.value, leaf.freq, prefix);
|
||||
|
||||
} else if ([tree isKindOfClass:[HuffmanNode class]]) {
|
||||
HuffmanNode *node = (HuffmanNode *)tree;
|
||||
|
||||
// traverse left
|
||||
[prefix appendString:@"0"];
|
||||
printCodes(node.left, prefix);
|
||||
[prefix deleteCharactersInRange:NSMakeRange([prefix length]-1, 1)];
|
||||
|
||||
// traverse right
|
||||
[prefix appendString:@"1"];
|
||||
printCodes(node.right, prefix);
|
||||
[prefix deleteCharactersInRange:NSMakeRange([prefix length]-1, 1)];
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
@autoreleasepool {
|
||||
|
||||
NSString *test = @"this is an example for huffman encoding";
|
||||
|
||||
// read each character and record the frequencies
|
||||
NSCountedSet *chars = [[NSCountedSet alloc] init];
|
||||
int n = [test length];
|
||||
for (int i = 0; i < n; i++)
|
||||
[chars addObject:@([test characterAtIndex:i])];
|
||||
|
||||
// build tree
|
||||
HuffmanTree *tree = buildTree(chars);
|
||||
|
||||
// print out results
|
||||
NSLog(@"SYMBOL\tWEIGHT\tHUFFMAN CODE");
|
||||
printCodes(tree, [NSMutableString string]);
|
||||
|
||||
NSString *test = @"this is an example for huffman encoding";
|
||||
|
||||
// read each character and record the frequencies
|
||||
NSCountedSet *chars = [[NSCountedSet alloc] init];
|
||||
int n = [test length];
|
||||
for (int i = 0; i < n; i++)
|
||||
[chars addObject:@([test characterAtIndex:i])];
|
||||
|
||||
// build tree
|
||||
HuffmanTree *tree = buildTree(chars);
|
||||
|
||||
// print out results
|
||||
NSLog(@"SYMBOL\tWEIGHT\tHUFFMAN CODE");
|
||||
printCodes(tree, [NSMutableString string]);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,48 +3,48 @@ use strict;
|
|||
|
||||
# produce encode and decode dictionary from a tree
|
||||
sub walk {
|
||||
my ($node, $code, $h, $rev_h) = @_;
|
||||
my ($node, $code, $h, $rev_h) = @_;
|
||||
|
||||
my $c = $node->[0];
|
||||
if (ref $c) { walk($c->[$_], $code.$_, $h, $rev_h) for 0,1 }
|
||||
else { $h->{$c} = $code; $rev_h->{$code} = $c }
|
||||
my $c = $node->[0];
|
||||
if (ref $c) { walk($c->[$_], $code.$_, $h, $rev_h) for 0,1 }
|
||||
else { $h->{$c} = $code; $rev_h->{$code} = $c }
|
||||
|
||||
$h, $rev_h
|
||||
$h, $rev_h
|
||||
}
|
||||
|
||||
# make a tree, and return resulting dictionaries
|
||||
sub mktree {
|
||||
my (%freq, @nodes);
|
||||
$freq{$_}++ for split '', shift;
|
||||
@nodes = map([$_, $freq{$_}], keys %freq);
|
||||
my (%freq, @nodes);
|
||||
$freq{$_}++ for split '', shift;
|
||||
@nodes = map([$_, $freq{$_}], keys %freq);
|
||||
|
||||
do { # poor man's priority queue
|
||||
@nodes = sort {$a->[1] <=> $b->[1]} @nodes;
|
||||
my ($x, $y) = splice @nodes, 0, 2;
|
||||
push @nodes, [[$x, $y], $x->[1] + $y->[1]]
|
||||
} while (@nodes > 1);
|
||||
do { # poor man's priority queue
|
||||
@nodes = sort {$a->[1] <=> $b->[1]} @nodes;
|
||||
my ($x, $y) = splice @nodes, 0, 2;
|
||||
push @nodes, [[$x, $y], $x->[1] + $y->[1]]
|
||||
} while (@nodes > 1);
|
||||
|
||||
walk($nodes[0], '', {}, {})
|
||||
walk($nodes[0], '', {}, {})
|
||||
}
|
||||
|
||||
sub encode {
|
||||
my ($str, $dict) = @_;
|
||||
join '', map $dict->{$_}//die("bad char $_"), split '', $str
|
||||
my ($str, $dict) = @_;
|
||||
join '', map $dict->{$_}//die("bad char $_"), split '', $str
|
||||
}
|
||||
|
||||
sub decode {
|
||||
my ($str, $dict) = @_;
|
||||
my ($seg, @out) = ("");
|
||||
my ($str, $dict) = @_;
|
||||
my ($seg, @out) = ("");
|
||||
|
||||
# append to current segment until it's in the dictionary
|
||||
for (split '', $str) {
|
||||
$seg .= $_;
|
||||
my $x = $dict->{$seg} // next;
|
||||
push @out, $x;
|
||||
$seg = '';
|
||||
}
|
||||
die "bad code" if length($seg);
|
||||
join '', @out
|
||||
# append to current segment until it's in the dictionary
|
||||
for (split '', $str) {
|
||||
$seg .= $_;
|
||||
my $x = $dict->{$seg} // next;
|
||||
push @out, $x;
|
||||
$seg = '';
|
||||
}
|
||||
die "bad code" if length($seg);
|
||||
join '', @out
|
||||
}
|
||||
|
||||
my $txt = 'this is an example for huffman encoding';
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
function Get-HuffmanEncodingTable ( $String )
|
||||
{
|
||||
# Create leaf nodes
|
||||
$ID = 0
|
||||
$Nodes = [char[]]$String |
|
||||
Group-Object |
|
||||
ForEach { $ID++; $_ } |
|
||||
Select @{ Label = 'Symbol' ; Expression = { $_.Name } },
|
||||
@{ Label = 'Count' ; Expression = { $_.Count } },
|
||||
@{ Label = 'ID' ; Expression = { $ID } },
|
||||
@{ Label = 'Parent' ; Expression = { 0 } },
|
||||
@{ Label = 'Code' ; Expression = { '' } }
|
||||
|
||||
# Grow stems under leafs
|
||||
ForEach ( $Branch in 2..($Nodes.Count) )
|
||||
{
|
||||
# Get the two nodes with the lowest count
|
||||
$LowNodes = $Nodes | Where Parent -eq 0 | Sort Count | Select -First 2
|
||||
|
||||
# Create a new stem node
|
||||
$ID++
|
||||
$Nodes += '' |
|
||||
Select @{ Label = 'Symbol' ; Expression = { '' } },
|
||||
@{ Label = 'Count' ; Expression = { $LowNodes[0].Count + $LowNodes[1].Count } },
|
||||
@{ Label = 'ID' ; Expression = { $ID } },
|
||||
@{ Label = 'Parent' ; Expression = { 0 } },
|
||||
@{ Label = 'Code' ; Expression = { '' } }
|
||||
|
||||
# Put the two nodes in the new stem node
|
||||
$LowNodes[0].Parent = $ID
|
||||
$LowNodes[1].Parent = $ID
|
||||
|
||||
# Assign 0 and 1 to the left and right nodes
|
||||
$LowNodes[0].Code = '0'
|
||||
$LowNodes[1].Code = '1'
|
||||
}
|
||||
|
||||
# Assign coding to nodes
|
||||
ForEach ( $Node in $Nodes[($Nodes.Count-2)..0] )
|
||||
{
|
||||
$Node.Code = ( $Nodes | Where ID -eq $Node.Parent ).Code + $Node.Code
|
||||
}
|
||||
|
||||
$EncodingTable = $Nodes | Where { $_.Symbol } | Select Symbol, Code | Sort Symbol
|
||||
return $EncodingTable
|
||||
}
|
||||
|
||||
# Get table for given string
|
||||
$String = "this is an example for huffman encoding"
|
||||
$HuffmanEncodingTable = Get-HuffmanEncodingTable $String
|
||||
|
||||
# Display table
|
||||
$HuffmanEncodingTable | Format-Table -AutoSize
|
||||
|
||||
# Encode string
|
||||
$EncodedString = $String
|
||||
ForEach ( $Node in $HuffmanEncodingTable )
|
||||
{
|
||||
$EncodedString = $EncodedString.Replace( $Node.Symbol, $Node.Code )
|
||||
}
|
||||
$EncodedString
|
||||
|
|
@ -1,37 +1,37 @@
|
|||
huffman :-
|
||||
L = 'this is an example for huffman encoding',
|
||||
atom_chars(L, LA),
|
||||
msort(LA, LS),
|
||||
packList(LS, PL),
|
||||
sort(PL, PLS),
|
||||
build_tree(PLS, A),
|
||||
coding(A, [], C),
|
||||
sort(C, SC),
|
||||
format('Symbol~t Weight~t~30|Code~n'),
|
||||
maplist(print_code, SC).
|
||||
L = 'this is an example for huffman encoding',
|
||||
atom_chars(L, LA),
|
||||
msort(LA, LS),
|
||||
packList(LS, PL),
|
||||
sort(PL, PLS),
|
||||
build_tree(PLS, A),
|
||||
coding(A, [], C),
|
||||
sort(C, SC),
|
||||
format('Symbol~t Weight~t~30|Code~n'),
|
||||
maplist(print_code, SC).
|
||||
|
||||
build_tree([[V1|R1], [V2|R2]|T], AF) :-
|
||||
V is V1 + V2,
|
||||
A = [V, [V1|R1], [V2|R2]],
|
||||
( T=[] -> AF=A ; sort([A|T], NT), build_tree(NT, AF) ).
|
||||
V is V1 + V2,
|
||||
A = [V, [V1|R1], [V2|R2]],
|
||||
( T=[] -> AF=A ; sort([A|T], NT), build_tree(NT, AF) ).
|
||||
|
||||
coding([_A,FG,FD], Code, CF) :-
|
||||
( is_node(FG) -> coding(FG, [0 | Code], C1)
|
||||
; leaf_coding(FG, [0 | Code], C1) ),
|
||||
( is_node(FD) -> coding(FD, [1 | Code], C2)
|
||||
; leaf_coding(FD, [1 | Code], C2) ),
|
||||
append(C1, C2, CF).
|
||||
( is_node(FG) -> coding(FG, [0 | Code], C1)
|
||||
; leaf_coding(FG, [0 | Code], C1) ),
|
||||
( is_node(FD) -> coding(FD, [1 | Code], C2)
|
||||
; leaf_coding(FD, [1 | Code], C2) ),
|
||||
append(C1, C2, CF).
|
||||
|
||||
leaf_coding([FG,FD], Code, CF) :-
|
||||
reverse(Code, CodeR),
|
||||
CF = [[FG, FD, CodeR]] .
|
||||
reverse(Code, CodeR),
|
||||
CF = [[FG, FD, CodeR]] .
|
||||
|
||||
is_node([_V, _FG, _FD]).
|
||||
|
||||
print_code([N, Car, Code]):-
|
||||
format('~w :~t~w~t~30|', [Car, N]),
|
||||
forall(member(V, Code), write(V)),
|
||||
nl.
|
||||
format('~w :~t~w~t~30|', [Car, N]),
|
||||
forall(member(V, Code), write(V)),
|
||||
nl.
|
||||
|
||||
packList([], []).
|
||||
packList([X], [[1,X]]) :- !.
|
||||
|
|
|
|||
|
|
@ -4,74 +4,74 @@ Red [file: %huffy.red]
|
|||
msg: "this is an example for huffman encoding"
|
||||
|
||||
;;map to collect leave knots per uniq character of message
|
||||
m: make map! []
|
||||
m: make map! []
|
||||
|
||||
knot: make object! [
|
||||
left: right: none ;; pointer to left/right sibling
|
||||
code: none ;; first holds char for debugging, later binary code
|
||||
count: depth: 1 ;;occurence of character - length of branch
|
||||
left: right: none ;; pointer to left/right sibling
|
||||
code: none ;; first holds char for debugging, later binary code
|
||||
count: depth: 1 ;;occurence of character - length of branch
|
||||
]
|
||||
|
||||
;;-----------------------------------------
|
||||
set-code: func ["recursive function to generate binary code sequence"
|
||||
wknot
|
||||
wcode [string!]] [
|
||||
wknot
|
||||
wcode [string!]] [
|
||||
;;-----------------------------------------
|
||||
either wknot/left = none [
|
||||
wknot/code: wcode
|
||||
] [
|
||||
set-code wknot/left rejoin [wcode "1"]
|
||||
set-code wknot/right rejoin [wcode "0"]
|
||||
]
|
||||
] ;;-- end func
|
||||
either wknot/left = none [
|
||||
wknot/code: wcode
|
||||
] [
|
||||
set-code wknot/left rejoin [wcode "1"]
|
||||
set-code wknot/right rejoin [wcode "0"]
|
||||
]
|
||||
] ;;-- end func
|
||||
|
||||
;-------------------------------
|
||||
merge-2knots: func ["function to merge 2 knots into 1 new"
|
||||
t [block!]][
|
||||
t [block!]][
|
||||
;-------------------------------
|
||||
nknot: copy knot ;; create new knot
|
||||
nknot/count: t/1/count + t/2/count
|
||||
nknot/right: t/1
|
||||
nknot/left: t/2
|
||||
nknot/depth: t/1/depth + 1
|
||||
tab: remove/part t 2 ;; delete first 2 knots
|
||||
insert t nknot ;; insert new generated knot
|
||||
] ;;-- end func
|
||||
nknot: copy knot ;; create new knot
|
||||
nknot/count: t/1/count + t/2/count
|
||||
nknot/right: t/1
|
||||
nknot/left: t/2
|
||||
nknot/depth: t/1/depth + 1
|
||||
tab: remove/part t 2 ;; delete first 2 knots
|
||||
insert t nknot ;; insert new generated knot
|
||||
] ;;-- end func
|
||||
|
||||
;; count occurence of characters, save in map: m
|
||||
foreach chr msg [
|
||||
either k: select/case m chr [
|
||||
k/count: k/count + 1
|
||||
][
|
||||
put/case m chr nknot: copy knot
|
||||
nknot/code: chr
|
||||
]
|
||||
either k: select/case m chr [
|
||||
k/count: k/count + 1
|
||||
][
|
||||
put/case m chr nknot: copy knot
|
||||
nknot/code: chr
|
||||
]
|
||||
]
|
||||
|
||||
;; create sortable block (=tab) for use as prio queue
|
||||
foreach k keys-of m [ append tab: [] :m/:k ]
|
||||
foreach k keys-of m [ append tab: [] :m/:k ]
|
||||
|
||||
;; build tree
|
||||
while [ 1 < length? tab][
|
||||
sort/compare tab function [a b] [
|
||||
a/count < b/count
|
||||
or ( a/count = b/count and ( a/depth > b/depth ) )
|
||||
]
|
||||
merge-2knots tab ;; merge 2 knots with lowest count / max depth
|
||||
sort/compare tab function [a b] [
|
||||
a/count < b/count
|
||||
or ( a/count = b/count and ( a/depth > b/depth ) )
|
||||
]
|
||||
merge-2knots tab ;; merge 2 knots with lowest count / max depth
|
||||
]
|
||||
|
||||
set-code tab/1 "" ;; generate binary codes, save at leave knot
|
||||
set-code tab/1 "" ;; generate binary codes, save at leave knot
|
||||
|
||||
;; display codes
|
||||
foreach k sort keys-of m [
|
||||
print [k " = " m/:k/code]
|
||||
append codes: "" m/:k/code
|
||||
print [k " = " m/:k/code]
|
||||
append codes: "" m/:k/code
|
||||
]
|
||||
|
||||
;; encode orig message string
|
||||
foreach chr msg [
|
||||
k: select/case m chr
|
||||
append msg-new: "" k/code
|
||||
k: select/case m chr
|
||||
append msg-new: "" k/code
|
||||
]
|
||||
|
||||
print [ "length of encoded msg " length? msg-new]
|
||||
|
|
@ -83,7 +83,7 @@ prin "decoded: "
|
|||
;; decode message (destructive! ):
|
||||
while [ not empty? msg-new ][
|
||||
foreach [k v] body-of m [
|
||||
if t: find/match msg-new v/code [
|
||||
if t: find/match/tail msg-new v/code [
|
||||
prin k
|
||||
msg-new: t
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,18 +5,18 @@ fcn buildHuffman(text){ //-->(encode dictionary, decode dictionary)
|
|||
// build the tree, which is a list of lists of ...
|
||||
tree:=ft.pump(List,fcn([(c,cnt)]){ //-->L( (cnt, ((sym,code))), ...)
|
||||
L(cnt, L(L(c,"")))
|
||||
}).copy(); // make it writable
|
||||
}).copy(); // make it writable
|
||||
|
||||
while(tree.len()>1){ // fake up a [lame] priorty queue
|
||||
tree=tree.sort(fcn(a,b){ a[0]>b[0] }); //prioritize high to low
|
||||
a,b:=tree.pop(-2,2); //remove 2 least frequent symbols
|
||||
mc:=fcn(n,c){ n[1] = c + n[1]; }; //(sym,code),"0"|"1"
|
||||
a,b:=tree.pop(-2,2); //remove 2 least frequent symbols
|
||||
mc:=fcn(n,c){ n[1] = c + n[1]; }; //(sym,code),"0"|"1"
|
||||
a[1].apply2(mc,"0"); b[1].apply2(mc,"1"); // mc(a[1],"0")
|
||||
tree.append( L(a[0]+b[0],a[1].extend(b[1])) ); //(a,b)-->new node
|
||||
}//-->L(L(39, L( L(" ","000"),L("e","0010"),L("a","0011") ...
|
||||
|
||||
tree=tree[0][1].pump(List,fcn(i){ // flatten rather than traverse
|
||||
if(T.isType(i))return(Void.Recurse,i,self.fcn); i });
|
||||
if(T.isType(i))return(Void.Recurse,i,self.fcn); i });
|
||||
encodeTable:=tree.toDictionary(); // symbol:Huffman code
|
||||
decodeTable:=encodeTable.pump(Dictionary(),"reverse"); // code:symbol
|
||||
return(encodeTable,decodeTable);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue