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 {
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;
}
}

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); }
}