Storing k-ary tree with an array - arrays

Does storing a k-ary tree as an array only work if you fill in each node from left to right with k-children before moving to the next one?
Ex:
1
/ | \
2 3 4
/ | \
5 6 7
Can be stored as an array that looks like:
[X,1,2,3,4,5,6,7]
0 1 2 3 4 5 6 7
And any parent can be found by taking the index/k.
However, for the same data but stored as:
1
/ | \
2 3 4
/ | |
5 6 7
with 7 as a child of 3 indexing no longer works.
Also, in general, the siblings are within +- k indices of the current node but how do I make sure I'm not accidentally accessing a parent/uncle node?

Assuming the root node is at index 0 in the array, then the children of the node at index i are at indexes (i*n) + 1 through (i*n) + n. A node's parent is at index (i-1)/n. There are similar equations for if you want to put the root at index 1, but there's no good reason to leave index 0 unoccupied.
If you want to visit all of the siblings of the current node, first find the parent node, and then visit all of that node's children. That way you won't accidentally visit an "uncle" node.
Normally, trees stored in an array like this are complete binary trees: all levels except possibly the last are full, and if the last level isn't completely full, then it's filled from left to right.
You don't have to fill in all positions, but if you don't then you need to have some kind of flag at that node's position to tell you that it's empty.
But storing the tree as in your second example, where the first child of index 3 is where one would normally put the last child of index 2 breaks those calculations. You would have to store an array of child indexes in the parent node, and the index of the parent in each child node.

Related

How to reverse an array from index i to index j multiple times using cartesian tree?

Suppose I have a given array A. Now there are multiple operations of the form
reverse i,j // means reverse the array Ai..j inclusive
and
print i,j
Print the array Ai..j.
Example ,
A = 6 9 1 10 4 15 9
reverse 2,3
A = 6 1 9 10 4 15 9
reverse 3,6
A = 6 1 15 4 10 9 9
print 1,4
6 1 15 4
I have heard that it can be done by cartesian trees. So I have been reading the blog here But I still can't understand how we can do this using cartesian tree, what is the key and value should be and how we should implement ?
In this problem, a treap(aka Cartesian tree) with implicit key should be used(there is no key at all, it is just about merging them in right order). The value of a node is an array element that it represents. To implement reverse operation, you can maintain reverse flag for each node(true if it must be reversed, false otherwise) and push it lazily(to push here means to exchange left and right children of a node and flip the value of a flag in its children).
Pseudo code for push:
void push(Node node)
if node.flag
swap(node.left, node.right)
if node.left != null
node.left.flag = not node.left.flag
if node.right != null
node.right.flag = not node.right.flag
Follow in below some examples that you could use.
console.log(
Array.from({length:1}).reduce((acc,item)=>acc.reverse(),[1,2,3]),
Array.from({length:2}).reduce((acc,item)=>acc.reverse(),[1,2,3]),
Array.from({length:3}).reduce((acc,item)=>acc.reverse(),[1,2,3])
)
console.log( Array.from({length:1}).reduce((acc,item)=>acc.reverse(),Array(...'love')).join(''), Array.from({length:2}).reduce((acc,item)=>acc.reverse(),Array(...'love')).join(''), Array.from({length:3}).reduce((acc,item)=>acc.reverse(),Array(...'love')).join('')
)
const reverseXTimes = (word, xTimes)=> Array.from({length:xTimes}).reduce((acc,item)=>acc.reverse(),Array(...word)).join('')
console.log(
reverseXTimes('passion',1),
reverseXTimes('passion',2),
reverseXTimes('passion',3),
)

Traversing a complete binary min heap

I am not sure how to traverse the tree structure below so that the nodes are always in ascending order. Heapifying the array [9 8 7 6 5 4 3 2 1 0] results in the array [0 1 3 2 5 4 7 9 6 8] which I think corresponds to this representation:
Wanting to keep the array as is (because I want to do efficient inserts later) how can I efficiently traverse it in ascending order? (That is visiting the nodes in this order [0 1 2 3 4 5 6 7 8 9])
Just sort the array. It will still be a min-heap afterward, and no other algorithm is asymptotically more efficient.
You can't traverse the heap in the same sense that you can traverse a BST. #Dukeling is right about the BST being a better choice if sorted traversal is an important operation. However you can use the following algorithm, which requires O(1) additional space.
Assume you have the heap in the usual array form.
Remove items one at a time in sorted order to "visit" them for the traversal.
After visiting the i'th item, put it back in the heap array at location n-i, which is currently unused by the heap (assuming zero-based array indices).
After traversal reverse the array to create a new heap.
Removing the items requires O(n log n) time. Reversing is another O(n).
If you don't need to traverse all the way, you can stop at any time and "fix up" the array by running the O(n) heapify operation. See pseudocode here for example.
I would actually rather suggest a self-balancing binary search tree (BST) here:
A binary search tree (BST) ... is a node-based binary tree data structure which has the following properties:
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
The left and right subtree each must also be a binary search tree.
There must be no duplicate nodes.
It's simpler and more space efficient to traverse a BST in sorted order (a so-called in-order traversal) than doing so with a heap.
A BST would support O(log n) inserts, and O(n) traversal.
If you're doing tons of inserts before you do a traversal again, it might be more efficient to just sort it into an array before traversing - the related running times would be O(1) for inserts and O(n log n) to get the sorted order - the exact point this option becomes more efficient than using a BST will need to be benchmarked.
For the sake of curiosity, here's how you traverse a heap in sorted order (if you, you know, don't want to just keep removing the minimum from the heap until it's empty, which is probably simpler option, since removing the minimum is a standard operation of a heap).
From the properties of a heap, there's nothing stopping some element to be in the left subtree, the element following it in the right, the one after in the left again, etc. - this means that you can't just completely finish the left subtree and then start on the right - you may need to keep a lot of the heap in memory as you're doing this.
The main idea is based on the fact that an element is always smaller than both its children.
Based on this, we could construct the following algorithm:
Create a heap (another one)
Insert the root of the original heap into the new heap
While the new heap has elements:
Remove minimum from the heap
Output that element
Add the children of that element in the original heap, if it has any, to the new heap
This takes O(n log n) time and O(n) space (for reference, the BST traversal takes O(log n) space), not to mention the added code complexity.
You can use std::set, if you're ok without duplicates. A std::set iterator will traverse in order and maintains ordering based on the default comparator. In the case of int, it's <, but if you traverse in reverse order with rbegin(), you can traverse from highest to lowest. Or you can add a custom comparator. The former is presented:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int main() {
vector<int> data{ 5, 2, 1, 9, 10, 3, 4, 7, 6, 8 };
set<int> ordered;
for (auto n : data) {
ordered.insert(n);
// print in order
for (auto it = ordered.rbegin(); it != ordered.rend(); it++) {
cout << *it << " ";
}
cout << endl;
}
return 0;
}
Output:
5
5 2
5 2 1
9 5 2 1
10 9 5 2 1
10 9 5 3 2 1
10 9 5 4 3 2 1
10 9 7 5 4 3 2 1
10 9 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1

locate root node in binary tree stored in array in inorder

Example Tree
2 -> root
1 -> Left
3 -> right
stored in array in in order [1, 2, 3]
How to retrieve the root node knowing that the tree is stored in inorder?
According to me all three as possible candidates of root node.
Indeed all 3 are possible candidates.
Here are possible trees that would result in the given in-order traversal:
1 2 3
\ / \ /
2 1 3 2
\ /
3 1
An in-order traversal isn't necessarily sufficient to uniquely identify a tree (and thus consistently identify the root). Assuming unique tree elements, you need either a pre-order or post-order traversal paired with an in-order traversal.
Reference - Which combinations of pre-, post- and in-order sequentialisation are unique?

replace each number, a[i] with next higher number on its right side,

Given an array of integers, replace each number, a[i] with next higher number(according to value) on its right side, whose value is closer to a[i] (if not present than keep it as it is.)
for e.g.
input – > 3 7 5
output -> 5 7 5
input –> 3 6 2 6 4 7 1
output-> 4 7 4 7 7 7 1
This question was asked in an interview.
If start from right and insert each element in BST and then finding the closer value in BST but this approach would also be O(n^2) in the worst case.
Is there any optimized approach for this?
You can build a balanced BST for the entire list of numbers. Then, go through the list again, using the tree to find the next larger number. After each item is done, remove it from the tree.
The depth of the tree never increases, so the total complexity is O(n log n) for building the tree in the first place, O(log n) per item for finding the next largest item, and O(log n) for removing the current item. Overall O(n log n) with no fancy data structures.

Checking for node repetition in multi-parent tree

I've got a pretty simple tree implementation in SQL:
CREATE TABLE [dbo].[Nodes] (
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL
);
CREATE TABLE [dbo].[NodeNodes] (
[ParentNodeId] [int] NOT NULL,
[ChildNodeId] [int] NOT NULL
);
My tree implementation is such that a node can have multiple parents. This is so the user can create custom trees that group together commonly used nodes. For example:
1 8 9
/ \ / \ / \
2 3 4 7 2 6
/ \ / \ / \
4 5 6 7 4 5
Node | Parents | Children
---------------------------
1 | - | 2,3
2 | 1,9 | 4,5
3 | 1 | 6,7
4 | 2,8 | -
5 | 2 | -
6 | 3,9 | -
7 | 3,8 | -
8 | - | 4,7
9 | - | 2,6
So there are three trees which are indicated by the three nodes with no parent. My problem is validating a potential relationship when the user adds a node as a child of another. I would like no node to appear twice in the same tree. For example, adding node 2 as a child of node 6 should fail because that would cause node 2 to appear twice in 1's tree and 9's tree. I'm having trouble writing an efficient algorithm that does this.
My first idea was to find all the roots of the prospective parent, flatten the trees of the roots to get one list of nodes per tree, then intersect those lists with the prospective child, and finally pass the validation only if all of the resultant intersected lists are empty. Going with the example, I'd get these steps:
1) Trace prospective parent through all parents to roots:
6->3->1
6->9
2) Flatten trees of the roots
1: {1,2,3,4,5,6,7}
9: {2,4,5,6,9}
3) Intersect lists with the prospective child
1: {1,2,3,4,5,6,7}^{2} = {2}
9: {2,4,5,6,9}^{2} = {2}
4) Only pass if all result lists are empty
1: {2} != {} ; fail
9: {2} != {} ; fail
This process works, except for the fact that it requires putting entire trees into memory. I have some trees with 20,000+ nodes and this takes almost a minute to run. This performance isn't a 100% dealbreaker, but it is very frustrating. Is there a more efficient algorithm to do this?
Edit 4/2 2pm
The above algorithm doesn't actually work. deroby pointed out that adding 9 as a child to 7 will be passed by the algorithm but shouldn't be. The problem is that adding a node with children to another node will succeed as long as the node isn't repeated -- it doesn't validate the children.
A year later I stumbled upon my own question and I decided I would add my solution. It turns out I had just forgotten my basic data structures. What I originally thought was a simple tree was actually a directed graph, and what I was testing for was a cycle. Seeing as how cycle detection is a pretty common thing, there should be numerous solutions and discussions about it out there on the internets. See Best algorithm for detecting cycles in a directed graph for one example.

Resources