List implemented using an inorder binary tree - python

For the new computer science assignment we are to implement a list/array using an inorder binary tree. I would just like a suggestion rather than a solution.
The idea is having a binary tree that has its nodes accessible via indexes, e.g.
t = ListTree()
t.insert(2,0) # 1st argument is the value, 2nd the index to insert at
t.get(0) # returns 2
The Node class that the values are stored in is not modifiable but has a property size which contains the total number of children below, along with left, right and value that point to children and store the value accordingly.
My chief problem at the moment keeping track of the index - as we're not allowed to store the index of the node in the node itself I must rely on traversing to track it. As I always start with the left node when traversing I haven't yet thought of a way to recursively figure out what index we are currently at.
Any suggestions would be welcome.
Thanks!

You really wouldn't want to store it on the node itself, because then the index would have to be updated on inserts for all nodes with index less than insert index. I think the real question is how to do an in-order traversal. Try having your recursive function return the number of nodes to its left.

I don't think you want to store the index, rather just the size of each subtree. For insance, if you wanted to look up the 10th element in the list, and the left and right subrees had 7 elements each, you would know that the root is the eight element (since it's in-order binary), and the first element of the right subree is 9th. armed with this knowledge, you would recurse into the right subree, looking for the 2nd element.
HTH

Well, a node in a binary tree cannot have a value and an index. They can have multiple pieces of data but the tree can only be keyed/built on one.
Maybe your assignment wants you to use the index value as the key to the tree and attach the value to the node for quick retrieval of the value given an index.

Does the tree have to be balanced? Does the algorithm need to be efficient?
If not, then the simplest thing to do is make a tree in which all the left children are null, i.e., a tree that devolves to a linked list.
To insert, recursively look go to the right child, and then update the size of the node on the way back out. Something like (pseudocode)
function insert(node, value, index, depth)
if depth < index
create the rightchild if necessary
insert( rightchild, value, index, depth + 1)
if depth == size
node.value = value
node.size = rightchild.size + 1
After you have this working, you can modify it to be more balanced. When increasing the length of the list, add nodes to the left or right child nodes depending on which currently has the least, and update the size on the way out of the recursion.
To generalize to be more efficient, you need to work on the index in terms of its binary representation.
For example, and empty list has one node, without children with value null and size 0.
Say you want to insert "hello" at index 1034. Then you want to end up with a tree whose root has two children, with sizes 1024 and 10. The left child has no actual children, but the right node has a right child of its own of size 2. (The left of size 8 is implied.) That node in turn, has one right child of size 0, with the value "hello". (This list has a 1-based index, but a 0-based index is similar.)
So you need to recursively break down the index into its binary parts, and add nodes as necessary. When searching the list, you need to take care when traversing a node with null children

A very easy solution is to do GetFirst() to get the first node of the tree (this is simply finding the leftmost node of the tree). If your index N is 0, return the first node. Otherwise, call GetNodeNext() N times to get the appropriate node. This isn't super efficient though since accessing a node by index takes O(N Lg N) time.
Node *Tree::GetFirstNode()
{
Node *pN,*child;
pN=GetRootNode();
while(NOTNIL(child=GetNodeLeft(pN)))
{
pN=child;
}
return(pN);
}
Node *Tree::GetNodeNext(Node *pNode)
{
Node *temp;
temp=GetNodeRight(pNode);
if(NOTNIL(temp))
{
pNode=temp;
temp=GetNodeLeft(pNode);
while(NOTNIL(temp))
{
pNode=temp;
temp=GetNodeLeft(pNode);
}
return(pNode);
}
else
{
temp=GetNodeParent(pNode);
while( (NOTNIL(temp)) && (GetNodeRight(temp)==pNode) )
{
pNode=temp;
temp=GetNodeParent(pNode);
}
return(temp);
}
}

Related

How to sort N elements given a list of tuples stating their known order?

sorry for the complicated / confusing title.
Basically I'm trying to implement a system that helps with the sorting of documents with no known date of writing.
It consists of two inputs:
Input 1: A tuple, where the first element is the number of documents, N. The second element is the number of pairs of documents with a known writing order, L. (First document was written before the second document).
Input 2: A list of L tuples. Each tuple contains two elements (documents). The first document was written before the second document. Eg: (1 2), (3 4) means that document1 was written before document2 and document3 was written before document4.
Next, the software must determine if there is a way of sorting all documents chronologically, there can be three outputs:
Inconclusive - Means that the temporal organization of the documents is inconsistent and there is no way of sorting them.
Incomplete - Means that information is lacking and the system can't find a way of sorting.
In case the information is enough, the system should output the order in which the documents have been written.
So far, I have managed to take both inputs, but I do not know where to start in terms of sorting the documents. Any suggestions?
Here's my code so far (Python3):
LN = tuple(int(x.strip()) for x in input("Number of docs. / Number of known pairs").split(' '))
print(LN)
if (LN[1]) > (LN[0]**2):
print("Invalid number of pairs")
else:
A = ['none'] * LN[0]
for i in range(LN[0]):
t = tuple(int(x.strip()) for x in input("Pair:").split(' '))
A[i] = t
print(A)
I appreciate all suggestions :)
Build a directed graph. The inputs are the edges. Check for cycles which would indicate inconsistent input. Find the "leftmost" node, that is the node that doesn't have any edge to it, meaning nothing to its left. Multiple that are leftmost? Incomplete. Then, for each node in the graph, assign the index that equals the length of the longest path from the leftmost node. As there are no (directed) cycles, you could probably just do BFS starting at the leftmost node and at each step assign to the node the maximum of its current value and its value given from its parent. Then iterate through all nodes, and put the numbers in their corresponding indices. Two nodes have the same index assigned? Incomplete.

Maximum Binary Tree (Leetcode) - Optimal Solution Explanation?

I was going through the Maximum Binary Tree leetcode problem. The TL;DR is that you have an array, such as this one:
[3,2,1,6,0,5]
You're supposed to take the maximum element and make that the root of your tree. Then split the array into the part to the left of that element and the part to its right, and these are used to recursively create the left and right subtrees in the same way, respectively.
LeetCode claims that the optimal solution (shown in the "Solution" tab) uses a linear search for the maximum value of the sub-array in each recursive step. This is O(n^2) in the worst case. This is the solution I came up with, and it's simple enough.
However, I was looking through other submissions and found a linear time solution, but I've struggled to understand how it works! It looks something like this:
def constructMaximumBinaryTree(nums):
nodes=[]
for num in nums:
node = TreeNode(num)
while nodes and num>nodes[-1].val:
node.left = nodes.pop()
if nodes:
nodes[-1].right = node
nodes.append(node)
return nodes[0]
I've analysed this function and in aggregate, this appears to be linear time (O(n)), since each unique node is added to and popped from the nodes array at most once. I've tried running it with different example inputs, but I'm struggling to connect the dots and wrap my head around how this works. Can someone please explain it to me?
One way to understand the algorithm is to consider the loop invariants. In this case, the array of nodes always satisfies the condition that before and after each execution of the for-loop, either:
nodes is empty and a max binary tree does not exist (for example, if the input nums was empty)
the first item in nodes is the max binary tree based on the data processed so far from the input nums
The while-loop ensures that the current max binary tree is the first item in the nodes array, since otherwise, it would have been popped and added as a left subtree.
During each iteration of the for-loop, the check:
if nodes:
nodes[-1].right = node
adds the current node as a right subtree to the last item in the nodes array. And when this happens, the current node is less than the last node in the nodes array (since each input integer is defined to be unique). And since the current node is less than the last node in the array, the last node acts as a partition point whose value is greater than the current item, which is why the current node is added as a right subtree.
When there are multiple items in the nodes array, each item is a subtree of the item to its left.
Running Time
For the running time, let n be the length of the input nums. There are n executions of the for-loop. If the input data were sorted in descending order, but with the max input value at the end of the input (such as: 4, 3, 2, 1, 5), then the inner while-loop would be skipped during each iteration until the last for-loop iteration. During the last for-loop iteration, the while loop would run n - 1 times, for a total running time of n + (n - 1) => 2n - 1 => O(n).

I want to add values while a recursive loop unfolds

This is a bottom up approach to check if the tree is an AVL tree or not. So how this code works is:
Suppose this is a tree :
8
3 10
2
1
The leaf node is checked that it is a leaf node(here 1). It then unfolds one recursion when the node with data 2 is the current value. The value of cl = 1, while it compares the right tree. The right branch of 2 is empty i.e does not have any children so the avl_compare will have (1, 0) which is allowed.
After this i want to add one value to cl so that when the node with data 3 is the current value, the value of cl = 2. avl_check is an assignment question. I have done this on my own but i need some help here to play with recursive functions.
def avl_check(self):
cl = cr = 0
if(self.left):
self.left.avl_check()
cl+=1
if(self.right):
self.right.avl_check()
cr += 1
if(not self.avl_compare(cl,cr)):
print("here")
Your immediate problem is that you don't seem to understand local and global variables. cl and cr are local variables; with the given control flow, the only values they can ever have are 0 and 1. Remember that each instance of the routine gets a new set of local variables: you set them to 0, perhaps increment to 1, and then you return. This does not affect the values of the variables in other instances of the function.
A deeper problem is that you haven't thought this through for larger trees. Assume that you do learn to use global variables and correct these increments. Take your current tree, insert nodes 4, 9, 10, and 11 (nicely balanced). Walk through your algorithm, tracing the values of cl and cr. By the time you get to node 10, cl is disturbingly more than the tree depth -- I think this is a fatal error in your logic.
Think through this again: a recursive routine should not have global variables, except perhaps for the data store of a dynamic programming implementation (which does not apply here). The function should check for the base case and return something trivial (such as 0 or 1). Otherwise, the function should reduce the problem one simple step and recur; when the recursion returns, the function does something simple with the result and returns the new result to its parent.
Your task is relatively simple:
Find the depths of the two subtrees.
If their difference > 1, return False
else return True
You should already know how to check the depth of a tree. Implement this first. After that, make your implementation more intelligent: checking the depth of a subtree should also check its balance at each step. That will be your final solution.

Sort nodes based on inputs / outputs

I have a node system where every node only stores its inputs and outputs, but not its index. Here is a simplified example:
class Node1:
requiredInputs = []
class Node2:
requiredInputs = ["Node1"]
class Node3:
requiredInputs = ["Node2"]
class Node4:
requiredInputs = ["Node3", "Node2"]
Now I want to order that nodes, so that all inputs are already processed when processing that node. For this simple example, a possible order would be [Node1, Node2, Node3, Node4].
My first idea would be to use a brute force to check every possible combination. However, this will be very slow for a bigger number of nodes.
What would be a more efficient way to do this? I dont need an implementation, just a basic idea or algorithm.
What you want is to topologically sort the nodes.
http://en.wikipedia.org/wiki/Topological_sorting
The very basic idea would be to assign an integer to each node that is at the beginning equal to the number of outputs it has. Then add all the nodes with the value 0 (that is, those that have no outputs) to the list that will represent the order. For each node that is ever appended to the list, subtract one from the values associated with the nodes that are inputs to that node. If any of those nodes now have the value of zero, add them to the list as well. Repeat doing it. It is guaranteed that eventually the process terminates, as long as you don't have cycles, and that nodes in the list will be sorted in such a way that inputs always go before outputs.
Algorithm
Topological sort is indeed the way to go; Per your request, I will not write the full implementation.
Outline & notes
Types
First, you code store the requiredInputs as classes, not as strings. This will make the comparison way more elegant:
class Node1:
requiredInputs = []
class Node2:
requiredInputs = [Node1]
class Node3:
requiredInputs = [Node2]
class Node4:
requiredInputs = [Node3, Node2]
Input and output data structures
Then, you can place your nodes in two arrays, for input and output. This can be done in-place (using a single array), but it's rarely worth the trouble.
unordered_nodes = [Node4, Node3, Node2, Node1]
ordered_nodes = []
Here's the algorithm outline:
while there are unordered_nodes:
for each node N in unordered_nodes:
if the requiredInputs of N are already in ordered_nodes:
add N to ordered_nodes
remove N from unordered_nodes
break
Expected result
When implemented, it should give:
print ordered_nodes
[<class __main__.Node1 at 0x10a7a8bb0>,
<class __main__.Node2 at 0x10a7a83f8>,
<class __main__.Node3 at 0x10a7a80b8>,
<class __main__.Node4 at 0x10a7a8600>]
Optimizations
There are quite a few ways to optimize or otherwise improve a topological sort. As before, I'll hint a few without disclosing any implementation.
Pre-sorting the input array by some property
Sorting in-place, with a single array
Using a different data structure to represent the relations between nodes
Adding more than one node to ordered_nodes at any iteration

Counting all nodes of all paths from root to leaves

If given a tree with nodes with integers: 1 ~ 10, and branching factor of 3 for all nodes, how can I write a function that traverses through the tree counting from root to leaves for EVERY paths
So for this example, let's say it needs to return this:
{1: 1, 2: 5}
I've tried this helper function:
def tree_lengths(t):
temp = []
for i in t.children:
temp.append(1)
temp += [e + 1 for e in tree_lengths(i)]
return temp
There are too many errors with this code. For one, it leaves behind imprints of every visited node in the traversal in the returning list - so it's difficult to figure out which ones are the values that I need from that list. For another, if the tree is large, it does not leave behind imprints of the root and earlier nodes in the path prior to reaching the line "for i in t.children". It needs to first: duplicate all paths from root leaves; second: return a list exclusively for the final number of each path count.
Please help! This is so difficult.
I'm not sure exactly what you are trying to do, but you'll likely need to define a recursive function that takes a node (the head of a tree or subtree) and an integer (the number of children you've traversed so far), and maybe a list of each visited node so far. If the node has no children, you've reached a leaf and you can print out whatever info you need. Otherwise, for each child, call this recursive function again with new parameters (+1 to count, the child node as head node, etc).

Categories

Resources