This commit is contained in:
2025-02-01 17:02:24 -05:00
parent 8a264d7dfc
commit 677f82fc8a
6 changed files with 599 additions and 389 deletions

13
.clang-format Normal file
View File

@@ -0,0 +1,13 @@
---
AlignConsecutiveShortCaseStatements:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
IndentCaseLabels: true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLoopsOnASingleLine: true
IndentWidth: 4
PointerAlignment: Left
AlignAfterOpenBracket: BlockIndent

View File

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

28
traversal/.project Normal file
View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>traversal</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<filteredResources>
<filter>
<id>1736900497</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=21

View File

@@ -0,0 +1,123 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Queue;
// a non-empty binary tree
abstract class BT<X> {
X value;
BT(X value) { this.value = value; }
// produce an iterator for the left child, or an empty iterator if one does
// not exist
abstract Iterator<X> leftIterator(DFTIterator<X> f);
// produce an iterator for the right child, or an empty iterator if one does
// not exist
abstract Iterator<X> rightIterator(DFTIterator<X> f);
// add this node's children, if they exist, to the queue (left then right)
abstract void addChildrenToQueue(Queue<BT<X>> queue);
}
class Leaf<X> extends BT<X> {
Iterator<X> leftIterator(DFTIterator<X> f) {
throw new NoSuchElementException();
}
Iterator<X> rigtIterator(DFTIterator<X> f) {
throw new NoSuchElementException();
}
void addChildrenToQueue(Queue<BT<X>> queue) { queue.add(this); }
Leaf(X value) { super(value); }
}
class Node<X> extends BT<X> {
BT<X> left;
BT<X> right;
Node(X value, BT<X> left, BT<X> right) {
super(value);
this.left = left;
this.right = right;
}
Iterator<X> leftIterator(DFTIterator<X> f) {
return this.left.leftIterator(f);
}
Iterator<X> rightIterator(DFTIterator<X> f) {
return this.right.rightIterator(f);
}
void addChildrenToQueue(Queue<BT<X>> queue) {
this.left.addChildrenToQueue(queue);
this.right.addChildrenToQueue(queue);
}
}
// a depth first iterator for a BT
interface DFTIterator<X> extends Iterator<X> {
// produce a depth first traversal iterator for the given BT
DFTIterator<X> iterate(BT<X> x);
}
abstract class DFT<X> implements DFTIterator<X> {
BT<X> bt;
Iterator<X> left;
Iterator<X> right;
// has the top-level value of bt been iterated over yet
boolean nodeGiven;
DFT(BT<X> bt) {
this.bt = bt;
this.left = bt.leftIterator(this);
this.right = bt.rightIterator(this);
}
public boolean hasNext() {
return left.hasNext() || !nodeGiven || right.hasNext();
}
// check that there is a next element, wraps the getNext method
public X next() {
if (!this.hasNext()) { throw new NoSuchElementException(); }
return this.getNext();
}
// actually get the next
abstract X getNext();
}
class InOrder<X> extends DFT<X> {
InOrder(BT<X> bt) { super(bt); }
public DFTIterator<X> iterate(BT<X> x) { return new InOrder<X>(x); }
}
class PreOrder<X> extends DFT<X> {
PreOrder(BT<X> bt) { super(bt); }
public DFTIterator<X> iterate(BT<X> x) { return new PreOrder<X>(x); }
}
class PostOrder<X> extends DFT<X> {
PostOrder(BT<X> bt) { super(bt); }
public DFTIterator<X> iterate(BT<X> x) { return new PostOrder<X>(x); }
}
// a breadth first iterator for a BT
class BFT<X> implements Iterator<X> {
Queue<BT<X>> queue = new LinkedList<BT<X>>();
BFT(BT<X> bt) { queue.add(bt); }
}