Thh
This commit is contained in:
@@ -6,504 +6,537 @@ import tester.Tester;
|
||||
|
||||
class Examples {
|
||||
|
||||
ITree a, b, c, d, e, f, g, h, i, j, o, t, r, u, s, n, v;
|
||||
ITree a, b, c, d, e, f, g, h, i, j, o, t, r, u, s, n, v;
|
||||
|
||||
ArrayList<String> letters;
|
||||
ArrayList<Integer> counts;
|
||||
ArrayList<String> letters;
|
||||
ArrayList<Integer> counts;
|
||||
|
||||
Huffman huff;
|
||||
Huffman huff;
|
||||
|
||||
ArrayList<ITree> trees, treesSomeSorted, treesFirstTwoSorted, treesSame,
|
||||
treesSorted;
|
||||
ArrayList<ITree> trees, treesSomeSorted, treesFirstTwoSorted, treesSame,
|
||||
treesSorted;
|
||||
|
||||
void init() {
|
||||
a = new Leaf(12, "a");
|
||||
b = new Leaf(45, "b");
|
||||
c = new Leaf(5, "c");
|
||||
d = new Leaf(13, "d");
|
||||
e = new Leaf(9, "e");
|
||||
f = new Leaf(16, "f");
|
||||
g = new Leaf(928373743, "f");
|
||||
h = new Leaf(1, "h");
|
||||
i = new Leaf(1, "i");
|
||||
j = new Leaf(1, "j");
|
||||
void init() {
|
||||
a = new Leaf(12, "a");
|
||||
b = new Leaf(45, "b");
|
||||
c = new Leaf(5, "c");
|
||||
d = new Leaf(13, "d");
|
||||
e = new Leaf(9, "e");
|
||||
f = new Leaf(16, "f");
|
||||
g = new Leaf(928373743, "f");
|
||||
h = new Leaf(1, "h");
|
||||
i = new Leaf(1, "i");
|
||||
j = new Leaf(1, "j");
|
||||
|
||||
trees = new ArrayList<ITree>(Arrays.asList(a, b, c, d, e, f));
|
||||
treesSomeSorted = new ArrayList<ITree>(Arrays.asList(e, d, f));
|
||||
treesFirstTwoSorted = new ArrayList<ITree>(Arrays.asList(c, e, b, f));
|
||||
treesSame = new ArrayList<ITree>(Arrays.asList(h, i));
|
||||
treesSorted = new ArrayList<ITree>(Arrays.asList(c, e, a, d, f, b));
|
||||
}
|
||||
trees = new ArrayList<ITree>(Arrays.asList(a, b, c, d, e, f));
|
||||
treesSomeSorted = new ArrayList<ITree>(Arrays.asList(e, d, f));
|
||||
treesFirstTwoSorted = new ArrayList<ITree>(Arrays.asList(c, e, b, f));
|
||||
treesSame = new ArrayList<ITree>(Arrays.asList(h, i));
|
||||
treesSorted = new ArrayList<ITree>(Arrays.asList(c, e, a, d, f, b));
|
||||
}
|
||||
|
||||
void init2() {
|
||||
// jacob itaru signorovitch
|
||||
void init2() {
|
||||
// jacob itaru signorovitch
|
||||
|
||||
letters = new ArrayList<>(Arrays.asList("j", "a", "c", "o", "b", "i", "t",
|
||||
"r", "u", "s", "g", "n", "h", "v"));
|
||||
letters = new ArrayList<>(Arrays.asList(
|
||||
"j", "a", "c", "o", "b", "i", "t", "r", "u", "s", "g", "n", "h", "v"
|
||||
));
|
||||
|
||||
counts = new ArrayList<>(
|
||||
Arrays.asList(1, 2, 2, 3, 1, 3, 2, 2, 1, 1, 1, 1, 1, 1));
|
||||
}
|
||||
counts = new ArrayList<>(
|
||||
Arrays.asList(1, 2, 2, 3, 1, 3, 2, 2, 1, 1, 1, 1, 1, 1)
|
||||
);
|
||||
}
|
||||
|
||||
void init3() {
|
||||
// hello world
|
||||
letters = new ArrayList<>(Arrays.asList("h", "e", "l", "o", "w", "r", "d"));
|
||||
counts = new ArrayList<>(Arrays.asList(1, 1, 3, 2, 1, 1, 1));
|
||||
huff = new Huffman(letters, counts);
|
||||
void init3() {
|
||||
// hello world
|
||||
letters =
|
||||
new ArrayList<>(Arrays.asList("h", "e", "l", "o", "w", "r", "d"));
|
||||
counts = new ArrayList<>(Arrays.asList(1, 1, 3, 2, 1, 1, 1));
|
||||
huff = new Huffman(letters, counts);
|
||||
|
||||
/*
|
||||
( ( ( h or e ) or o ) or ( l or ( d or ( w or r ) ) ) )
|
||||
/*
|
||||
( ( ( h or e ) or o ) or ( l or ( d or ( w or r ) ) ) )
|
||||
|
||||
if you space it out and read it sideways it's like the tree
|
||||
if you space it out and read it sideways it's like the tree
|
||||
|
||||
(
|
||||
(
|
||||
(
|
||||
h
|
||||
(
|
||||
h
|
||||
or
|
||||
e
|
||||
)
|
||||
or
|
||||
e
|
||||
o
|
||||
)
|
||||
or
|
||||
o
|
||||
)
|
||||
or
|
||||
(
|
||||
l
|
||||
or
|
||||
(
|
||||
d
|
||||
l
|
||||
or
|
||||
(
|
||||
w
|
||||
d
|
||||
or
|
||||
r
|
||||
(
|
||||
w
|
||||
or
|
||||
r
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
*/
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void testUtilInsertIntoSorted(Tester t) {
|
||||
init();
|
||||
Util.insertIntoSorted(c, treesSomeSorted);
|
||||
t.checkExpect(treesSomeSorted,
|
||||
new ArrayList<ITree>(Arrays.asList(c, e, d, f)));
|
||||
Util.insertIntoSorted(a, treesSomeSorted);
|
||||
t.checkExpect(treesSomeSorted,
|
||||
new ArrayList<ITree>(Arrays.asList(c, e, a, d, f)));
|
||||
Util.insertIntoSorted(b, treesSomeSorted);
|
||||
t.checkExpect(treesSomeSorted,
|
||||
new ArrayList<ITree>(Arrays.asList(c, e, a, d, f, b)));
|
||||
Util.insertIntoSorted(j, treesSame);
|
||||
t.checkExpect(treesSame, new ArrayList<ITree>(Arrays.asList(h, i, j)));
|
||||
}
|
||||
void testUtilInsertIntoSorted(Tester t) {
|
||||
init();
|
||||
Util.insertIntoSorted(c, treesSomeSorted);
|
||||
t.checkExpect(
|
||||
treesSomeSorted, new ArrayList<ITree>(Arrays.asList(c, e, d, f))
|
||||
);
|
||||
Util.insertIntoSorted(a, treesSomeSorted);
|
||||
t.checkExpect(
|
||||
treesSomeSorted, new ArrayList<ITree>(Arrays.asList(c, e, a, d, f))
|
||||
);
|
||||
Util.insertIntoSorted(b, treesSomeSorted);
|
||||
t.checkExpect(
|
||||
treesSomeSorted,
|
||||
new ArrayList<ITree>(Arrays.asList(c, e, a, d, f, b))
|
||||
);
|
||||
Util.insertIntoSorted(j, treesSame);
|
||||
t.checkExpect(treesSame, new ArrayList<ITree>(Arrays.asList(h, i, j)));
|
||||
}
|
||||
|
||||
void testUtilInsert(Tester t) {
|
||||
init();
|
||||
Util.insert(a, treesFirstTwoSorted, 2);
|
||||
t.checkExpect(treesFirstTwoSorted,
|
||||
new ArrayList<ITree>(Arrays.asList(c, e, a, b, f)));
|
||||
Util.insert(g, treesFirstTwoSorted, 3);
|
||||
t.checkExpect(treesFirstTwoSorted,
|
||||
new ArrayList<ITree>(Arrays.asList(c, e, a, g, b, f)));
|
||||
}
|
||||
void testUtilInsert(Tester t) {
|
||||
init();
|
||||
Util.insert(a, treesFirstTwoSorted, 2);
|
||||
t.checkExpect(
|
||||
treesFirstTwoSorted,
|
||||
new ArrayList<ITree>(Arrays.asList(c, e, a, b, f))
|
||||
);
|
||||
Util.insert(g, treesFirstTwoSorted, 3);
|
||||
t.checkExpect(
|
||||
treesFirstTwoSorted,
|
||||
new ArrayList<ITree>(Arrays.asList(c, e, a, g, b, f))
|
||||
);
|
||||
}
|
||||
|
||||
void testUtilSort(Tester t) {
|
||||
init();
|
||||
ArrayList<ITree> treesSortedCp = treesSorted;
|
||||
void testUtilSort(Tester t) {
|
||||
init();
|
||||
ArrayList<ITree> treesSortedCp = treesSorted;
|
||||
|
||||
Util.sort(treesSortedCp);
|
||||
t.checkExpect(treesSortedCp, treesSorted);
|
||||
Util.sort(treesSortedCp);
|
||||
t.checkExpect(treesSortedCp, treesSorted);
|
||||
|
||||
Util.sort(trees);
|
||||
t.checkExpect(trees, treesSorted);
|
||||
}
|
||||
Util.sort(trees);
|
||||
t.checkExpect(trees, treesSorted);
|
||||
}
|
||||
|
||||
void testUtilEnlist(Tester t) {
|
||||
String s = "Hello";
|
||||
t.checkExpect(Util.enlist(s), new ArrayList<String>(
|
||||
Arrays.asList("H", "e", "l", "l", "o")));
|
||||
void testUtilEnlist(Tester t) {
|
||||
String s = "Hello";
|
||||
t.checkExpect(
|
||||
Util.enlist(s),
|
||||
new ArrayList<String>(Arrays.asList("H", "e", "l", "l", "o"))
|
||||
);
|
||||
|
||||
String s2 = "h";
|
||||
t.checkExpect(Util.enlist(s2), new ArrayList<String>(Arrays.asList("h")));
|
||||
}
|
||||
String s2 = "h";
|
||||
t.checkExpect(
|
||||
Util.enlist(s2), new ArrayList<String>(Arrays.asList("h"))
|
||||
);
|
||||
}
|
||||
|
||||
void testHuffmanMkcode(Tester t) {
|
||||
init();
|
||||
Huffman h = new Huffman(new ArrayList<String>(Arrays.asList("a", "b")),
|
||||
new ArrayList<Integer>(Arrays.asList(1, 1)));
|
||||
void testHuffmanMkcode(Tester t) {
|
||||
init();
|
||||
Huffman h = new Huffman(
|
||||
new ArrayList<String>(Arrays.asList("a", "b")),
|
||||
new ArrayList<Integer>(Arrays.asList(1, 1))
|
||||
);
|
||||
|
||||
t.checkExpect(h.code, new Node(2, new Leaf(1, "a"), new Leaf(1, "b")));
|
||||
t.checkExpect(h.code, new Node(2, new Leaf(1, "a"), new Leaf(1, "b")));
|
||||
|
||||
Huffman h2 = new Huffman(
|
||||
new ArrayList<String>(Arrays.asList("a", "b", "c", "d", "e")),
|
||||
new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5)));
|
||||
Huffman h2 = new Huffman(
|
||||
new ArrayList<String>(Arrays.asList("a", "b", "c", "d", "e")),
|
||||
new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5))
|
||||
);
|
||||
|
||||
// 1: a:1, b:2, c:3, d:4, e:5
|
||||
// 2: (a:1|b:2):3, c:3, d:4, e:5
|
||||
// 3: d:4, e:5, ((a:1|b:2):3|c:3):6
|
||||
// 4: ((a:1|b:2):3|c:3):6, (d:4|e:5):9
|
||||
// 5: (((a:1|b:2):3|:3):6|(d:4|e:5):9):15
|
||||
// 1: a:1, b:2, c:3, d:4, e:5
|
||||
// 2: (a:1|b:2):3, c:3, d:4, e:5
|
||||
// 3: d:4, e:5, ((a:1|b:2):3|c:3):6
|
||||
// 4: ((a:1|b:2):3|c:3):6, (d:4|e:5):9
|
||||
// 5: (((a:1|b:2):3|:3):6|(d:4|e:5):9):15
|
||||
|
||||
t.checkExpect(
|
||||
h2.code,
|
||||
new Node(15,
|
||||
new Node(6, new Leaf(3, "c"),
|
||||
new Node(3, new Leaf(1, "a"), new Leaf(2, "b"))),
|
||||
new Node(9, new Leaf(4, "d"), new Leaf(5, "e"))));
|
||||
}
|
||||
t.checkExpect(
|
||||
h2.code, new Node(
|
||||
15,
|
||||
new Node(
|
||||
6, new Leaf(3, "c"),
|
||||
new Node(3, new Leaf(1, "a"), new Leaf(2, "b"))
|
||||
),
|
||||
new Node(9, new Leaf(4, "d"), new Leaf(5, "e"))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void testHuffmanEncodeAndAlsoDecodeAndAlsoEverythingElse(Tester t) {
|
||||
init3();
|
||||
t.checkExpect(
|
||||
huff.code,
|
||||
new Node(
|
||||
10,
|
||||
new Node(
|
||||
4,
|
||||
new Node(
|
||||
2,
|
||||
new Leaf(1, "h"), // //
|
||||
new Leaf(1, "e")),
|
||||
new Node(
|
||||
2,
|
||||
new Leaf(1, "w"), // //
|
||||
new Leaf(1, "r"))),
|
||||
new Node(
|
||||
6,
|
||||
new Leaf(3, "l"), // //
|
||||
new Node(
|
||||
3,
|
||||
new Leaf(1, "d"), // //
|
||||
new Leaf(2, "o")))));
|
||||
void testHuffmanEncodeAndAlsoDecodeAndAlsoEverythingElse(Tester t) {
|
||||
init3();
|
||||
t.checkExpect(
|
||||
huff.code, new Node(
|
||||
10,
|
||||
new Node(
|
||||
4,
|
||||
new Node(
|
||||
2,
|
||||
new Leaf(
|
||||
1, "h"
|
||||
), // //
|
||||
new Leaf(1, "e")
|
||||
),
|
||||
new Node(
|
||||
2,
|
||||
new Leaf(
|
||||
1, "w"
|
||||
), // //
|
||||
new Leaf(1, "r")
|
||||
)
|
||||
),
|
||||
new Node(
|
||||
6,
|
||||
new Leaf(
|
||||
3, "l"
|
||||
), // //
|
||||
new Node(
|
||||
3,
|
||||
new Leaf(
|
||||
1, "d"
|
||||
), // //
|
||||
new Leaf(2, "o")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
ArrayList<Boolean> path =
|
||||
new ArrayList<>(Arrays.asList(false, false, false));
|
||||
ArrayList<Boolean> path =
|
||||
new ArrayList<>(Arrays.asList(false, false, false));
|
||||
|
||||
ArrayList<Boolean> path2 =
|
||||
new ArrayList<>(Arrays.asList(false, false, false, // h
|
||||
false, false, true, // e
|
||||
true, false, // l
|
||||
true, false, // l
|
||||
true, true, true // o
|
||||
));
|
||||
ArrayList<Boolean> path2 = new ArrayList<>(Arrays.asList(
|
||||
false, false, false, // h
|
||||
false, false, true, // e
|
||||
true, false, // l
|
||||
true, false, // l
|
||||
true, true, true // o
|
||||
));
|
||||
|
||||
ArrayList<Boolean> path3 =
|
||||
new ArrayList<>(Arrays.asList(false, false, false, // h
|
||||
false, false, true, // e
|
||||
true, false, // l
|
||||
true, false, // l
|
||||
true, true, true, // o
|
||||
false, true, false, // w
|
||||
true, true, true, // o
|
||||
false, true, true, // r
|
||||
true, false, // l
|
||||
true, true, false // d
|
||||
));
|
||||
ArrayList<Boolean> path3 = new ArrayList<>(Arrays.asList(
|
||||
false, false, false, // h
|
||||
false, false, true, // e
|
||||
true, false, // l
|
||||
true, false, // l
|
||||
true, true, true, // o
|
||||
false, true, false, // w
|
||||
true, true, true, // o
|
||||
false, true, true, // r
|
||||
true, false, // l
|
||||
true, true, false // d
|
||||
));
|
||||
|
||||
t.checkExpect(huff.encode("h"), path);
|
||||
t.checkExpect(huff.decode(path), "h");
|
||||
t.checkExpect(huff.encode("h"), path);
|
||||
t.checkExpect(huff.decode(path), "h");
|
||||
|
||||
t.checkExpect(huff.encode("hello"), path2);
|
||||
t.checkExpect(huff.decode(path2), "hello");
|
||||
t.checkExpect(huff.encode("hello"), path2);
|
||||
t.checkExpect(huff.decode(path2), "hello");
|
||||
|
||||
t.checkExpect(huff.encode("helloworld"), path3);
|
||||
t.checkExpect(huff.decode(path3), "helloworld");
|
||||
t.checkExpect(huff.encode("helloworld"), path3);
|
||||
t.checkExpect(huff.decode(path3), "helloworld");
|
||||
|
||||
Huffman huff2 = new Huffman("foo bar baz");
|
||||
ArrayList<Boolean> enc = huff2.encode("booz farz fazz");
|
||||
t.checkExpect(huff2.decode(enc), "booz farz fazz");
|
||||
}
|
||||
Huffman huff2 = new Huffman("foo bar baz");
|
||||
ArrayList<Boolean> enc = huff2.encode("booz farz fazz");
|
||||
t.checkExpect(huff2.decode(enc), "booz farz fazz");
|
||||
}
|
||||
}
|
||||
|
||||
class Huffman {
|
||||
|
||||
ArrayList<String> charset; // Character set.
|
||||
ArrayList<Integer> freqs; // Frequencies of characters in charset.
|
||||
ITree code; // The tree allowing for encoding and decoding.
|
||||
ArrayList<ArrayList<Boolean>> map; // Association between the charset and the
|
||||
// path to reach that char in the code.
|
||||
ArrayList<String> charset; // Character set.
|
||||
ArrayList<Integer> freqs; // Frequencies of characters in charset.
|
||||
ITree code; // The tree allowing for encoding and decoding.
|
||||
ArrayList<ArrayList<Boolean>>
|
||||
map; // Association between the charset and the
|
||||
// path to reach that char in the code.
|
||||
|
||||
Huffman(ArrayList<String> charset, ArrayList<Integer> freqs) {
|
||||
if (charset.size() != freqs.size())
|
||||
throw new IllegalArgumentException(
|
||||
"Character set must match frequencies.");
|
||||
Huffman(ArrayList<String> charset, ArrayList<Integer> freqs) {
|
||||
if (charset.size() != freqs.size())
|
||||
throw new IllegalArgumentException(
|
||||
"Character set must match frequencies."
|
||||
);
|
||||
|
||||
if (charset.size() < 2)
|
||||
throw new IllegalArgumentException("Character set too small.");
|
||||
if (charset.size() < 2)
|
||||
throw new IllegalArgumentException("Character set too small.");
|
||||
|
||||
this.charset = charset;
|
||||
this.freqs = freqs;
|
||||
this.charset = charset;
|
||||
this.freqs = freqs;
|
||||
|
||||
this.map = new ArrayList<>();
|
||||
this.map = new ArrayList<>();
|
||||
|
||||
// Generate the code.
|
||||
this.makeCode();
|
||||
// Generate the code.
|
||||
this.makeCode();
|
||||
|
||||
// Generate map.
|
||||
this.makeMap();
|
||||
}
|
||||
|
||||
// Generates character freqs from string.
|
||||
Huffman(String data) {
|
||||
if (data.length() <= 1)
|
||||
throw new Error("Can't create tree from that.");
|
||||
ArrayList<String> charset = new ArrayList<>();
|
||||
ArrayList<Integer> freqs = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
// The current character.
|
||||
String ch = data.substring(i, i + 1);
|
||||
|
||||
if (charset.contains(ch)) {
|
||||
int j = charset.indexOf(ch);
|
||||
freqs.set(j, freqs.get(j) + 1);
|
||||
} else {
|
||||
charset.add(ch);
|
||||
freqs.add(1);
|
||||
}
|
||||
// Generate map.
|
||||
this.makeMap();
|
||||
}
|
||||
|
||||
this.charset = charset;
|
||||
this.freqs = freqs;
|
||||
this.map = new ArrayList<>();
|
||||
// Generates character freqs from string.
|
||||
Huffman(String data) {
|
||||
if (data.length() <= 1) throw new Error("Can't create tree from that.");
|
||||
ArrayList<String> charset = new ArrayList<>();
|
||||
ArrayList<Integer> freqs = new ArrayList<>();
|
||||
|
||||
// Generate the code.
|
||||
this.makeCode();
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
// The current character.
|
||||
String ch = data.substring(i, i + 1);
|
||||
|
||||
// Generate map.
|
||||
this.makeMap();
|
||||
}
|
||||
if (charset.contains(ch)) {
|
||||
int j = charset.indexOf(ch);
|
||||
freqs.set(j, freqs.get(j) + 1);
|
||||
} else {
|
||||
charset.add(ch);
|
||||
freqs.add(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Creates the code tree.
|
||||
void makeCode() {
|
||||
ArrayList<ITree> nodes = new ArrayList<>();
|
||||
this.charset = charset;
|
||||
this.freqs = freqs;
|
||||
this.map = new ArrayList<>();
|
||||
|
||||
// Copy all chars over as a tree leaves.
|
||||
for (int i = 0; i < this.charset.size(); i++)
|
||||
nodes.add(new Leaf(this.freqs.get(i), this.charset.get(i)));
|
||||
// Generate the code.
|
||||
this.makeCode();
|
||||
|
||||
Util.sort(nodes);
|
||||
|
||||
// Combine until all under a single tree.
|
||||
while (nodes.size() > 1) {
|
||||
// Move the 2 lowest into their own tree.
|
||||
ITree firstLowest = nodes.get(0);
|
||||
ITree secondLowest = nodes.get(1);
|
||||
nodes.remove(firstLowest);
|
||||
nodes.remove(secondLowest);
|
||||
ITree parent = new Node(firstLowest.sumFreq(secondLowest), firstLowest,
|
||||
secondLowest);
|
||||
|
||||
// Put new tree into list.
|
||||
Util.insertIntoSorted(parent, nodes);
|
||||
// Generate map.
|
||||
this.makeMap();
|
||||
}
|
||||
|
||||
// Set the code to the first (and hopefully only) tree.
|
||||
this.code = nodes.getFirst();
|
||||
}
|
||||
// Creates the code tree.
|
||||
void makeCode() {
|
||||
ArrayList<ITree> nodes = new ArrayList<>();
|
||||
|
||||
// Make the character path mapping.
|
||||
void makeMap() {
|
||||
for (String ch : this.charset)
|
||||
this.map.addLast(this.code.encode(ch));
|
||||
}
|
||||
// Copy all chars over as a tree leaves.
|
||||
for (int i = 0; i < this.charset.size(); i++)
|
||||
nodes.add(new Leaf(this.freqs.get(i), this.charset.get(i)));
|
||||
|
||||
// Encode a message.
|
||||
ArrayList<Boolean> encode(String s) {
|
||||
Util.sort(nodes);
|
||||
|
||||
ArrayList<String> msg =
|
||||
Util.enlist(s); // The given message, as a list of characters.
|
||||
ArrayList<Boolean> enc = new ArrayList<>(); // The returned encoded message.
|
||||
// Combine until all under a single tree.
|
||||
while (nodes.size() > 1) {
|
||||
// Move the 2 lowest into their own tree.
|
||||
ITree firstLowest = nodes.get(0);
|
||||
ITree secondLowest = nodes.get(1);
|
||||
nodes.remove(firstLowest);
|
||||
nodes.remove(secondLowest);
|
||||
ITree parent = new Node(
|
||||
firstLowest.sumFreq(secondLowest), firstLowest, secondLowest
|
||||
);
|
||||
|
||||
// Loop for each character in the message.
|
||||
for (String ch : msg)
|
||||
enc.addAll(this.encodeCh(ch));
|
||||
// Put new tree into list.
|
||||
Util.insertIntoSorted(parent, nodes);
|
||||
}
|
||||
|
||||
return enc;
|
||||
}
|
||||
// Set the code to the first (and hopefully only) tree.
|
||||
this.code = nodes.getFirst();
|
||||
}
|
||||
|
||||
// Encode a character.
|
||||
ArrayList<Boolean> encodeCh(String ch) {
|
||||
// Throw error if character is not in charset.
|
||||
if (!this.charset.contains(ch))
|
||||
throw new IllegalArgumentException("Cannot encode unknown character \"" +
|
||||
ch + "\".");
|
||||
// Make the character path mapping.
|
||||
void makeMap() {
|
||||
for (String ch : this.charset) this.map.addLast(this.code.encode(ch));
|
||||
}
|
||||
|
||||
int i = this.charset.indexOf(ch);
|
||||
return this.map.get(i);
|
||||
}
|
||||
// Encode a message.
|
||||
ArrayList<Boolean> encode(String s) {
|
||||
|
||||
// Decode a message.
|
||||
String decode(ArrayList<Boolean> enc) { return this.code.follow(enc); }
|
||||
ArrayList<String> msg =
|
||||
Util.enlist(s); // The given message, as a list of characters.
|
||||
ArrayList<Boolean> enc =
|
||||
new ArrayList<>(); // The returned encoded message.
|
||||
|
||||
// Loop for each character in the message.
|
||||
for (String ch : msg) enc.addAll(this.encodeCh(ch));
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
// Encode a character.
|
||||
ArrayList<Boolean> encodeCh(String ch) {
|
||||
// Throw error if character is not in charset.
|
||||
if (!this.charset.contains(ch))
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot encode unknown character \"" + ch + "\"."
|
||||
);
|
||||
|
||||
int i = this.charset.indexOf(ch);
|
||||
return this.map.get(i);
|
||||
}
|
||||
|
||||
// Decode a message.
|
||||
String decode(ArrayList<Boolean> enc) { return this.code.follow(enc); }
|
||||
}
|
||||
|
||||
// Binary tree.
|
||||
interface ITree {
|
||||
// Compare this and another tree, and return the lesser of the two.
|
||||
boolean lessThan(ITree n);
|
||||
// Compare this and another tree, and return the lesser of the two.
|
||||
boolean lessThan(ITree n);
|
||||
|
||||
// Is this tree less than the given frequency?
|
||||
boolean lessThan(int freq);
|
||||
// Is this tree less than the given frequency?
|
||||
boolean lessThan(int freq);
|
||||
|
||||
// Sum the frequency with another tree.
|
||||
int sumFreq(ITree t);
|
||||
int sumFreq(int freq);
|
||||
// Sum the frequency with another tree.
|
||||
int sumFreq(ITree t);
|
||||
int sumFreq(int freq);
|
||||
|
||||
// Encode a character.
|
||||
ArrayList<Boolean> encode(String ch);
|
||||
ArrayList<Boolean> encode(String ch, ArrayList<Boolean> encodingSoFar);
|
||||
// Encode a character.
|
||||
ArrayList<Boolean> encode(String ch);
|
||||
ArrayList<Boolean> encode(String ch, ArrayList<Boolean> encodingSoFar);
|
||||
|
||||
// Follow (decode) a path.
|
||||
String follow(ArrayList<Boolean> path);
|
||||
String followCh(ArrayList<Boolean> path);
|
||||
// Follow (decode) a path.
|
||||
String follow(ArrayList<Boolean> path);
|
||||
String followCh(ArrayList<Boolean> path);
|
||||
}
|
||||
|
||||
abstract class ATree implements ITree {
|
||||
|
||||
int freq; // The frequency of the tree.
|
||||
int freq; // The frequency of the tree.
|
||||
|
||||
ATree(int freq) { this.freq = freq; }
|
||||
ATree(int freq) { this.freq = freq; }
|
||||
|
||||
public boolean lessThan(ITree n) { return n.lessThan(this.freq); }
|
||||
public boolean lessThan(int freq) { return this.freq < freq; }
|
||||
public int sumFreq(ITree t) { return t.sumFreq(this.freq); }
|
||||
public int sumFreq(int freq) { return this.freq + freq; }
|
||||
public boolean lessThan(ITree n) { return n.lessThan(this.freq); }
|
||||
public boolean lessThan(int freq) { return this.freq < freq; }
|
||||
public int sumFreq(ITree t) { return t.sumFreq(this.freq); }
|
||||
public int sumFreq(int freq) { return this.freq + freq; }
|
||||
}
|
||||
|
||||
class Node extends ATree {
|
||||
|
||||
// Left (false) and right (true) branches of tree.
|
||||
ITree l, r;
|
||||
// Left (false) and right (true) branches of tree.
|
||||
ITree l, r;
|
||||
|
||||
Node(int freq, ITree l, ITree r) {
|
||||
super(freq);
|
||||
this.l = l;
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
public ArrayList<Boolean> encode(String ch) {
|
||||
ArrayList<Boolean> ret = new ArrayList<>();
|
||||
ret.addAll(this.l.encode(ch, new ArrayList<>(Arrays.asList(false))));
|
||||
ret.addAll(this.r.encode(ch, new ArrayList<>(Arrays.asList(true))));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ArrayList<Boolean> encode(String ch,
|
||||
ArrayList<Boolean> encodingSoFar) {
|
||||
ArrayList<Boolean> ret = new ArrayList<>(),
|
||||
left = new ArrayList<Boolean>(Arrays.asList(false)),
|
||||
right = new ArrayList<>(Arrays.asList(true));
|
||||
|
||||
left.addAll(0, encodingSoFar);
|
||||
right.addAll(0, encodingSoFar);
|
||||
|
||||
ret.addAll(this.l.encode(ch, left));
|
||||
ret.addAll(this.r.encode(ch, right));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String follow(ArrayList<Boolean> path) {
|
||||
ArrayList<Boolean> pathcpy = path;
|
||||
String ret = "";
|
||||
|
||||
// Each loop is 1 character.
|
||||
while (pathcpy.size() > 0) {
|
||||
Boolean b = pathcpy.getFirst();
|
||||
pathcpy.removeFirst();
|
||||
ret += b ? this.r.followCh(pathcpy) : this.l.followCh(pathcpy);
|
||||
Node(int freq, ITree l, ITree r) {
|
||||
super(freq);
|
||||
this.l = l;
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
public ArrayList<Boolean> encode(String ch) {
|
||||
ArrayList<Boolean> ret = new ArrayList<>();
|
||||
ret.addAll(this.l.encode(ch, new ArrayList<>(Arrays.asList(false))));
|
||||
ret.addAll(this.r.encode(ch, new ArrayList<>(Arrays.asList(true))));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String followCh(ArrayList<Boolean> path) {
|
||||
if (path.size() <= 0)
|
||||
throw new Error("Invalid path.");
|
||||
Boolean b = path.getFirst();
|
||||
path.removeFirst();
|
||||
return b ? this.r.followCh(path) : this.l.followCh(path);
|
||||
}
|
||||
public ArrayList<Boolean>
|
||||
encode(String ch, ArrayList<Boolean> encodingSoFar) {
|
||||
ArrayList<Boolean> ret = new ArrayList<>(),
|
||||
left = new ArrayList<Boolean>(Arrays.asList(false)),
|
||||
right = new ArrayList<>(Arrays.asList(true));
|
||||
|
||||
left.addAll(0, encodingSoFar);
|
||||
right.addAll(0, encodingSoFar);
|
||||
|
||||
ret.addAll(this.l.encode(ch, left));
|
||||
ret.addAll(this.r.encode(ch, right));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String follow(ArrayList<Boolean> path) {
|
||||
ArrayList<Boolean> pathcpy = new ArrayList<>();
|
||||
for (Boolean b : path) pathcpy.add(b);
|
||||
String ret = "";
|
||||
|
||||
// Each loop is 1 character.
|
||||
while (pathcpy.size() > 0) {
|
||||
Boolean b = pathcpy.getFirst();
|
||||
pathcpy.removeFirst();
|
||||
ret += b ? this.r.followCh(pathcpy) : this.l.followCh(pathcpy);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String followCh(ArrayList<Boolean> path) {
|
||||
if (path.size() <= 0) throw new Error("Invalid path.");
|
||||
Boolean b = path.getFirst();
|
||||
path.removeFirst();
|
||||
return b ? this.r.followCh(path) : this.l.followCh(path);
|
||||
}
|
||||
}
|
||||
|
||||
class Leaf extends ATree {
|
||||
|
||||
String ch; // The character.
|
||||
String ch; // The character.
|
||||
|
||||
Leaf(int freq, String ch) {
|
||||
super(freq);
|
||||
this.ch = ch;
|
||||
}
|
||||
Leaf(int freq, String ch) {
|
||||
super(freq);
|
||||
this.ch = ch;
|
||||
}
|
||||
|
||||
public ArrayList<Boolean> encode(String ch) {
|
||||
throw new Error("Can't, fool.");
|
||||
}
|
||||
public ArrayList<Boolean> encode(String ch) {
|
||||
throw new Error("Can't, fool.");
|
||||
}
|
||||
|
||||
public ArrayList<Boolean> encode(String ch,
|
||||
ArrayList<Boolean> encodingSoFar) {
|
||||
if (ch.equals(this.ch))
|
||||
return encodingSoFar;
|
||||
else
|
||||
return new ArrayList<Boolean>();
|
||||
}
|
||||
public ArrayList<Boolean>
|
||||
encode(String ch, ArrayList<Boolean> encodingSoFar) {
|
||||
if (ch.equals(this.ch)) return encodingSoFar;
|
||||
else return new ArrayList<Boolean>();
|
||||
}
|
||||
|
||||
public String follow(ArrayList<Boolean> path) {
|
||||
throw new Error("Shouldn't call follow() on leaf.");
|
||||
}
|
||||
public String followCh(ArrayList<Boolean> path) { return this.ch; }
|
||||
public String follow(ArrayList<Boolean> path, String soFar) {
|
||||
return soFar.concat(this.ch);
|
||||
}
|
||||
public String follow(ArrayList<Boolean> path) {
|
||||
throw new Error("Shouldn't call follow() on leaf.");
|
||||
}
|
||||
public String followCh(ArrayList<Boolean> path) { return this.ch; }
|
||||
public String follow(ArrayList<Boolean> path, String soFar) {
|
||||
return soFar.concat(this.ch);
|
||||
}
|
||||
}
|
||||
|
||||
class Util {
|
||||
|
||||
// Sort a list of trees from least to most frequent.
|
||||
static void sort(ArrayList<ITree> trees) {
|
||||
// Our work here is done.
|
||||
if (trees.size() < 2)
|
||||
return;
|
||||
// Sort a list of trees from least to most frequent.
|
||||
static void sort(ArrayList<ITree> trees) {
|
||||
// Our work here is done.
|
||||
if (trees.size() < 2) return;
|
||||
|
||||
for (int i = 1; i < trees.size(); i++) {
|
||||
// Copy out the tree to insert.
|
||||
ITree tree = trees.get(i);
|
||||
trees.remove(tree);
|
||||
// Insert it.
|
||||
insert(tree, trees, i);
|
||||
for (int i = 1; i < trees.size(); i++) {
|
||||
// Copy out the tree to insert.
|
||||
ITree tree = trees.get(i);
|
||||
trees.remove(tree);
|
||||
// Insert it.
|
||||
insert(tree, trees, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert a Tree into an ArrayList of trees already sorted in [0, i), where
|
||||
// 0 <= i <= trees.size(), such that it is sorted through [0, i].
|
||||
static void insert(ITree tree, ArrayList<ITree> trees, int i) {
|
||||
// Extract sorted.
|
||||
ArrayList<ITree> sorted = new ArrayList<>(trees.subList(0, i));
|
||||
// Insert tree.
|
||||
insertIntoSorted(tree, sorted);
|
||||
// Overwrite original trees with sorted ones.
|
||||
for (int j = 0; j < i; trees.set(j, sorted.get(j++)))
|
||||
;
|
||||
// Insert the last tree back in.
|
||||
trees.add(i, sorted.getLast());
|
||||
}
|
||||
// Insert a Tree into an ArrayList of trees already sorted in [0, i), where
|
||||
// 0 <= i <= trees.size(), such that it is sorted through [0, i].
|
||||
static void insert(ITree tree, ArrayList<ITree> trees, int i) {
|
||||
// Extract sorted.
|
||||
ArrayList<ITree> sorted = new ArrayList<>(trees.subList(0, i));
|
||||
// Insert tree.
|
||||
insertIntoSorted(tree, sorted);
|
||||
// Overwrite original trees with sorted ones.
|
||||
for (int j = 0; j < i; trees.set(j, sorted.get(j++)));
|
||||
// Insert the last tree back in.
|
||||
trees.add(i, sorted.getLast());
|
||||
}
|
||||
|
||||
// Insert a Tree in an already fully sorted ArrayList of Trees.
|
||||
static void insertIntoSorted(ITree tree, ArrayList<ITree> sortedTrees) {
|
||||
for (int i = 0; i < sortedTrees.size(); i++)
|
||||
if (sortedTrees.get(i).lessThan(tree)) {
|
||||
sortedTrees.add(i, tree); //
|
||||
return;
|
||||
}
|
||||
sortedTrees.addLast(tree); // This tree is bigger than all the others.
|
||||
}
|
||||
// Insert a Tree in an already fully sorted ArrayList of Trees.
|
||||
static void insertIntoSorted(ITree tree, ArrayList<ITree> sortedTrees) {
|
||||
for (int i = 0; i < sortedTrees.size(); i++)
|
||||
if (sortedTrees.get(i).lessThan(tree)) {
|
||||
sortedTrees.add(i, tree); //
|
||||
return;
|
||||
}
|
||||
sortedTrees.addLast(tree); // This tree is bigger than all the others.
|
||||
}
|
||||
|
||||
// Convert a string to a list.
|
||||
static ArrayList<String> enlist(String s) {
|
||||
ArrayList<String> ret = new ArrayList<>();
|
||||
for (int i = 0; i < s.length(); ret.add(String.valueOf(s.charAt(i++))))
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
// Convert a string to a list.
|
||||
static ArrayList<String> enlist(String s) {
|
||||
ArrayList<String> ret = new ArrayList<>();
|
||||
for (int i = 0; i < s.length(); ret.add(String.valueOf(s.charAt(i++))));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user