Tree insertions - data-structures

Aren't the Tree insert functions on interactivepython incorrect?
Insert Left:
def insertLeft(root,newBranch):
t = root.pop(1)
if len(t) > 1:
root.insert(1,[newBranch,t,[]])
else:
root.insert(1,[newBranch, [], []])
return root
I found the logic to be incorrect, insertion is leading to a broken tree.
I tried the below (you can run the code on the same page) and see a validation.
r = BinaryTree(3)
insertLeft(r,4)
insertLeft(r,5)
insertLeft(r, [10, [11, [],[]], []])
insertRight(r,6)
insertRight(r,7)
print(r)
Output:
[3,
[
[10, [11, [], []], []],
[5, [4, [], []], []],
[]
],
[
7,
[],
[6, [], []]
]
]

The result is as intended by those functions. The following:
insertLeft(r, [10, [11, [],[]], []])
...injects a value as the left child of the root. The value that will be given to that new node is what you provided as second argument. This function always creates one new node (triplet) and you have given it the value of a tree structure.
This looks strange in the output, and it looks as if the structure was corrupted, but that is not the case. The value [10, [11, [],[]], []] is just that -- a value -- and it does not take part in structuring the main tree.
Maybe you want to merge two trees. But in that case you should decide what should happen with the subtree at the root's left node. For instance, you could do something like this:
insertLeft(r, 11)
insertLeft(r, 10)
... and then the previous subtree ([5, [4, [], []], []]) will become a child of the node with value 11.
In short, in order to merges subtrees you cannot just pass one subtree as argument to insertLeft. The method is only intended to inject single nodes with one specific value.

Related

Calculations in lists in PROLOG

I try to create an emergency system to find people on time and those late.
so my list now looks like:
[ [patient(204,4,2),patient(203,3,2)] , [patient(303,7,3),patient(302,6,3)] , [patient(404,12,4) ,patient(403,11,4)] , [patient(504,16,5),patient(503,15,5)] ]
I want for each list to find those on time using the following function (score):
(consultation time) * (index of patient) + (2nd argument of patient predicate)
consultation time is constant:
example :
consultTime(15)
For this exemple i have to get something like :
[ [4 , 18] , [37, 51] , [72, 86] , [106, 120] ]
the problem is with the indices how can i preserve the same index as with a normal list i.e.:
[ [0, 1], [2, 3], [4, 5] ]
I'm sorry, i didn't find a good question for my problem.
the problem is with the indices how can i preserve the same index as with a normal list i.e.:
[ [0, 1], [2, 3], [4, 5] ]
Pass a counter in at the start of each list, use it to count through the elements, then return how far it got. Pass that value in to start the count for the next list:
% process a single list, just showing the counter
process([], C, C, []).
process([P1|P1s], Count, CountTo, [Count|P2s]) :-
succ(Count, Next),
process(P1s, Next, CountTo, P2s).
% for the list of lists
test([], _, []).
test([L1|L1s], CountFrom, [L2|L2s]) :-
process(L1, CountFrom, CountTo, L2),
test(L1s, CountTo, L2s).
e.g.
?- _Patients = [
[patient(204,4,2), patient(203,3,2)],
[patient(303,7,3), patient(302,6,3)],
[patient(404,12,4), patient(403,11,4)],
[patient(504,16,5), patient(503,15,5)]
],
test(_Patients, 0, Ps).
Ps = [[0, 1], [2, 3], [4, 5], [6, 7]]

Dijkstra: how to set a termination condition when finding the destination?

As we know, Dijkstra finds the shortest path from a single source node to any other node in a given graph. I try to modify the original Dijkstra to find the shortest path between a pair of the source node and destination node. It seems easy that only set a termination condition for terminating the program when the Dijkstra finds the destination node.
However, the "termination condition" I set in my Python codes seems to lead a sub-optimal shortest path rather than the optimal shortest path.
The Dijkstra code is as follows,
def dijkstra(adjList, source, sink):
#define variables
n = len(adjList) #intentionally 1 more than the number of vertices, keep the 0th entry free for convenience
visited = [False]*n
parent = [-1] *n
#distance = [float('inf')]*n
distance = [1e7]*n
heapNodes = [None]*n
heap = FibonacciHeap()
for i in range(1, n):
heapNodes[i] = heap.insert(1e7, i)
distance[source] = 0
heap.decrease_key(heapNodes[source], 0)
while heap.total_nodes:
current = heap.extract_min().value
#print("Current node is: ", current)
visited[current] = True
#early exit
if sink and current == sink:
break
for (neighbor, cost) in adjList[current]:
if not visited[neighbor]:
if distance[current] + cost < distance[neighbor]:
distance[neighbor] = distance[current] + cost
heap.decrease_key(heapNodes[neighbor], distance[neighbor])
if neighbor == sink and current != source: # this is a wrong logic , since the neighbor may not be selected as the next hop.
print("find the sink 1")
printSolution(source, sink, distance,parent)
break
if neighbor == sink:
print("find the sink2")
break
return distance
adjList = [
[],
[[2, 7], [3, 9], [6, 14]],
[[1, 7], [4, 15], [3, 10]],
[[1, 9], [2, 10], [4, 11], [6, 2]],
[[2, 15], [3, 11], [5, 6]],
[[4, 6], [6, 9]],
[[5, 9], [1, 14]]
]
dijkstra(adjList,1,4)
The graph of the adjacency list is as shown:
I want to find the path from node 1 to node 4, there are three paths:
path 1: 1 --> 2 --> 4 cost: 22
path 2: 1 --> 2 --> 3 --> 4 cost: 28
path 3: 1 --> 3 --> 4 cost: 20
path 4: 1 --> 3 --> 6 --> 5 --> 4 cost: 26
path 5: 1 --> 6 --> 3 --> 4 cost: 28
path 6: 1 --> 6 --> 5 --> 4 cost: 29
Originally, Dijkstra will select path 3: 1 --> 3 --> 4 since it has the minimum cost.
But, I modify the termination condition, i.e., when finding the adjacency node of the current node is the destination, the program will be ended. And I get the result of a path between node 1 and node 4. The result is path 1: 1 --> 2 --> 4.
I analyze that, this is because I set the wrong termination condition. The program will be terminated when finding the adjacency node of the current node is the destination, that is wrong but I have no idea that setting a proper termination condition when the destination node is found.Could you please provide some ideas?
The only right place for the termination condition is at the start of the outer loop when you just got the current node from the heap.
It is wrong to do that test when you iterate the neighbors, as you don't have the guarantee that this last edge is part of the shortest path. Just imagine some insane high cost for that last step to the neighbor: never could that be on the shortest path, so don't perform the terminating condition there: there still might be another path to the sink that is cheaper.
I also did not see where you actually populated parent in your code.
I would also not put all nodes on the heap from the start, as heaps are faster when they have fewer elements. You can start with a heap with just 1 node.
Another little optimisation is to use parent also for marking nodes as visited, so you don't actually need both parent and visited.
Finally, I don't know the FibonacciHeap library, so I have just taken heapq, which is a very light heap implementation:
from heapq import heappop, heappush
def dijkstra(adjList, source, sink):
n = len(adjList)
parent = [None]*n
heap = [(0, source, 0)] # No need to push all nodes on the heap at the start
# only add the source to the heap
while heap:
distance, current, came_from = heappop(heap)
if parent[current] is not None: # skip if already visited
continue
parent[current] = came_from # this also marks the node as visited
if sink and current == sink: # only correct place to have terminating condition
# build path
path = [current]
while current != source:
current = parent[current]
path.append(current)
path.reverse()
return distance, path
for (neighbor, cost) in adjList[current]:
if parent[neighbor] is None: # not yet visited
heappush(heap, (distance + cost, neighbor, current))
adjList = [
[],
[[2, 7], [3, 9], [6, 14]],
[[1, 7], [4, 15], [3, 10]],
[[1, 9], [2, 10], [4, 11], [6, 2]],
[[2, 15], [3, 11], [5, 6]],
[[4, 6], [6, 9]],
[[5, 9], [1, 14]]
]
dist, path = dijkstra(adjList,1,4)
print("found shortest path {}, which has a distance of {}".format(path, dist))
You actually have the correct condition for exit in your code that is when current==sink. You cannot impose any other exit condition. The algorithm necessarily needs to run until the destination node is visited because only at this point you can fix the value of the shortest path to the destination. Because of this condition, the complexity of finding the single source single destination shortest path is the same as that of the single source all nodes shortest paths. So your early exit condition is correct and you should remove all the neighbor condition checks.

Prolog - sort sublists of a list

I want to sort the sublists of a list which contains integers eliminating the duplicates. Example:
[1, 2, [4, 1, 4], 3, 6, [7, 10, 1, 3, 9], 5, [1, 1, 1], 7]
=>>>
[1, 2, [1, 4], 3, 6, [1, 3, 7, 9, 10], 5, [1], 7].
I know that i have to work with functor s(but i didn't really get it).
Here is my code : (the (insert+sorting) function works in a simple list of integers,but don't work here. i'm getting red false everytime)
insert(E,[],[E]).
insert(E,[H|T],[H|L]):-
E>H,
insert(E,T,L).
insert(E,[H|T],[H|T]):-
E=H,
!.
insert(E,[H|T],[E|[H|T]]):-
E<H,
!.
sort([],[]).
sort([i(H)|T],L):-
sort(T,L1),
insert(i(H),L1,L).
You could try a solution like this, it uses the the sort/2 predicate to sort sublists:
sort_sublists([], []).
sort_sublists([X|Xs], List) :-
(integer(X) ->
List = [X | List1]
;
sort(X, Sorted),
List = [Sorted | List1]
),
sort_sublists(Xs, List1).
Example call:
?- set_prolog_flag(answer_write_options,[max_depth(0)]).
true.
?- sort_sublists([1, 2, [4, 1, 4], 3, 6, [7, 10, 1, 3, 9], 5, [1, 1, 1], 7], X).
X = [1,2,[1,4],3,6,[1,3,7,9,10],5,[1],7].
#Eduard Adrian it's hard to answer in comments, so first thing you need to do is to remove duplicates from the nested lists.
Here i tried that and you can see different cases that you need to handle. One example:(Head of your list can be a list but it's tail will be empty this happends if last element of your list is a list) in that case you need to define another predicate which will match your recursive call.
Once you have removed duplicates you can use simple sorting algorithm but you have to check if the head is a list then you sort innner list first and place it to the same place otherwise call sort predicate.
As you asked how check if an element is_list or integer, for that you can always use built-in because those predicates you can't write by yourself.

Given a tree represented in the form of nested lists, how do I traverse it breadth first?

Suppose I have the a tree given in the nested list representation, how do I traverse it breadth first? For example, if I'm given
[1, [2, [3, [4, [3, 5]]]], [3, [4, 5, 2]]]
The output would be
[1,2,3,3,4,4,5,2,3,5]
Also, given a flattened representation of the depth-first order like [1,2,3,4,3,5,3,4,5,2], how do I find the indices of the breadth-first order?
Thanks in advance for any help.
Here's the code in Python:
queue = [1, [2, [3, [4, [3, 5]]]], [3, [4, 5, 2]]]
while queue:
firstItem = queue.pop(0)
if type(firstItem) is list:
for item in firstItem:
queue.append(item)
else:
print('Traversed %d' % (firstItem))
The output is:
Traversed 1
Traversed 2
Traversed 3
Traversed 3
Traversed 4
Traversed 5
Traversed 2
Traversed 4
Traversed 3
Traversed 5
After studying my output and what you specified the output should be in your question, I think my output is more correct. More specifically, the left most 3 in the input list and [4, 5, 2] at the end of the input list are on the same "level", and thus should be traversed 3, 4, 5, 2, as shown from the 4th line to the 7th line of my output.
As for your second question, I think you should ask a separate question because it really is a completely different question.

Object tree traversal in ruby

So... I have the following:
A class with several properties which are retrieved from an .xml file. These properties are if the object is a condition (it has two children) and its name. Basically, the object's children properties are the names of its children.
The .xml looks like this:
<object-2>
<name>Object - 2</name>
<yesChild>Object - 3</yesChild>
<noChild>Object - 4</noChild>
</object-2>
If the noChild is empty, then it means that the object is not a condition. All objects retrieved from the .xml are stored into an array.
What I need is to somehow create a tree out of it and identify all paths that can be taken in order to reach the last element in the array. The algorithm does not need to traverse all nodes, just the ones it needs to reach the last element of the array.
Example:
We have 4 objects: X1, X2, X3 and X4, where X1 is a condition with X2 and X3 as its children then we will have 2 paths that start in X1 and end in X4.
Path 1: X1->X2->X4
Path 2: X1->X3->X4
Thank you.
Since you don't show what format the data is after you parse, I'm going to guess :) Here's how I would store the parsed data in ruby objects (using new-style hash key syntax for clarity):
[ {yes: 2, no: 3},
{yes: 4},
{yes: 4},
{yes: -1} ]
Then, tree-traversal can be done recursively. As long as your arrays aren't several thousands of elements long, this will work fine.
def tree(object_number, list)
if object_number == list.size
[[object_number]]
else
list[object_number-1].values.map { |obj_num|
tree(obj_num,list)
}.inject{|a,b| a+b}.map{|l| [object_number] + l}
end
end
Now you call the function:
tree(1,data)
=> [[1, 2, 4], [1, 3, 4]]
data = [ {yes: 2, no: 3}, {yes: 4, no:5}, {yes:5, no:4}, {yes:5}, {yes: -1} ]
tree(1,data)
=> [[1, 2, 4, 5], [1, 2, 5], [1, 3, 5], [1, 3, 4, 5]]
How it works: The easiest way to build this list is backwards, since we only know the number of paths once we have gotten to the end of all of them. So this code follows the references all the way to the end, and when it gets to the last object, it returns it as a single-element two dimensional array.
tree(5,list)
=> [[5]]
at each level of recursion, it takes the results of it's recursion call (returned as a list of lists) and prepends it's own object number to each of the interior lists. So, following back up the tree:
tree(4,list) # prepends 4 to tree(5)
=> [[4,5]]
tree(3,list) # prepends 3 to tree(4) and tree(5)
=> [[3,4,5],[3,5]]
tree(2,list) # prepends 2 to tree(4) and tree(5)
=> [[2,4,5],[2,5]]
tree(1,list) # prepends 1 to tree(2) and tree(3)
=> [[1, 2, 4, 5], [1, 2, 5], [1, 3, 5], [1, 3, 4, 5]]
If the lists might be long enough to overflow your stack, it is always possible to do this without recursion. Recursion is just the simplest way for this particular problem.

Resources