Iterative Inorder Traversal B-Tree - java

My end goal is to do a findKthElement function and the only way I can think of is to perform iterative inorder traversal so that I can keep a counter, which obviously doesn't work if its recursive. I have tried my best at an implementation similar to a BST but its not working, just printing the same thing infinately. Here is my attempt:
public void findKth() {
Stack<BTreeNode> s = new Stack<>();
BTreeNode current = this.root;
while(current != null || !s.isEmpty()) {
int i;
for(i = 0; i < current.numNodes; i++) {
if(!current.isLeaf) {
s.push(current);
current = current.children[i];
}
}
current = s.pop();
for(int j = 0; j < current.numNodes; j++) {
System.out.println(current.keys[j].getName());
}
}
}

keep a counter, which obviously doesn't work if its recursive
There is no problem keeping a counter in a recursive solution. You just need to make sure it's a mutable reference. For example:
public class Counter {
private int count;
public boolean complete() { return count == 0; }
public void decrement() { count--; }
}
Optional<Node> findKthChild(Node node, Counter counter) {
if (counter.isLeaf()) {
if (counter.complete())
return Optional.of(node);
counter.decrement();
} else {
for (Node child: getChildren()) {
Optional<Node> kthChild = findKthChild(child, counter);
if (kthChild.isPresent())
return kthChild;
}
}
return Optional.empty();
}
If you're familiar with streams the internal for loop could be:
return getChildren().stream()
.map(ch -> findKthChild(ch, counter))
.filter(Optional::isPresent)
.findFirst().orElse(Optional.empty());

This reeks of home work. One should try to solve it by tracing the needed steps manually, with pen and paper.
I am not claiming that the code below is correct, or good.
It is to indicate that an in-order traversal, depth first, needs to come back a some nodes ith sub-branch to continue with the next child.
For that I use the new record class as stack element, a class consisting of just BTreeNode node and int index.
public String findKth(int k) {
record NodePos(BTreeNode node, int index) {};
Stack<NodePos> stack = new Stack<>();
stack.push(new NodePos(this.root, -1);
while (!stack.isEmpty()) {
NodePos pos = stack.pop();
pos = new NodePos(pos.node, pos.index + 1);
if (pos.index >= pos.node.numNodes) { // Past end of child nodes.
continue;
}
// Sub-branch:
if (!pos.node.isLeaf) {
stack.push(new NodePos(pos.node.children[pos.index], -1);
continue;
}
// Key:
if (pos.index + 1 >= pos.node.numNodes) { // Past end of child keys.
continue;
}
System.console().printf("%d. %s%n", k, pos.node.keys[pos.index]);
if (k <= 0) {
return pos.node.keys[pos.index];
}
--k;
stack.push(pos);
}
}
There are numNodes sub-branches (node.children)and numNodes - 1 keys in a node (node.keys).
When you are at the i th sub-branch, you may first continue with the subtree, and when not sufficient (decreasing k still greater 0), then continue with the i-1 th key.
As you see, when not manually executing the code, it is hard to read it. For that it invaluable advice to work out these things yourself.
A recursive solution is easier by the way.
Okay, a working solution
My answer above was intended to think about, certainly not correct,
as the OP did not show having seriously thought about the algorithm,
given the OPs code. But there is effort evidently.
Hence a readable recursive solution. Still in a form which cannot
be given back as ones own home work.
static class BTreeNode {
int numNodes;
boolean isLeaf;
BTreeNode[] children;
int[] keys;
BTreeNode(int... keys) {
numNodes = keys.length + 1;
this.keys = keys.clone();
isLeaf = true;
}
public void addChildren(BTreeNode... children) {
assert children.length == numNodes;
this.children = children.clone();
isLeaf = false;
}
}
public static OptionalInt findKth(BTreeNode node, AtomicInteger k) {
if (node == null || k.get() < 0) {
return OptionalInt.empty();
}
for (int i = 0; i < node.numNodes; ++i) {
if (!node.isLeaf) {
OptionalInt result = findKth(node.children[i], k);
if (result.isPresent()) {
return result;
}
}
if (i + 1 < node.numNodes) {
int j = k.getAndDecrement();
System.out.printf("%d. %s%n", j, node.keys[i]);
if (j <= 0) {
return OptionalInt.of(node.keys[i]);
}
}
}
return OptionalInt.empty();
}
public static void main(String[] args) {
//
// (4 8 12)
// (1 2 3) (5 6 7) (9 10 11) (13 14 15)
BTreeNode n1to3 = new BTreeNode(1, 2, 3);
BTreeNode n5to7 = new BTreeNode(5, 6, 7);
BTreeNode n9to11 = new BTreeNode(9, 10, 11);
BTreeNode n13to15 = new BTreeNode(13, 14, 15);
BTreeNode root = new BTreeNode(4, 8, 12);
root.addChildren(n1to3, n5to7, n9to11, n13to15);
OptionalInt key5 = findKth(root, new AtomicInteger(5));
System.out.println("The result is " + key5.orElse(-1));
}
One walks in-order through the B-tree decrementing the asked k till it reaches 0. The in-order walk with numNodes subtree branches and numNodes - 1 keys requires a for+if.
The AtomicInteger is used to have a counter, a result from findKth otherwise one would need an input parameter k, and a new value for k on return. That can be done.
Optimisation: One could skip visiting a subtree, if one knew the number of elements in an entire subtree. For leaf nodes that would be numNodes.

Related

Reduced time complexity of inner loop: Find count of elements greater than current element in the first loop and store that in solved array

I want to reduce the complexity of this program and find count of elements greater than current/picked element in first loop (array[])and store the count in solved array(solved[]) and loop through the end of the array[]. I have approached the problem using a general array based approach which turned out to have greater time complexity when 2nd loop is huge.
But If someone can suggest a better collection here in java that can reduce the complexity of this code that would also be highly appreciated.
for (int i = 0; i < input; i++) {
if (i < input - 1) {
count=0;
for (int j = i+1; j < input; j++) {
System.out.print((array[i])+" ");
System.out.print("> ");
System.out.print((array[j]) +""+(array[i] > array[j])+" ");
if (array[i] > array[j]) {
count++;
}
}
solved[i] = count;
}
}
for (int i = 0; i < input; i++) {
System.out.print(solved[i] + " ");
}
What I want to achieve in simpler terms
Input
Say I have 4 elements in my
array[] -->86,77,15,93
output
solved[]-->2 1 0 0
2 because after 86 there are only two elements 77,15 lesser than 86
1 because after 77 there is only 15 lesser than 77
rest 15 <93 hence 0,0
So making the code simpler and making the code faster aren't necessarily the same thing. If you want the code to be simple and readable, you could try a sort. That is, you could try something like
int[] solved = new int[array.length];
for (int i = 0; i < array.length; i++){
int[] afterward = Arrays.copyOfRange(array, i, array.length);
Arrays.sort(afterward);
solved[i] = Arrays.binarySearch(afterward, array[i]);
}
What this does it it takes a copy of the all the elements after the current index (and also including it), and then sorts that copy. Any element less than the desired element will be beforehand, and any element greater will be afterward. By finding the index of the element, you're finding the number of indices before it.
A disclaimer: There's no guarantee that this will work if duplicates are present. You have to manually check to see if there are any duplicate values, or otherwise somehow be sure you won't have any.
Edit: This algorithm runs in O(n2 log n) time, where n is the size of the original list. The sort takes O(n log n), and you do it n times. The binary search is much faster than the sort (O(log n)) so it gets absorbed into the O(n log n) from the sort. It's not perfectly optimized, but the code itself is very simple, which was the goal here.
With Java 8 streams you could reimplement it like this:
int[] array = new int[] { 86,77,15,93 };
int[] solved =
IntStream.range(0, array.length)
.mapToLong((i) -> Arrays.stream(array, i + 1, array.length)
.filter((x) -> x < array[i])
.count())
.mapToInt((l) -> (int) l)
.toArray();
There is actually a O(n*logn) solution, but you should use a self balancing binary search tree such as red-black tree.
Main idea of the algorithm:
You will iterate through your array from right to left and insert in the tree triples (value, sizeOfSubtree, countOfSmaller). Variable sizeOfSubtree will indicate the size of the subtree rooted at that element, while countOfSmaller counts the number of elements that are smaller than this element and appear at the right side of it in the original array.
Why binary search tree? An important property of BST is that all nodes in the left subtree are smaller than the current node, and all in the right subtree are greater.
Why self-balancing tree? Because this will guarantee you O(logn) time complexity while inserting a new element, so for n elements in array that will give O(n*logn) in total.
When you insert a new element you will also calculate the value of countOfSmaller by counting elements that are currently in the tree and are smaller than this element - exactly what are we looking for. Upon inserting in the tree compare the new element with the existing nodes, starting with the root. Important: if the value of the new element is greater than the value of the root, it means that is also greater than all the nodes in the left subtree of root. Therefore, set countOfSmaller to the sizeOfSubtree of root's left child + 1 (because the new element is also greater than root) and proceed recursively in the right subtree. If it is smaller than root, it goes to the left subtree of root. In both cases increment sizeOfSubtree of root and proceed recursively. While rebalancing the tree, just update the sizeOfSubtree for nodes that are included in left/right rotation and that's it.
Sample code:
public class Test
{
static class Node {
public int value, countOfSmaller, sizeOfSubtree;
public Node left, right;
public Node(int val, int count) {
value = val;
countOfSmaller = count;
sizeOfSubtree = 1; /** You always add a new node as a leaf */
System.out.println("For element " + val + " the number of smaller elements to the right is " + count);
}
}
static Node insert(Node node, int value, int countOfSmaller)
{
if (node == null)
return new Node(value, countOfSmaller);
if (value > node.value)
node.right = insert(node.right, value, countOfSmaller + size(node.left) + 1);
else
node.left = insert(node.left, value, countOfSmaller);
node.sizeOfSubtree = size(node.left) + size(node.right) + 1;
/** Here goes the rebalancing part. In case that you plan to use AVL, you will need an additional variable that will keep the height of the subtree.
In case of red-black tree, you will need an additional variable that will indicate whether the node is red or black */
return node;
}
static int size(Node n)
{
return n == null ? 0 : n.sizeOfSubtree;
}
public static void main(String[] args)
{
int[] array = {13, 8, 4, 7, 1, 11};
Node root = insert(null, array[array.length - 1], 0);
for(int i = array.length - 2; i >= 0; i--)
insert(root, array[i], 0); /** When you introduce rebalancing, this should be root = insert(root, array[i], 0); */
}
}
As Miljen Mikic pointed out, the correct approach is using RB/AVL tree. Here is the code that can read and N testcase do the job as quickly as possible. Accepting Miljen code as the best approach to the given problem statement.
class QuickReader {
static BufferedReader quickreader;
static StringTokenizer quicktoken;
/** call this method to initialize reader for InputStream */
static void init(InputStream input) {
quickreader = new BufferedReader(new InputStreamReader(input));
quicktoken = new StringTokenizer("");
}
static String next() throws IOException {
while (!quicktoken.hasMoreTokens()) {
quicktoken = new StringTokenizer(quickreader.readLine());
}
return quicktoken.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
static long nextLong() throws IOException {
return Long.parseLong(next());
}
static double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
public class ExecuteClass{
static int countInstance = 0;
static int solved[];
static int size;
static class Node {
public int value, countOfSmaller, sizeOfSubtree;
public Node left, right;
public Node(int val, int count, int len, int... arraytoBeused) {
countInstance++;
value = val;
size = len;
countOfSmaller = count;
sizeOfSubtree = 1; /** You always add a new node as a leaf */
solved = arraytoBeused;
solved[size - countInstance] = count;
}
}
static Node insert(Node node, int value, int countOfSmaller, int len, int solved[]) {
if (node == null)
return new Node(value, countOfSmaller, len, solved);
if (value > node.value)
node.right = insert(node.right, value, countOfSmaller + size(node.left) + 1, len, solved);
else
node.left = insert(node.left, value, countOfSmaller, len, solved);
node.sizeOfSubtree = size(node.left) + size(node.right) + 1;
return node;
}
static int size(Node n) {
return n == null ? 0 : n.sizeOfSubtree;
}
public static void main(String[] args) throws IOException {
QuickReader.init(System.in);
int testCase = QuickReader.nextInt();
for (int i = 1; i <= testCase; i++) {
int input = QuickReader.nextInt();
int array[] = new int[input];
int solved[] = new int[input];
for (int j = 0; j < input; j++) {
array[j] = QuickReader.nextInt();
}
Node root = insert(null, array[array.length - 1], 0, array.length, solved);
for (int ii = array.length - 2; ii >= 0; ii--)
insert(root, array[ii], 0, array.length, solved);
for (int jj = 0; jj < solved.length; jj++) {
System.out.print(solved[jj] + " ");
}
System.out.println();
countInstance = 0;
solved = null;
size = 0;
root = null;
}
}
}

Updating Heap in both direction (Prim's Algorithm)

In Prim's algorithm, it is recommended to maintain the invariant in the following way :
When a vertice v is added to the MST:
For each edge (v,w) in the unexplored tree:
1. Delete w from the min heap.
2. Recompute the key[w] (i.e. it's value from the unexplored tree
to the explored one).
3. Add the value back to the heap.
So, basically this involves deletion from the heap (and heapify which takes O(logn)) and then reinserting (again O(logn))
Instead, if I use the following approach:
For each edge (v,w) in the unexplored tree:
1. Get the position of the node in the heap(array) using HashMap -> O(1)
2. Update the value in place.
3. Bubble up or bubble down accordingly. -> O(logn)
Which gives better constants than the previous one.
The controversial part is the 3rd part where Im supposed to bubble up or down.
My implementation is as follows :
public int heapifyAt(int index){
// Bubble up
if(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
while(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
swap(index, (int)Math.floor(index/2));
index = (int)Math.floor(index/2);
}
}else{
// Bubble down
while(index*2 + 2 < size && (heap[index].edgeCost > heap[index*2 + 1].edgeCost|| heap[index].edgeCost > heap[index*2 + 2].edgeCost)){
if(heap[index*2 + 1].edgeCost < heap[index*2 + 2].edgeCost){
//swap with left child
swap(index, index*2 + 1);
index = index*2 + 1;
}else{
//swap with right child
swap(index, index*2 + 2);
index = index*2 + 2;
}
}
}
return index;
}
And I'am plucking from the heap this way :
public AdjNode pluck(){
AdjNode min = heap[0];
int minNodeNumber = heap[0].nodeNumber;
AdjNode toRet = new AdjNode(min.nodeNumber, min.edgeCost);
heap[0].edgeCost = INF; // set this to infinity, so it'll be at the bottom
// of the heap.
heapifyat(0);
visited.add(minNodeNumber);
updatevertices(minNodeNumber); // Update the adjacent vertices
return toRet;
}
And updating the plucked vertices this way :
public void updatevertices(int pluckedNode){
for(AdjNode adjacentNode : g.list[pluckedNode]){
if(!visited.contains(adjacentNode.nodeNumber)){ // Skip the nodes that are already visited
int positionInHeap = map.get(adjacentNode.nodeNumber); // Retrive the position from HashMap
if(adjacentNode.edgeCost < heap[positionInHeap].edgeCost){
heap[positionInHeap].edgeCost = adjacentNode.edgeCost; // Update if the cost is better
heapifyAt(positionInHeap); // Now this will go bottom or up, depending on the value
}
}
}
}
But when I execute it on large graph, the code fails, There are small values in the bottom of heap and large values at the top. But the heapifyAt() API seems to work fine. So I am unable to figure out is my approach wrong or my code?
Moreover, if I replace the heapifyAt() API by siftDown(), i.e. construct the heap, it works fine, but it doesnt make sense calling siftDown() that takes O(n) time for every updates which can be processed in logarithmic time.
In short : Is it possible to update the values in Heap both way, or the algorithm is wrong, since that's why it is recommended to first remove the element from Heap and reinsert it.
EDIT : Complete code:
public class Graph1{
public static final int INF = 9999999;
public static final int NEGINF = -9999999;
static class AdjNode{
int nodeNumber;
int edgeCost;
AdjNode next;
AdjNode(int nodeNumber, int edgeCost){
this.nodeNumber = nodeNumber;
this.edgeCost = edgeCost;
}
}
static class AdjList implements Iterable<AdjNode>{
AdjNode head;
AdjList(){
}
public void add(int to, int cost){
if(head==null){
head = new AdjNode(to, cost);
}else{
AdjNode temp = head;
while(temp.next!=null){
temp = temp.next;
}
temp.next = new AdjNode(to, cost);
}
}
public Iterator<AdjNode> iterator(){
return new Iterator<AdjNode>(){
AdjNode temp = head;
public boolean hasNext(){
if(head==null){
return false;
}
return temp != null;
}
public AdjNode next(){
AdjNode ttemp = temp;
temp = temp.next;
return ttemp;
}
public void remove(){
throw new UnsupportedOperationException();
}
};
}
public void printList(){
AdjNode temp = head;
if(head==null){
System.out.println("List Empty");
return;
}
while(temp.next!=null){
System.out.print(temp.nodeNumber + "|" + temp.edgeCost + "-> ");
temp = temp.next;
}
System.out.println(temp.nodeNumber + "|" + temp.edgeCost);
}
}
static class Heap{
int size;
AdjNode[] heap;
Graph g;
int pluckSize;
Set<Integer> visited = new HashSet<Integer>();
HashMap<Integer, Integer> map = new HashMap<>();
Heap(){
}
Heap(Graph g){
this.g = g;
this.size = g.numberOfVertices;
this.pluckSize = size - 1;
heap = new AdjNode[size];
copyElements();
constructHeap();
}
public void copyElements(){
AdjList first = g.list[0];
int k = 0;
heap[k++] = new AdjNode(0, NEGINF); //First entry
for(AdjNode nodes : first){
heap[nodes.nodeNumber] = nodes;
}
for(int i=0; i<size; i++){
if(heap[i]==null){
heap[i] = new AdjNode(i, INF);
}
}
}
public void printHashMap(){
System.out.println("Priniting HashMap");
for(int i=0; i<size; i++){
System.out.println(i + " Pos in heap :" + map.get(i));
}
line();
}
public void line(){
System.out.println("*******************************************");
}
public void printHeap(){
System.out.println("Printing Heap");
for(int i=0; i<size; i++){
System.out.println(heap[i].nodeNumber + " | " + heap[i].edgeCost);
}
line();
}
public void initializeMap(){
for(int i=0; i<size; i++){
map.put(heap[i].nodeNumber, i);
}
}
public void swap(int one, int two){
AdjNode first = heap[one];
AdjNode second = heap[two];
map.put(first.nodeNumber, two);
map.put(second.nodeNumber, one);
AdjNode temp = heap[one];
heap[one] = heap[two];
heap[two] = temp;
}
public void constructHeap(){
for(int i=size-1; i>=0; i--){
int temp = i;
while(heap[temp].edgeCost < heap[(int)Math.floor(temp/2)].edgeCost){
swap(temp, (int)Math.floor(temp/2));
temp = (int)Math.floor(temp/2);
}
}
initializeMap();
}
public void updatevertices(int pluckedNode){
for(AdjNode adjacentNode : g.list[pluckedNode]){
if(!visited.contains(adjacentNode.nodeNumber)){
int positionInHeap = map.get(adjacentNode.nodeNumber);
if(adjacentNode.edgeCost < heap[positionInHeap].edgeCost){
// //System.out.println(adjacentNode.nodeNumber + " not visited, Updating vertice " + heap[positionInHeap].nodeNumber + " from " + heap[positionInHeap].edgeCost + " to " + adjacentNode.edgeCost);
// heap[positionInHeap].edgeCost = INF;
// //heap[positionInHeap].edgeCost = adjacentNode.edgeCost;
// int heapifiedIndex = heapifyAt(positionInHeap); // This code follows my logic
// heap[heapifiedIndex].edgeCost = adjacentNode.edgeCost; // (which doesnt work)
// //heapifyAt(size - 1);
heap[positionInHeap].edgeCost = adjacentNode.edgeCost;
//heapifyAt(positionInHeap);
constructHeap(); // When replaced by SiftDown,
} // works as charm
}
}
}
public void printSet(){
Iterator<Integer> it = visited.iterator();
System.out.print("Printing set : [");
while(it.hasNext()){
System.out.print((int)it.next() + ", ");
}
System.out.println("]");
}
public AdjNode pluck(){
AdjNode min = heap[0];
int minNodeNumber = heap[0].nodeNumber;
AdjNode toRet = new AdjNode(min.nodeNumber, min.edgeCost);
heap[0].edgeCost = INF;
constructHeap();
visited.add(minNodeNumber);
updatevertices(minNodeNumber);
return toRet;
}
public int heapifyAt(int index){
if(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
while(heap[index].edgeCost < heap[(int)Math.floor(index/2)].edgeCost){
swap(index, (int)Math.floor(index/2));
index = (int)Math.floor(index/2);
}
}else{
if(index*2 + 2 < size){
while(index*2 + 2 < size && (heap[index].edgeCost > heap[index*2 + 1].edgeCost|| heap[index].edgeCost > heap[index*2 + 2].edgeCost)){
if(heap[index*2 + 1].edgeCost < heap[index*2 + 2].edgeCost){
//swap with left child
swap(index, index*2 + 1);
index = index*2 + 1;
}else{
//swap with right child
swap(index, index*2 + 2);
index = index*2 + 2;
}
}
}
}
return index;
}
}
static class Graph{
int numberOfVertices;
AdjList[] list;
Graph(int numberOfVertices){
list = new AdjList[numberOfVertices];
for(int i=0; i<numberOfVertices; i++){
list[i] = new AdjList();
}
this.numberOfVertices = numberOfVertices;
}
public void addEdge(int from, int to, int cost){
this.list[from].add(to, cost);
this.list[to].add(from, cost);
}
public void printGraph(){
System.out.println("Printing Graph");
for(int i=0; i<numberOfVertices; i++){
System.out.print(i + " = ");
list[i].printList();
}
}
}
public static void prims(Graph graph, Heap heap){
int totalMin = INF;
int tempSize = graph.numberOfVertices;
while(tempSize>0){
AdjNode min = heap.pluck();
totalMin += min.edgeCost;
System.out.println("Added cost : " + min.edgeCost);
tempSize--;
}
System.out.println("Total min : " + totalMin);
}
public static void main(String[] args) throws Throwable {
Scanner in = new Scanner(new File("/home/mayur/Downloads/PrimsInput.txt"));
Graph graph = new Graph(in.nextInt());
in.nextInt();
while(in.hasNext()){
graph.addEdge(in.nextInt() - 1, in.nextInt() - 1, in.nextInt());
}
Heap heap = new Heap(graph);
prims(graph, heap);
}
}
With a proper implementation of heap, you should be able to bubble up and down. Heap preserves a group of elements using an order that applies to both directions and bubbling up and down are essentially the same, apart from the direction in which you move.
As to your implementation, I believe you are correct but one, seemingly minor issue: indexing.
If you look around for array implementations of heap, you will notice that in most cases the root is located at index 1, instead of 0. The reason for that being, in a 1-indexed array you preserve the following relation between parent p and children c1 and c2.
heap[i] = p
heap[2 * i] = c1
heap[2 * i + 1] = c2
It is trivial to draw an array on a piece of paper and see that this relation holds, if you have the root at heap[1]. The children of root, at index 1, are located at indices 2 and 3. Children of the node at index 2 are at indices 4 & 5, while children of the node at index 3 are at indices 6 & 7, and so on.
This relation helps you get to the children or the parent of any node at i, without having to keep track of where they are. (i.e. parent is at floor(i/2) and children are at 2i and 2i+1)
What you seem to have tried is a 0-indexed implementation of heap. Consequently you had to use a slightly different relation given below for parent p and children c1 and c2.
heap[i] = p
heap[2 * i + 1] = c1
heap[2 * i + 2] = c2
This seems to be ok when accessing the children. For example, the children of root, at index 0, are located at indices 1 and 2. Children of the node at index 1 are at indices 3 & 4, while children of the node at index 2 are at indices 5 & 6, and so on. However there is a pickle when accessing the parent of a node. If you consider node 3 and take floor(3/2), you do get index 1, which is the parent of 1. However, if you take the node at index 4, floor(4/2) gives you index 2, which is not the parent of the node at index 4.
Obviously, this adaptation of the index relationship between a parent and its children does not work for both children. Unlike the 1-indexed heap implementation, you can not treat both children the same while accessing their parents. Therefore, the problem lies specifically in your bubbling up part, without necessarily being related to bubbling up operation. As a matter of fact, though I haven't tested your code, the bubbling up portion of heapifyAt function seems to be correct.(i.e. except the indexing, of course)
Now, you may keep using a 0-indexed heap and adapt your code so that whenever you are looking for a node's parent, you implicitly check whether it is the right (i.e. not as in correct but as in the opposite of left) child of that parent and use floor((i-1)/2) if it is. Checking whether a node is the right child is trivial: just look if it is even or not. (i.e. as you index right children with 2i + 2, they will always be even)
However I recommend you take a different approach and instead use a 1-indexed array implementation of heap. The elegance of the array implementation of heap is that you can treat each node the same and you don't have to do anything different based on its index or location, with the root of the heap perhaps being the only possible exception to this.

Binary tree - find position in inorder traversal

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

Binary Tree Max sum level - Better Design?

I have written a code for finding level in Binary Tree having max sum of elements. I have a few Questions.
Is it a good design ? - I have used 2 queues but the total num of elements both queues store will be less than n. SO I think it should be Ok.
Can there be a better design?
public class MaxSumLevel {
public static int findLevel(BinaryTreeNode root) {
Queue mainQ = new Queue();
Queue tempQ = new Queue();
int maxlevel = 0;
int maxVal = 0;
int tempSum = 0;
int tempLevel = 0;
if (root != null) {
mainQ.enqueue(root);
maxlevel = 1;
tempLevel = 1;
maxVal = root.getData();
}
while ( !mainQ.isEmpty()) {
BinaryTreeNode head = (BinaryTreeNode) mainQ.dequeue();
BinaryTreeNode left = head.getLeft();
BinaryTreeNode right = head.getRight();
if (left != null) {
tempQ.enqueue(left);
tempSum = tempSum + left.getData();
}
if (right != null) {
tempQ.enqueue(right);
tempSum = tempSum + right.getData();
}
if (mainQ.isEmpty()) {
mainQ = tempQ;
tempQ = new Queue();
tempLevel ++;
if (tempSum > maxVal) {
maxVal = tempSum;
maxlevel = tempLevel;
tempSum = 0;
}
}
}
return maxlevel;
}
}
I like recursion (note, untested code):
public static int maxLevel(BinaryTreeNode tree) {
ArrayList<Integer> levels = new ArrayList<Integer>();
findLevels(tree, 0, levels);
// now just return the index in levels with the maximal value.
// bearing in mind that levels could be empty.
}
private static void findLevels(BinaryTreeNode tree, int level,
ArrayList<Integer> levels) {
if (tree == null) {
return;
}
if (levels.length <= level) {
levels.add(0);
}
levels.set(level, levels.get(level) + tree.getData());
findLevels(tree.getLeft(), level+1, levels);
findLevels(tree.getRight(), level+1, levels);
}
If I was feeling really mean to the garbage collector, I'd make findLevels return a list of (level, value) pairs and sum over those. That makes a lot more sense in co-routiney sort of languages, though, it'd be weird in java.
Obviously you can take the strategy in the recursive function and do it with an explicit stack of nodes to be processed. The key difference between my way and yours is that mine takes memory proportional to the height of the tree; yours takes memory proportional to its width.
Looking at your code, it seems pretty reasonable for the approach. I'd rename tempLevel to currentLevel, and I'd be inclined to pull the inner loop out into a function sumLevel that takes a queue and returns an int and a queue (except actually the queue would be an argument, because you can only return one value, grrr). But it seems okay as is.
It depends on how many nodes your trees have and how deep they are. Since you're performing breadth first search, your queues will take O(n) memory space, which is OK for most applications.
The following solution has O(l) space complexity and and O(n) time complexity (l is the depth of a tree and n number of its vertices):
public List<Integer> levelsSum(BinaryTreeNode tree) {
List<Integer> sums = new ArrayList<Integer>()
levelsSum(tree, sums, 0);
return sums;
}
protected void levelsSum(BinaryTreeNode tree, List<Integer> levelSums, int level) {
if (tree == null)
return;
// add new element into the list if needed
if (level.size() <= level)
levelSums.add(Integer.valueOf(0));
// add this node's value to the appropriate level
levelSums.set(level, levelSums.get(level) + tree.getData());
// process subtrees
levelSum(tree.getLeft(), levelSums, level + 1);
levelSum(tree.getRight(), levelSums, level + 1);
}
Now just call levelsSum on a tree and scan the returned list to find the maximum value.
Are You sure that elements will all be non-negative?
I would make it callable like new MaxSumLevel(root).getLevel(). Otherwise, what will You when You have to sometimes return maxSum ?
I would structure this as 2 nested loops:
while(!mainQ.isEmpty()){
while(!mainQ.isEmpty()){
BinaryTreeNode head = (BinaryTreeNode) mainQ.dequeue();
BinaryTreeNode left = head.getLeft();
BinaryTreeNode right = head.getRight();
if (left != null) {
tempQ.enqueue(left);
tempSum = tempSum + left.getData();
}
if (right != null) {
tempQ.enqueue(right);
tempSum = tempSum + right.getData();
}
}
mainQ = tempQ;
tempQ = new Queue();
tempLevel ++;
if (tempSum > maxVal) {
maxVal = tempSum;
maxlevel = tempLevel;
tempSum = 0;
}
}
This recursive approach works for me:
public int findMaxSumRootLeaf(TreeNode node,int currSum) {
if(node == null)
return 0;
return Math.max(findMaxSumRootLeaf(node.leftChild,currSum)+node.data, findMaxSumRootLeaf(node.rightChild,currSum)+node.data);
}
You can represent end of a level using null in the queue and calculating the maximum sum for each level.
public int maxLevelSum(BinaryTreeNode root) {
if (root == null) //if empty tree
return 0;
else {
int current_sum = 0;
int max_sum = 0;
Queue<BinaryTreeNode> queue = new LinkedList<BinaryTreeNode>(); //initialize a queue
queue.offer(root); //add root in queue
queue.offer(null); // null in queue represent end of a level
while (!queue.isEmpty()) {
BinaryTreeNode temp = queue.poll();
if (temp != null) {
if (temp.getLeft() != null) //if left is not null
queue.offer(temp.getLeft());
if (temp.getRight() != null)
queue.offer(temp.getRight()); //if right is not null
current_sum = current_sum + temp.getData(); //add to level current level sum
} else { // we reached end of a level
if (current_sum > max_sum) //check if cuurent level sum is greater than max
max_sum = current_sum;
current_sum = 0; //make current_sum=0 for new level
if (!queue.isEmpty())
queue.offer(null); //completion of a level
}
}
return max_sum; //return the max sum
}
}

Using a recursive method to find the smallest element in a subtree given the root: what am I doing wrong here?

So I have a homework question where I'm supposed to use a recursive method to "find the minimum element within a subtree rooted at the specified node"
And then I'm given this as my starting point:
public TreeNode
{
int data;
TreeNode left;
TreeNode right;
}
and
/**
Finds the minimum value for the subtree that is
rooted at a given node
#param n The root of the subtree
#return The minimum value
PRECONDITION: n is not null.
*/
int min(TreeNode n)
{
// COMPLETE THE BODY OF THIS METHOD
}
Now, I've got a very basic driver program written to insert nodes into the tree and I've written my recursive method, but it seems to be counting up instead of down, here's my method:
int min(TreeNode n){
if(n.left != null) {
n = n.left;
min(n);
System.out.println("N is now " + n.value);
}
return n.value;
}
Output of my code:
Building tree with rootvalue 25
=================================
Inserted 11 to left of node 25
Inserted 15 to right of node 11
Inserted 16 to right of node 15
Inserted 23 to right of node 16
Inserted 79 to right of node 25
Inserted 5 to left of node 11
Inserted 4 to left of node 5
Inserted 2 to left of node 4
Root is 25
N is now 2
N is now 4
N is now 5
N is now 11
The minimum integer in the given nodes subtree is: 11
Can someone please explain to me why this doesn't work?
Note: this is all assuming you're in a Binary Search Tree, so returning the minimum element means returning the left-most element.
This means your recursive call is quite simple:
min(node):
if this node has a left node:
return min(node.left)
if this node does not have a left node:
return this node's value
The logic is that if we don't have another left node then we are the left-most node, so we are the minimum value.
Now, in Java:
int min(TreeNode n){
if (n.left == null)
return n.value;
return min(n.left); // n.left cannot be null here
}
Now to explain your results, consider how this method works. It calls the method on the next node (min(n.left)) before continuing. In your case you had a println after this recursive call. Therefore the println inside the recursive call went first. So your prints started at the bottom of the tree and worked their way back up. This explains the "reverse order" printing.
Your method then returned 11 as your result because (as another answer has explained) your n = n.left didn't affect any of your recursive sub-calls, only the one in the current function call. This means you returned the left node of the root, rather than the furthest left child.
I hope this makes sense. If you need clarification on anything leave a comment or something. Recursion can be quite tricky to get your head around at first.
The issue is that Java is call-by-value, not by reference -- although references are passed by value. But what that really means in this case is that the call to min(n) does not change what the variable n refers to -- it doesn't do anything at all. What you should probably be doing is return min(n).
public static void main(String[] args) throws IOException, NoSuchMethodException, InitializationError {
Logger.getRootLogger().addAppender(new ConsoleAppender(new SimpleLayout(), "System.out"));
Logger.getRootLogger().setLevel(Level.ALL);
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
n1.data = 110;
n1.left = n2;
n1.right = n3;
n2.data = 15;
n2.left = n4;
n2.right = null;
n3.data = 3;
n3.left = null;
n3.right = null;
n4.data = 4;
n4.left = null;
n4.right = n5;
n5.data = 12;
n5.left = n6;
n5.right = null;
n6.data = 19;
n6.left = null;
n6.right = null;
System.out.print("min=" + min(n1));
}
static public class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
static int min(TreeNode n) {
return min(n, n.data);
}
static int min(TreeNode n, int min) {
System.out.println("N is now " + n.data);
int currentMin = min;
if (n.left != null && n.right != null) {
final int left = min(n.left);
final int right = min(n.right);
if (left < right) {
currentMin = left;
} else {
currentMin = right;
}
} else if (n.left != null) {
currentMin = min(n.left);
} else if (n.right != null) {
currentMin = min(n.right);
}
if (currentMin < min) {
return currentMin;
} else {
return min;
}
}
OUTPUT is:
N is now 110
N is now 15
N is now 4
N is now 12
N is now 19
N is now 3
min=3
You need to use some tree traversal algoritm, for checking every node of the tree. Also you need to store current finded minimum. Pass this minimum into recursive function. It is calling "accumulator".
The last statement in your method implementation returns the node n's value. As n starts with the root and is replaced by its left child (if exists) you always get the value of the root's left child.
The following code should do it:
int min(final Tree n){
int result;
if(n == null){
result = Integer.MAX_VALUE;
} else {
result = n.value;
final int leftResult = min(n.left);
if(leftResult < result){
result = leftResult;
}
final int rightResult = min(n.right);
if(rightResult < result){
result = rightResult;
}
}
return result;
}
Or you could use the Visitor pattern (you would need to make your tree Iterable then and pass the values to the Visitor one-by-one):
interface TreeVisitor {
void accept(int value);
}
class MinTreeVisistor implements TreeVisitor {
int min = Integer.MAX_VALUE;
#Override
public void accept(int value) {
if(value < this.min) {
this.min = value;
}
}
}

Categories

Resources