Compare commits

...

5 Commits

Author SHA1 Message Date
Wouter Groeneveld d30a8c82da http://www.brainbaking.com/post/pseudocode/ 2018-04-09 15:49:34 +02:00
Wouter Groeneveld 959e23575d deletion btree rest 2018-04-04 17:21:44 +02:00
wgroeneveld 01368089b1 blueprint deletion btrees 2018-04-04 08:25:15 +02:00
wgroeneveld f29428f591 btrees hf18 2018-04-03 15:50:57 +02:00
wgroeneveld bee1b816cd huffman mintree 2018-04-01 10:47:29 +02:00
12 changed files with 1012 additions and 2 deletions

View File

@ -0,0 +1,179 @@
package be.brainbaking.datastructures.trees;
import java.util.List;
import java.util.Optional;
public class BTree {
private Node root;
private final int t;
public BTree(Node node, int t) {
this.root = node;
this.t = t;
}
public BTree(int t) {
this(Node.createRoot(), t);
}
public Node getRoot() {
return root;
}
public void add(String key) {
Node node = root;
if(node.isFull(t)) {
NodeSplitResult splitResult = node.split(t);
Node newNode = Node.createFromSplitResult(node, splitResult);
root = newNode;
insertNonFull(newNode, key);
} else {
insertNonFull(node, key);
}
}
/**
* case 1: if x is a leaf and x has >= t keys, just delete it.
* case 2: if x is an internal node
* a) if x's left child has >= t keys, move the largest key to the key to delete.
* b) if x's right child has >= t keys, move the smallest key to the key to delete.
* c) if none of the children have >= t keys, merge the children and delete the key.
* case 3: if x is a leaf and x has == t - 1 keys, then
* a) if x has a sibling with at least t keys
* - move parent's key -> x
* - find extreme(key) sibling with at least t keys (left/right), move x's key -> parent
* - then proceed as case 1
* b) if x's sibling also has t - 1 keys
* - merge x with sibling: move parent's key -> x (as t key)
* - then delete that key
* @param key
*/
public void delete(String key) {
BTreeSearchResult searchResult = search(key);
if(!searchResult.isFound()) return;
Node node = searchResult.getNode();
Node parent = searchResult.getParent();
if(node.isLeaf() && node.getNumberOfKeys() >= t) { // case 1
node.deleteKey(key);
} else if(node.isLeaf() && node.getNumberOfKeys() == t - 1) { // case 3
List<Node> siblings = parent.getSiblingsOf(node);
Optional<Node> maybeSibling = getSiblingWithTNumberOfKeys(siblings);
if(maybeSibling.isPresent()) {
// 3.a
String parentKeyToPushDown = parent.getKeyBetweenChildren(node, maybeSibling.get());
String extremeKeyToPushUp = maybeSibling.get().getExtremeKeyComparedTo(parentKeyToPushDown);
pushKeyDown(node, parent, parentKeyToPushDown);
pullKeyUp(parent, maybeSibling, extremeKeyToPushUp);
node.deleteKey(key);
} else if(siblings.stream().allMatch(s -> s.getNumberOfKeys() == t - 1)) {
// 3.b
Node rightMostSibling = siblings.stream().filter(s -> s.getNumberOfKeys() == t - 1).reduce((one, two) -> two).get();
node.mergeWith(rightMostSibling);
String parentKeyToPushDown = parent.getKeyBetweenChildren(node, rightMostSibling);
parent.getChildren().remove(rightMostSibling);
pushKeyDown(node, parent, parentKeyToPushDown);
node.deleteKey(key);
}
} else if(!node.isLeaf()) { // case 2
List<Node> children = node.getChildenBetweenKey(key);
Node left = children.get(0);
Node right = children.get(1);
if(left.getNumberOfKeys() >= t) {
// 2.a
switchKeys(node, key, left, left.getLastKey());
left.deleteKey(key);
} else if(right.getNumberOfKeys() >= t) {
// 2.b
switchKeys(node, key, right, right.getFirstKey());
right.deleteKey(key);
} else {
// 2.c
left.mergeWith(right);
node.getChildren().remove(right);
node.deleteKey(key);
}
}
}
private void switchKeys(Node node, String key, Node nodeToSwitch, String keyToSwith) {
node.getKeys().remove(key);
node.addKey(keyToSwith);
nodeToSwitch.getKeys().remove(keyToSwith);
nodeToSwitch.addKey(key);
}
private void pullKeyUp(Node parent, Optional<Node> maybeSibling, String extremeKeyToPushUp) {
maybeSibling.get().getKeys().remove(extremeKeyToPushUp);
parent.addKey(extremeKeyToPushUp);
}
private void pushKeyDown(Node node, Node parent, String parentKeyToPushDown) {
parent.getKeys().remove(parentKeyToPushDown);
node.addKey(parentKeyToPushDown);
}
private Optional<Node> getSiblingWithTNumberOfKeys(List<Node> siblings) {
return siblings.stream().filter(s -> s.getNumberOfKeys() == t).findFirst();
}
private void insertNonFull(Node node, String key) {
if(node.isLeaf()) {
node.addKey(key);
} else {
int i = findRightChildIndexToSearchThrough(node, key);
Node nodeToSeekThrough = node.getChildren().get(i - 1);
if(nodeToSeekThrough.isFull(t)) {
NodeSplitResult splitResult = nodeToSeekThrough.split(t);
node.addChild(i - 1, splitResult.getNewNode());
node.addKey(splitResult.getSplitKey());
if(splitResult.getSplitKey().compareTo(key) > 0) {
i++;
}
}
insertNonFull(node.getChildren().get(i - 1), key);
}
}
private int findRightChildIndexToSearchThrough(Node node, String key) {
int i = node.getNumberOfKeys();
while(i >= 1 && key.compareTo(node.getKeys().get(i - 1)) < 0) {
i--;
}
i++;
return i;
}
public BTreeSearchResult search(String key) {
return searchInNode(root, key, null);
}
private BTreeSearchResult searchInNode(Node node, String key, Node parent) {
int i = 0;
while(i < node.getNumberOfKeys() && key.compareTo(node.getKeys().get(i)) > 0) {
i++;
}
if(i < node.getNumberOfKeys() && key == node.getKeys().get(i)) {
return new BTreeSearchResult(node, i, parent);
}
if(node.isLeaf()) return new BTreeSearchResult();
return searchInNode(node.getChildren().get(i), key, node);
}
}

View File

@ -0,0 +1,35 @@
package be.brainbaking.datastructures.trees;
public class BTreeSearchResult {
private final Node parent;
private final Node node;
private final int index;
public BTreeSearchResult() {
this(null, -1, null);
}
public boolean isFound() {
return node != null;
}
public Node getParent() {
return parent;
}
public BTreeSearchResult(Node node, int index, Node parent) {
this.node = node;
this.parent = parent;
this.index = index;
}
public int getIndex() {
return index;
}
public Node getNode() {
return node;
}
}

View File

@ -0,0 +1,187 @@
package be.brainbaking.datastructures.trees;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Each node has the following fields:
* n[x], the number of keys
* the n[x] keys themselves, stored in nondecreasing order key1[x] <= key2[x] <= ... <= keyn[x]
* leaf[x], a boolean value that is TRUE if x is a leaf and FALSE if x is an internal node
*
* each internal node x also contains n[x] + 1 pointers cn[x] to its children.
* The keys keyi[x] separate the ranges of keys stored in each subtree:
* if ki is any key stored in the subtree with root ci[x], then
* k1 <= key1[x] <= k2 <= key2[x]
*
* All leaves have the same depth, which is the tree's height h.
* There are lower and upper bounds on the number of keys a node can contain. (fixed int, "t" >= 2)
* min. t - 1 keys
* max. 2t - 1 keys: "full"
*/
public class Node {
private boolean leaf;
private List<String> keys;
private List<Node> children;
public boolean isFull(int t) {
return getNumberOfKeys() >= 2* t - 1;
}
public Node(boolean leaf) {
keys = new ArrayList<>();
children = new ArrayList<>();
this.leaf = leaf;
}
/**
* Voegt key gesorteerd toe.
* Dit heb ik enkel voor bepaalde gevallen nodig, maar gebruik ik hier gegeneraliseerd.
* Betekent een performance hit van worst-case O(n[x]) (bvb switchkeys) -> uit context af te leiden waar
* @param key
*/
public void addKey(String key) {
int i;
for(i = 0; i < keys.size(); i++) {
if(keys.get(i).compareTo(key) >= 0) {
break;
}
}
keys.add(i, key);
}
public List<Node> getChildenBetweenKey(String key) {
int keyIndex = keys.indexOf(key);
return Arrays.asList(children.get(keyIndex), children.get(keyIndex + 1)); // kan volgens specs niet crashen, zie def. BTree props
}
public String getKeyBetweenChildren(Node child1, Node child2) {
return keys.get(Math.max(children.indexOf(child1), children.indexOf(child2)) - 1);
}
public String getExtremeKeyComparedTo(String parentKey) {
return parentKey.compareTo(keys.get(0)) < 0 ? keys.get(0) : keys.get(keys.size() - 1);
}
public List<Node> getSiblingsOf(Node child) {
List<Node> siblings = new ArrayList<>();
int index = children.indexOf(child);
if(index > 0) {
siblings.add(children.get(index - 1));
}
if(index < children.size() - 1) {
siblings.add(children.get(index + 1));
}
return siblings;
}
public void mergeWith(Node node) {
if(node.getKeys().get(0).compareTo(getKeys().get(0)) >= 0) {
rightSideMergeWith(node);
} else {
leftSideMergeWith(node);
}
}
private void leftSideMergeWith(Node node) {
keys = Stream.concat(node.keys.stream(), keys.stream()).collect(Collectors.toList());
children = Stream.concat(node.children.stream(), children.stream()).collect(Collectors.toList());
}
private void rightSideMergeWith(Node node) {
keys = Stream.concat(keys.stream(), node.keys.stream()).collect(Collectors.toList());
children = Stream.concat(children.stream(), node.children.stream()).collect(Collectors.toList());
}
public void addChild(Node node) {
addChild(children.size(), node);
}
public void addChild(int index, Node node) {
// dit lijkt mij nog een performance hit te zijn die niet in default in BTrees zit
// ik wou het object-oriented aanpakken maar moet hier dan nog max O(index) aflopen.
children.add(index, node);
}
public NodeSplitResult split(int t) {
if(!isFull(t)) throw new UnsupportedOperationException("node niet vol, split zelf maar wa jong");
Node newNode = new Node(isLeaf());
for(int i = 0; i < t - 1; i++) {
newNode.addKey(keys.get(i + t));
}
// n[x] = aantal sleutels = size(c[x]) - 1; er zijn altijd n[x] + 1 kinderen
if(!isLeaf()) {
for(int i = 0; i < t; i++) {
newNode.children.add(children.get(i + t - 1));
}
}
List<String> newKeys = new ArrayList<>();
for(int i = 0; i < t - 1; i++) {
newKeys.add(keys.get(i));
}
String key = keys.get(t - 1);
keys = newKeys;
if(!isLeaf()) {
List<Node> newChildren = new ArrayList<>();
for(int i = 0; i < t; i++) {
newChildren.add(children.get(i));
}
children = newChildren;
}
return new NodeSplitResult(newNode, key);
}
public static Node createRoot() {
return new Node(true);
}
public int getNumberOfKeys() {
return keys.size();
}
public List<Node> getChildren() {
return children;
}
public String getLastKey() {
return keys.get(getNumberOfKeys() - 1);
}
public String getFirstKey() {
return keys.get(0);
}
public List<String> getKeys() {
return keys;
}
public boolean isLeaf() {
return leaf;
}
public static Node createFromSplitResult(Node node, NodeSplitResult splitResult) {
Node root = new Node(false);
root.addKey(splitResult.getSplitKey());
root.addChild(node);
root.addChild(splitResult.getNewNode());
return root;
}
public void deleteKey(String key) {
keys.remove(key);
}
}

View File

@ -0,0 +1,20 @@
package be.brainbaking.datastructures.trees;
public class NodeSplitResult {
private final Node newNode;
private final String splitKey;
public Node getNewNode() {
return newNode;
}
public String getSplitKey() {
return splitKey;
}
public NodeSplitResult(Node newNode, String splitKey) {
this.newNode = newNode;
this.splitKey = splitKey;
}
}

View File

@ -0,0 +1,260 @@
package be.brainbaking.datastructures.trees;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
// deletion examples: https://www.youtube.com/watch?v=fKubKYzwDl0 - cases omgekeerde van p451
public class BTreeTest {
@Test
public void deleteCase1() {
Node root = new Node(false);
root.addKey("D");
root.addKey("G");
Node child1 = new Node(true);
child1.addKey("A");
child1.addKey("B");
child1.addKey("C");
Node child2 = new Node(true);
child2.addKey("E");
child2.addKey("F");
Node child3 = new Node(true);
child3.addKey("H");
child3.addKey("I");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("B");
assertArrayEquals(Arrays.asList("A", "C").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
}
@Test
public void deleteCase2A() {
Node root = new Node(false);
root.addKey("Q");
root.addKey("U");
Node child1 = new Node(true);
child1.addKey("O");
child1.addKey("P");
Node child2 = new Node(true);
child2.addKey("R");
child2.addKey("S");
child2.addKey("T");
Node child3 = new Node(true);
child3.addKey("W");
child3.addKey("X");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("U");
assertArrayEquals(Arrays.asList("Q", "T").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("O", "P").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("R", "S").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
assertArrayEquals(Arrays.asList("W", "X").toArray(), tree.getRoot().getChildren().get(2).getKeys().toArray());
}
@Test
public void deleteCase2B() {
Node root = new Node(false);
root.addKey("I");
root.addKey("M");
Node child1 = new Node(true);
child1.addKey("G");
child1.addKey("H");
Node child2 = new Node(true);
child2.addKey("J");
child2.addKey("K");
child2.addKey("L");
Node child3 = new Node(true);
child3.addKey("O");
child3.addKey("P");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("I");
assertArrayEquals(Arrays.asList("J", "M").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("G", "H").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("K", "L").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
assertArrayEquals(Arrays.asList("O", "P").toArray(), tree.getRoot().getChildren().get(2).getKeys().toArray());
}
@Test
public void deleteCase2C() {
Node root = new Node(false);
root.addKey("R");
root.addKey("U");
root.addKey("X");
Node child1 = new Node(true);
child1.addKey("P");
child1.addKey("Q");
Node child2 = new Node(true);
child2.addKey("S");
child2.addKey("T");
Node child3 = new Node(true);
child3.addKey("V");
child3.addKey("W");
Node child4 = new Node(true);
child4.addKey("Y");
child4.addKey("Z");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
root.addChild(child4);
BTree tree = new BTree(root, 3);
tree.delete("U");
assertArrayEquals(Arrays.asList("R", "X").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("P", "Q").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("S", "T", "V", "W").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
assertArrayEquals(Arrays.asList("Y", "Z").toArray(), tree.getRoot().getChildren().get(2).getKeys().toArray());
}
@Test
public void deleteCase3A() {
Node root = new Node(false);
root.addKey("J");
root.addKey("M");
Node child1 = new Node(true);
child1.addKey("G");
child1.addKey("H");
Node child2 = new Node(true);
child2.addKey("K");
child2.addKey("L");
Node child3 = new Node(true);
child3.addKey("O");
child3.addKey("P");
child3.addKey("R");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("L");
assertArrayEquals(Arrays.asList("J", "O").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("K", "M").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
}
@Test
public void deleteCase3B() {
Node root = new Node(false);
root.addKey("Q");
root.addKey("T");
Node child1 = new Node(true);
child1.addKey("O");
child1.addKey("P");
Node child2 = new Node(true);
child2.addKey("R");
child2.addKey("S");
Node child3 = new Node(true);
child3.addKey("W");
child3.addKey("X");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
BTree tree = new BTree(root, 3);
tree.delete("S");
assertArrayEquals(Arrays.asList("Q").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("O", "P").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("R", "T", "W", "X").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
}
@Test
public void searching_afterAddingExampleAndHavingToSplit() {
BTree tree = new BTree(4);
tree.add("A");
tree.add("D");
tree.add("F");
tree.add("H");
tree.add("L");
tree.add("N");
tree.add("P");
tree.add("Q");
assertEquals(1, tree.search("D").getIndex());
assertEquals(0, tree.search("H").getIndex()); // want die key is naar boven verhuisd bij splitten
assertEquals(2, tree.search("P").getIndex());
assertEquals(3, tree.search("Q").getIndex());
}
@Test
public void addingOnly() {
BTree tree = new BTree(4);
tree.add("A");
tree.add("D");
tree.add("F");
tree.add("H");
tree.add("L");
tree.add("N");
tree.add("P");
// nog eentje toevoegen zou moeten splitsen (4*2 groot)
tree.add("Q");
assertArrayEquals(Arrays.asList("H").toArray(), tree.getRoot().getKeys().toArray());
assertArrayEquals(Arrays.asList("A", "D", "F").toArray(), tree.getRoot().getChildren().get(0).getKeys().toArray());
assertArrayEquals(Arrays.asList("L", "N", "P", "Q").toArray(), tree.getRoot().getChildren().get(1).getKeys().toArray());
}
@Test
public void simpleOperations_addAndSearch() {
BTree tree = new BTree(5);
tree.add("key1");
BTreeSearchResult result = tree.search("key1");
assertEquals(true, result.isFound());
}
@Test
public void simpleOperations_searchKeyNotFound() {
BTree tree = new BTree(5);
tree.add("key100");
BTreeSearchResult result = tree.search("key1");
assertEquals(false, result.isFound());
}
}

View File

@ -0,0 +1,147 @@
package be.brainbaking.datastructures.trees;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
public class NodeTest {
@Test
public void merge_addsKeysAndChildren() {
Node child = new Node(true);
child.addKey("I");
Node node = new Node(false);
node.addKey("G");
node.addKey("H");
node.addChild(new Node(true));
Node siblingToMergeWith = new Node(false);
siblingToMergeWith.addKey("K");
siblingToMergeWith.addKey("L");
Node siblingChild = new Node(true);
siblingChild.addKey("X");
siblingToMergeWith.addChild(siblingChild);
node.mergeWith(siblingToMergeWith);
assertArrayEquals(Arrays.asList("G", "H", "K", "L").toArray(), node.getKeys().toArray());
assertEquals(2, node.getChildren().size());
}
@Test
public void getKeyBetweenChildren_basedOnChildIndex() {
Node parent = new Node(false);
parent.addKey("J");
parent.addKey("M");
Node child1 = new Node(true);
child1.addKey("G");
child1.addKey("H");
parent.addChild(child1);
Node child2 = new Node(true);
child2.addKey("K");
child2.addKey("L");
parent.addChild(child2);
Node child3 = new Node(true);
child3.addKey("O");
child3.addKey("P");
child3.addKey("R");
parent.addChild(child3);
assertEquals("J", parent.getKeyBetweenChildren(child1, child2));
assertEquals("M", parent.getKeyBetweenChildren(child2, child3));
}
@Test
public void getExtremeKey_returnsFirstKeyBiggerThanParentKey_leftSide() {
Node parent = new Node(false);
parent.addKey("J");
parent.addKey("M");
Node child = new Node(true);
child.addKey("O");
child.addKey("P");
child.addKey("R");
parent.addChild(child);
assertEquals("O", child.getExtremeKeyComparedTo("M"));
}
@Test
public void getExtremeKey_returnsLastKeySmallerThanParentKey_rightSide() {
Node parent = new Node(false);
parent.addKey("J");
parent.addKey("M");
Node child = new Node(true);
child.addKey("K");
child.addKey("L");
parent.addChild(child);
assertEquals("L", child.getExtremeKeyComparedTo("M"));
}
@Test
public void createFromSplitResult_nodeALeftAndBRight() {
Node root = new Node(false);
root.addKey("R");
Node node = new Node(true);
node.addKey("A");
NodeSplitResult result = new NodeSplitResult(node, "B");
Node newRoot = Node.createFromSplitResult(root, result);
assertSame(root, newRoot.getChildren().get(0));
assertSame(node, newRoot.getChildren().get(1));
}
@Test
public void addKey_addsToCorrectPositionAutomatically() {
Node node = new Node(true);
node.addKey("A");
node.addKey("C");
node.addKey("B");
assertArrayEquals(Arrays.asList("A", "B", "C").toArray(), node.getKeys().toArray());
}
@Test
public void split() {
Node node = new Node(false);
Node child = new Node(true);
node.addChild(child);
node.addKey("N");
node.addKey("W");
child.addKey("P");
child.addChild(new Node(true));
child.addKey("Q");
child.addChild(new Node(true));
child.addKey("R");
child.addChild(new Node(true));
child.addKey("S");
child.addChild(new Node(true));
child.addKey("T");
child.addChild(new Node(true));
child.addKey("U");
child.addChild(new Node(true));
child.addKey("V");
child.addChild(new Node(true));
NodeSplitResult result = child.split(4);
assertEquals(3, result.getNewNode().getNumberOfKeys());
assertEquals(3, child.getNumberOfKeys());
assertEquals("S", result.getSplitKey());
assertArrayEquals(Arrays.asList("P", "Q", "R").toArray(), child.getKeys().toArray());
assertArrayEquals(Arrays.asList("T", "U", "V").toArray(), result.getNewNode().getKeys().toArray());
}
}

View File

@ -0,0 +1,72 @@
package com.com.brainbaking.greedy;
import java.util.*;
import java.util.stream.Collectors;
public class Huffman {
private final String toEncode;
private final Node root;
public Huffman(String toEncode) {
this.toEncode = toEncode;
root = buildMinRoot(buildQueue());
}
private Node buildMinRoot(Queue<Node> nodes) {
Node root = null;
while(nodes.size() > 1) {
Node first = nodes.poll();
Node second = nodes.poll();
root = new Node(first, second);
nodes.add(root);
}
// in geval van maar 1 karakter
return root == null ? nodes.poll() : root;
}
private Queue<Node> buildQueue() {
Set<Integer> chars = buildCharSet();
Queue<Node> tree = new PriorityQueue<>();
for(Integer character : chars) {
int frequency = (int) toEncode.chars().filter(c -> c == character).count();
tree.add(new Node(character, frequency));
}
return tree;
}
private Set<Integer> buildCharSet() {
return toEncode.chars().boxed().collect(Collectors.toSet());
}
public String encode() {
Map<Character, String> encodeMap = new HashMap<>();
buildEncodedMap(root, encodeMap, "");
String encoded = "";
for(int i = 0; i < toEncode.length(); i++) {
encoded += encodeMap.get(toEncode.charAt(i));
}
return encoded;
// wat is hier mis mee?
//return toEncode.chars().mapToObj(c -> encodeMap.get(c)).collect(Collectors.joining());
}
private void buildEncodedMap(Node node, Map<Character,String> map, String encoded) {
if(node.isRoot()) {
// in geval van maar 1 karakter
map.put(node.getCharacter(), encoded.equals("") ? "0" : encoded);
return;
}
buildEncodedMap(node.getLeft(), map, encoded + "0");
buildEncodedMap(node.getRight(), map, encoded + "1");
}
}

View File

@ -0,0 +1,47 @@
package com.com.brainbaking.greedy;
public class Node implements Comparable<Node> {
private final char character;
private final int frequency;
private Node left;
private Node right;
public boolean isRoot() {
return left == null && right == null;
}
public Node getLeft() {
return left;
}
public Node getRight() {
return right;
}
public char getCharacter() {
return character;
}
public int getFrequency() {
return frequency;
}
public Node(Node left, Node right) {
this.left = left;
this.right = right;
this.character = '-';
this.frequency = left.getFrequency() + right.getFrequency();
}
public Node(Integer character, int frequency) {
this.character = (char) character.intValue();
this.frequency = frequency;
}
@Override
public int compareTo(Node o) {
return frequency - o.frequency;
}
}

View File

@ -0,0 +1,36 @@
package com.brainbaking.greedy;
import com.com.brainbaking.greedy.Huffman;
import org.junit.Test;
import static junit.framework.TestCase.assertEquals;
public class HuffmanTest {
@Test
public void huffman_OnlyOnCharacter() {
Huffman huffman = new Huffman("aaa");
String result = huffman.encode();
assertEquals("000", result);
}
@Test
public void huffman_charAFrequences5TimesButBAndCOnlyOnce() {
Huffman huffman = new Huffman("baaaaac");
String result = huffman.encode();
assertEquals("001111101", result);
}
@Test
public void huffmanEncoded() {
Huffman huffman = new Huffman("hallo dit is een test wasda jong");
String result = huffman.encode();
assertEquals("110001101100110011000111101110100101111010000111001001011011101000100001011111001110100010111101111011111000011001110", result);
}
}

View File

@ -5,6 +5,10 @@ import java.util.stream.Collectors;
public class Lists {
public static ListsWrapper exchange(int oneBasedA) {
return new ListsWrapper(oneBasedA);
}
public static void swap(List<Integer> list, int oneBasedA, int oneBasedB) {
int temp = list.get(oneBasedA - 1);
list.set(oneBasedA - 1, list.get(oneBasedB - 1));

View File

@ -0,0 +1,22 @@
package be.brainbaking.lists;
import java.util.List;
public class ListsWrapper {
private final int oneBasedA;
private int oneBasedB;
public ListsWrapper with(int oneBasedB) {
this.oneBasedB = oneBasedB;
return this;
}
public void in(List<Integer> list) {
Lists.swap(list, oneBasedA, oneBasedB);
}
public ListsWrapper(int oneBasedA) {
this.oneBasedA = oneBasedA;
}
}

View File

@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.List;
import static be.brainbaking.lists.Lists.asString;
import static be.brainbaking.lists.Lists.exchange;
public class QuickSort implements Sortable {
@ -68,11 +69,11 @@ public class QuickSort implements Sortable {
for(int j = oneBasedStartIndex; j <= oneBasedEndIndex - 1; j++) {
if(list.get(j - 1) <= x) {
i++;
Lists.swap(list, i, j);
exchange(i).with(j).in(list);
}
}
Lists.swap(list, i + 1, oneBasedEndIndex);
exchange(i + 1).with(oneBasedEndIndex).in(list);
System.out.println("partitioned: " + asString(list));
return i + 1;
}