I am attempting to use the functionality of Binary Search Trees without actually create Node objects and giving them left/right children and instead using the basic idea of a Binary Search Tree within three parallel arrays: left, data, and right. At a particular index in these arrays, left holds the index to data where the current data's left child lives, while right holds the index to data where the current data's right child lives. This table gives a better example of what I am talking about:
The -1 values represent where a node does not have a left or right child. Before any nodes are inserted, all of the arrays hold the value 0, and every time a node is inserted, its left and right children index values are set to -1 (indicating that what we just inserted is a leaf). What I'm struggling to figure out is to how to do this recursively without accidentally accessing an index of -1. My current attempt seen below is running into this issue:
public void insert(int d) {
//PRE: the tree is not full
//if d is not in the tree insert d otherwise the tree does not change
if(root == -1) {
root = d;
}
insert(d, 0);
}
private void insert(int d, int index) {
if(data[index] == d) {
return;
}
if(data[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
}
if(data[index] > d) {
if(left[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
} else {
insert(d, left[index]);
}
}
if(data[index] < d) {
if(right[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
} else {
insert(d, right[index]);
}
}
return;
}
I'm curious for ideas as to how I can prevent from accessing an array with index value -1, while still being able to indicate that a node does not have a child to a particular side.
I understand the concept that every time I'm inserting a node, I'm inserting a leaf, so when a node is placed at a particular index, its left and right can automatically be set to -1, but my current recursive calls end up passing in -1 at one point or another. Even if I change this value to 0, or something else, that doesn't necessarily help me make any progress in my recursion.
Some remarks on your code:
The root variable should not be assigned d, but the index where d will be stored, only then does it make sense that an empty tree is encoded with root equal to -1 (realise that d could be -1).
Your code has no logic to determine at which index to store a new node. This is really your question. A simple solution is to maintain a size variable. This is then the index at which the next node will be stored, after which the size member should be incremented.
There is then never a reason to think of 0 as some special indicator, and your code should only check for -1 references, not 0.
You have some code repetition which you can avoid by creating a method that will "create" a node: it will use size for its index, and will take a value as argument.
Here is the suggested code:
class BinaryTree {
public static final int MAXSIZE = 100;
int left[] = new int[BinaryTree.MAXSIZE];
int right[] = new int[BinaryTree.MAXSIZE];
int data[] = new int[BinaryTree.MAXSIZE];
int root = -1;
int size = 0;
private int createNode(int value) {
data[size] = value;
left[size] = -1;
right[size] = -1;
return size++;
}
public void insert(int value) {
if (root == -1) {
root = createNode(value);
} else {
insert(value, 0);
}
}
private void insert(int value, int index) {
if (data[index] == value) {
return;
}
if (data[index] > value) {
if (left[index] == -1) {
left[index] = createNode(value);
} else {
insert(value, left[index]);
}
} else {
if (right[index] == -1) {
right[index] = createNode(value);
} else {
insert(value, right[index]);
}
}
return;
}
}
This code can be further extended with:
verification that the tree has reached a maximum size,
node deletion
"memory management" for reusing the indexes of deleted nodes (by maintaining a "free list")
self-balancing (like AVL or red-black tree)
Doing the "memory management" (array slot management) yourself is really going to mimic the powerful heap memory management that Java offers out of the box when using class instances. For that reason I would advise to implement a tree the OOP way.
Related
So I am trying to pick out the farthest node for each iteration. I start by randomly picking the first node, then continueing by picking the farthest node from the first one.
From there I have two nodes which I want to compare in distance (I am using the euclidean metric) with the rest of the nodes. Then I add the one that is farthest away over both already picked nodes and continue this process, until I have chosen k nodes.
Node maxDistNode = null;
k = k - pickedNodes.size(); //in this case pickedNodes has 2 entries already
while(k > 0) {
for(Node pickedN: pickedNodes) {
for(Node notpickedN: allNodes) {
if(notpickedN.distance < distanceBetween(notpickedN, pickedN)) { //distanceBetween(Node a, Node b) is method that returns Math.hypot(a.x - b.x, a.x - b.x)
notpickedN.distance = distanceBetween(notpickedN, pickedN);
}
}
maxDistNode = Collections.max(allNodes, new Comparator<Node>() {
#Override
public int compare(Node o1, Node o2) {
if(o1.distance > o2.distance) {
return 1;
}
if(o1.distance == o2.distance) {
return 0;
}
return -1;
}
});
}
if(maxDistNode != null) {
maxDistNode.setPicked(true);
pickedNodes.add(maxDistNode);
allNodes.remove(maxDistNode);
--k;
}
}
Nodes have initially a distance of Integer.MIN_VALUE given. Now the problem is, that this works fine for when k is very small, though when ever I want to search for more nodes this will give me the same one for k-times. Therefore I am left with many duplicate nodes.
How can I change this so I can get the farthest node over all newly added and old pickNodes?
I have this method and it should show on the screen the smallest n Elements in BST,
Example n=3, the smallest 3 elements and so on..
Unfortunately at running, it shows that its reaching an Empty content and gets shut down. Further notes, the method should give and int back and its not void, but I couldn't find another way to show all the Elements, because return type int will give just one Element? right?
public int sorteduptp(int n) {
if (n > 0 && !isEmpty()) {
BinarySearchTree current = this;
while (!current.leftChild.isEmpty() && current.size() != n) {
current = current.leftChild;
}
if (n == 1) {
System.out.println(current.leftChild.getContent());
return 0;
} else {
sorteduptp(n - 1);
while (!current.isLeaf()) {
System.out.println(current.getContent());
System.out.println(current.rightChild);
}
System.out.println(current.getContent());
}
}
}
It seems that the current = current.leftChild; will never get used in the recursive step because current = this will set current to the top of the tree. So you might want add that as parameter and initially pass this.
For the return, you can make it as array of integers like int[] or an ArrayList. Those can hold more than one values.
I am totally stuck on this problem. I need to output the position of a value in an inorder list (First index 0). The caveat is that I can't create the list and search through it. For each node I have a variable that contains information about how many nodes are in any given tree (including the root). I have it working for about 50% of the cases but the rest fail in hard to understand ways... If the value doesn't exist i need to return the index where it would have been.
In the class Tree
public int position(int val) {
if (this.isEmpty()){
return 0;
}
if (val == root.key){
return (root.subNodes - root.rightchild.subNodes) - 1;
}
if (val < root.key){
return root.position(0,root.subNodes - 1,val,root);
} else {
return (root.subNodes - root.rightchild.subNodes) +root.position(0,root.subNodes - 1,val,root.rightchild);
}
}
In the class node
int position(int min, int max, int k, Node n){
if (k == n.key){
if (n.rightchild != null){
return n.subNodes - (n.rightchild.subNodes);
}
return max;
}
if (n.rightchild == null && n.leftchild == null){
return 1;
}
if (k < n.key){
return position(min ,n.leftchild.subNodes - 1, k, n.leftchild);
}
if (k > n.key && n.rightchild != null){
return position(n.subNodes - (n.rightchild.subNodes + 1), n.subNodes - 1, k, n.rightchild);
}
return max;
}
The Idea:
You can do an in order traversal of the tree and keep track of the number of nodes you have visited. This requires a counter of some sort and probably a helper method.
We stop searching when we find a node with a value greater than or equal to the desired value. This is because we either found the index of the desired value or the index of where the desired value would go (the desired value wouldn't go in any earlier or later indexes). If we never find a node equal or greater than desired value, then the desired value would go at the end of the tree, which has a position equal to the count of nodes.
The Implementation:
Imagine you have this Node
public class Node {
int value;
Node leftChild;
Node rightChild;
// Getters and Setters
}
And this Tree
public class Tree {
Node root;
// Getters and Setters
}
Inside of Tree
public int position(int val) {
positionHelper(val, root, 0);
}
public int positionHelper(int val, Node currentNode, int steps) {
// In-order search checks left node, then current node, then right node
if(currentNode.getLeftChild() != null) {
steps = positionHelper(val, currentNode.getLeftChild(), steps++);
}
// We found the node or have already moved over the node, return current steps
if(currentNode.getValue() >= val) {
return steps;
}
// Next Node Index
steps++;
if(currentNode.getRightChild() != null) {
steps = positionHelper(val, currentNode.getRightChild(), steps++);
}
return steps;
}
Let me know if it has any issues or there are any questions
I have a binary search tree where i have to implement a method called
int valueAtPosition(int x)
The problem is, that i need the position in an in order traversal.
To find the in order traversal i have this the following code, but i don't know how i count the recursive calls, to get the right position.
public void inOrderTraverseTree(Node root){
if(root != null){
inOrderTraverseTree(root.leftChild);
System.out.println(root);
inOrderTraverseTree(root.rightChild);
}
}
I think the other solutions are O(n). All you need for this is a count of the children for each node for O(log n).
When you insert a node, for each node you traverse you increase the counter on the traversed node by one.
You need to maintain these counters when deleting, rebalancing, etc which normally isn't difficult.
With this you can get the position of the node when inserted, find the position of a node by value or find a node by position.
To find a node by position is the same kind of binary traversal as for finding by value. If you want the item at position 1000 then you start at the root. No root, not item at that position. Then you look at the left child (you can do it in the other order too and switch ascending/descending), on the left if the left child exists the number of children on the left is 0 plus the count of the children on the left node. Let say in this scenario that the left exists and has 500 children. Then you know 1000 can't be left because there aren't enough items on the left, so it must be right. You can repeat this also checking for bounds all the way down.
For simple O(n) in order traversal if you have a global counter you just increase it only after traversing the left. That should do the same as a depth first search. No need for decreasing and increasing counters or pushing and popping on a stack. You can also have your functions return a count.
public int inOrderTraverseTree(Node root){
if(root == null)
return 0;
int count = inOrderTraverseTree(root.leftChild);
count++;
count += inOrderTraverseTree(root.rightChild);
return count;
}
This approach only becomes annoying if you want to return the node as well.
You can of course replace a recursive function with your own stack but this is a rarely needed performance optimisation and you'll be far better off with the O(log n) solution if you need performance than an optimised custom stack based solution.
You can also use a counter in the recursive approach. However, you can't simply pass an int counter argument - you need all calls to see the "same" counter, so you will have to wrap it in a class (or, as in this case, an inner class):
public static class Counter {
private int value;
public Counter(int initialValue) { value = initialValue; }
public boolean decrement() { value--; return value == 0; }
public boolean expired() { return value <= 0; }
}
public Node inOrderTraverseTree(Node root, Counter counter){
if (root != null && ! counter.expired()) {
Node left = inOrderTraverseTree(root.leftChild, counter);
if (left != null) {
return left;
} else if (counter.decrement()) {
return root;
} else {
return inOrderTraverseTree(root.rightChild, counter);
}
} else {
return null;
}
}
To find the 9th node in-order (using 1-based indexing), you would call this as
Node the9th = inOrderTraverseTree(root, new Counter(9));
If there is no 9th node, it would return null. If you want to use 0-based indexing instead, change { value--; return value == 0; } to { return value-- == 0; }
The iterative in-order traversal approach makes this pretty easy. Increment a counter whenever a node is popped from the stack. When the counter is equal to x, return the value of the node.
Integer valueAtPosition(int x, Node root) {
int count = 0;
List<Node> stack = new ArrayList<>();
Node node = root;
while (!stack.isEmpty() || node != null) {
if (node != null) {
stack.add(node);
node = node.leftChild;
} else {
node = stack.pop();
if (count == x) {
return node.value;
}
count++;
node = node.rightChild;
}
}
return null;
}
Recursive version requires passing a mutable wrapper for a counter like so:
public class Counter {
int count = 0;
}
public void inOrderTraverseTree(Node root, int index, Counter counter){
if(root == null || counter.count > index) {
return;
}
inOrderTraverseTree(root.leftChild);
if (counter.count == index) {
System.out.println(root);
}
counter.count = counter.count + 1;
inOrderTraverseTree(root.rightChild);
}
Following is recursive in-order traversal approach: (in c++)
bool valueAtPositionUtil(struct treeNode *root, int &currIndex, int i, int &value) {
if(root != NULL) {
if(valueAtPositionUtil(root->left, currIndex, i, value)) {
return true;
}
if(currIndex == i) {
value = root->data;
return true;
}
currIndex++;
if(valueAtPositionUtil(root->right, currIndex, i, value)) {
return true;
}
}
return false;
}
int ValueAtPosition(int i, struct treeNode *root) {
int value = 0;
int currIndex = 0;
if(valueAtPositionUtil(root, currIndex, i, value)) {
return value;
}
//index out of bound
// you can return according your problem
return -1;
}
I am using array based MinHeap in java. I am trying to create a custom method which can remove any element not only root from the heap but couldn't. Below is MinHeap code-
public class MinHeap {
/** Fixed-size array based heap representation */
private int[] h;
/** Number of nodes in the heap (h) */
private int n = 0;
/** Constructs a heap of specified size */
public MinHeap(final int size) {
h = new int[size];
}
/** Returns (without removing) the smallest (min) element from the heap. */
public int peek() {
if (isEmpty()) {
throw new RuntimeException("Heap is empty!");
}
return h[0];
}
/** Removes and returns the smallest (min) element from the heap. */
public int poll() {
if (isEmpty()) {
throw new RuntimeException("Heap is empty!");
}
final int min = h[0];
h[0] = h[n - 1];
if (--n > 0)
siftDown(0);
return min;
}
/** Checks if the heap is empty. */
public boolean isEmpty() {
return n == 0;
}
/** Adds a new element to the heap and sifts up/down accordingly. */
public void add(final int value) {
if (n == h.length) {
throw new RuntimeException("Heap is full!");
}
h[n] = value;
siftUp(n);
n++;
}
/**
* Sift up to make sure the heap property is not broken. This method is used
* when a new element is added to the heap and we need to make sure that it
* is at the right spot.
*/
private void siftUp(final int index) {
if (index > 0) {
final int parent = (index - 1) / 2;
if (h[parent] > h[index]) {
swap(parent, index);
siftUp(parent);
}
}
}
/**
* Sift down to make sure that the heap property is not broken This method
* is used when removing the min element, and we need to make sure that the
* replacing element is at the right spot.
*/
private void siftDown(int index) {
final int leftChild = 2 * index + 1;
final int rightChild = 2 * index + 2;
// Check if the children are outside the h bounds.
if (rightChild >= n && leftChild >= n)
return;
// Determine the smallest child out of the left and right children.
final int smallestChild = h[rightChild] > h[leftChild] ? leftChild
: rightChild;
if (h[index] > h[smallestChild]) {
swap(smallestChild, index);
siftDown(smallestChild);
}
}
/** Helper method for swapping h elements */
private void swap(int a, int b) {
int temp = h[a];
h[a] = h[b];
h[b] = temp;
}
/** Returns the size of heap. */
public int size() {
return n;
}
}
How can i design a method to remove any element from this MinHeap?
If you know the index of the element to be removed,
private void removeAt(int where) {
// This should never happen, you should ensure to call it only with valid indices
if (n == 0) throw new IllegalArgumentException("Trying to delete from empty heap");
if (where >= n) throw new IllegalArgumentException("Informative error message");
// Now for the working cases
if (where == n-1) {
// removing the final leaf, trivial
--n;
return;
}
// other nodes
// place last leaf into place where deletion occurs
h[where] = h[n-1];
// take note that we have now one element less
--n;
// the new node here can be smaller than the previous,
// so it might be smaller than the parent, therefore sift up
// if that is the case
if (where > 0 && h[where] > h[(where-1)/2]) {
siftUp(where);
} else if (where < n/2) {
// Now, if where has a child, the new value could be larger
// than that of the child, therefore sift down
siftDown(where);
}
}
The exposed function to remove a specified value (if present) would be
public void remove(int value) {
for(int i = 0; i < n; ++i) {
if (h[i] == value) {
removeAt(i);
// assumes that only one value should be removed,
// even if duplicates are in the heap, otherwise
// replace the break with --i to continue removing
break;
}
}
}
Summarising, we can remove a node at a given position by replacing the value with the value of the last leaf (in the cases where the removal is not trivial), and then sifting up or down from the deletion position. (Only one or none sift needs to be done, depending on a comparison with the parent and/or children, if present.)
That works because the heap invariant is satisfied for the parts of the tree above and below the deletion position, so if the new value placed there by the swap is smaller than the parent, sifting up will place it in its proper position above the deletion position. All elements moved are smaller than any element in the children, so the heap invariant is maintained for the part below (and including) the deletion position.
If the new value is larger than one of the direct children, it's basically a removal of the root from the sub-heap topped at the deletion position, so the siftDown restores the heap invariant.
The fix for the mentioned flaw in the siftDown method is to set smallestChild to leftChild if rightChild >= n:
final int smallestChild = (rightChild >= n || h[rightChild] > h[leftChild]) ? leftChild
: rightChild;