How to implement a Binary Search Tree in Julia? - julia

I am trying to implement BST in Julia, but I encountered problem when I call insert function. When I try to create new node, the structure stays unchanged.
My code:
type Node
key::Int64
left
right
end
function insert(key::Int64, node)
if node == 0
node = Node(key, 0, 0)
elseif key < node.key
insert(key, node.left)
elseif key > node.key
insert(key, node.right)
end
end
root = Node(0,0,0)
insert(1,root)
insert(2,root)
I also tried to change zero to nothing. Next version which I tried is with defined datatypes in Node, but when I try to call insert with nothing value(similar to C Null) it gave me error.
Thank for answer.

The code has a number of issues.
One is that it is not type stable, left and right could contain anything.
The other is that setting the local variable node inside the insert function will not affect change anything.
A stylistic issue, functions that modify their arguments generally have a ! as the last character in the name, such as insert!, push! setindex!.
I think the following should work:
type BST
key::Int
left::Nullable{BST}
right::Nullable{BST}
end
BST(key::Int) = BST(key, Nullable{BST}(), Nullable{BST}())
BST() = BST(0)
function Base.push!(node::BST, key)
if key < node.key
if node.left.isnull
node.left = BST(key)
else
push!(node.left.value, key)
end
elseif key > node.key
if node.right.isnull
node.right = BST(key)
else
push!(node.right.value, key)
end
end
end
root = BST()
push!(root, 1)
push!(root, 2)
This version overloads the Julia push! function, and uses the Nullable type so that it can distinguish between a leaf node and where it needs to continue searching to find where to insert the key. This is a recursive definition, and is not optimized, it would be much faster to do it with loops instead of recursive.

Related

Confusion about recursion for BST

Is there an easy way to understand when you can just call the recursive method vs having to set that recursive method to a variable?
For example...
Just calling the recursive function to traverse:
self.recurse(node.left)
self.recurse(node.right)
Having to set the recursive function to node.left and node.right:
node.left = self.recurse(node.left)
node.right = self.recurse(node.left)
Another example is to delete a node in a bst you have to set the recursive function to root.left and root.right... I get it but not completely... is there a easy way to understand when you can just call the recursive function vs having to set it to node.left, node.right..etc...?
def deleteNode(self, root: TreeNode, key:int) -> TreeNode:
if not root:
return root
if key < root.val:
root.left = self.deleteNode(root.left,key)
elif key > root.val:
root.right = self.deleteNode(root.right,key)
else:
if not root.left:
return root.right
elif not root.right:
return root.left
root.val = self.successor(root.right)
root.right = self.deleteNode(root.right,root.val)
return root
To understand this two above scenarios (Simple Recursive Call and Set result of Recursive call to a Variable), just try to understand the following code/function.
Let's say, you have a TREE, which contains a value in every node where value is either negative or positive. Now let's say, you are going to count how many nodes are there whose value is Positive.
The TREE structure for this problem is like following:
TREE{
Integer val;
TREE left = right = null;
}
Now you gave me this problem to solve. And I wrote a function/method which will count nodes with positive value. The function is following:
Integer countNodes(TREE node){
if(node == null){
return 0;
}else{
Integer count = 0; // which will count how many nodes are there with positive value
if(node.val >= 0){
count += 1; // if the value is positive I incremented count
}
// and we are checking every other nodes present in the TREE
getCount(node.left);
getCount(node.right);
// and return the final result
return count;
}
}
Now I returned my function to you, and you executed! But what! There is a big WRONG! It's giving wrong result, over and over again!!
But why???
Let's analysis.
if(node.val >= 0){
count += 1;
}
Up to that we were right! But the problem was, we were incremented the count, but wasn't use it! Each time we was calling function recursively, a new stack frame was created, a new variable named "count" was created, but we were not using this value!
To use the variable "count", we need to re-initialize the returned value of every recursive call to the variable, that's the way we can keep a link between the current stack-frame and the previous stack-frame and the previous of previous stack-frame and goes onn!.. we need to change little-bit in the function countNodes like following:
if(node.val >= 0){
count += 1;
}
count += getCount(node.left); // re-initialize count in each recursive call
count += getCount(node.right); // re-initialize count in each recursive call
return count;
Now everything we'll be alright! this code will work perfectly!
The above scenarios is implies your problem.
self.recurse(node.left)
self.recurse(node.right)
this is nothing but simple traversing over all the nodes.
But if you need to use the returned result of every recursion, you need to initialize/re-initialize the returned value to a variable. That's what is happening with:
node.left = self.recurse(node.left)
node.right = self.recurse(node.left)
I HOPE this long (bit long) explanation will help to go further. Happy Coding! : )

How to find if item is contained in Dict in Julia

I'm fairly new to Julia and am trying to figure out how to check if the given expression is contained in a Dict I've created.
function parse( expr::Array{Any} )
if expr[1] == #check here if "expr[1]" is in "owl"
return BinopNode(owl[expr[1]], parse( expr[2] ), parse( expr[3] ) )
end
end
owl = Dict(:+ => +, :- => -, :* => *, :/ => /)
I've looked at Julia's documentation and other resources, but can't find any answer to this.
"owl" is the name of my dictionary that I'm trying to check. I want to run the return statement should expr[1] be either "+,-,* or /".
A standard approach to check if some dictionary contains some key would be:
:+ in keys(owl)
or
haskey(owl, :+)
Your solution depends on the fact that you are sure that 0 is not one of the values in the dictionary, which might not be true in general. However, if you want to use such an approach (it is useful when you do not want to perform a lookup in the dictionary twice: once to check if it contains some key, and second time to get the value assigned to the key if it exists) then normally you would use nothing as a sentinel and then perform the check get_return_value !== nothing (note two = here - they are important for the compiler to generate an efficient code). So your code would look like this:
function myparse(expr::Array{Any}, owl) # better pass `owl` as a parameter to the function
v = get(expr[1], owl, nothing)
if v !== nothing
return BinopNode(v, myparse(expr[2]), myparse(expr[3]))
end
# and what do we do if v === nothing?
end
Note that I use myparse name, as parse is a function defined in Base, so we do not want to have a name clash. Finally your myparse is recursive so you should define a second method to this function handling the case when expr is not an Array{Any}.
I feel like an idiot for finding this so fast, but I came up with the following solution: (Willing to hear more efficient answers however)
yes = 1
yes = get(owl,expr[1],0)
if yes != 0
#do return statement here
"yes" should get set equal to 0 if the expression is not found in the dictionary "owl". So a simple != if statement to see if it's zero fixes my problem.

How to define the type of a Binary Search Tree in Julia?

I try to define the type of a Binary Search Tree of integers in Julia with the following :
mutable struct BST
key::Int
left::Union{BST, Nothing}
right::Union{BST, Nothing}
end
Now I would like to define the constructors and the basic Push! method using this naive approach :
BST(key::Int) = BST(key, Nothing, Nothing)
BST() = BST(0)
function Base.push!(node::BST, key)
if key < node.key
if node.left.isnull
node.left = BST(key)
else
push!(node.left.value, key)
end
elseif key > node.key
if node.right.isnull
node.right = BST(key)
else
push!(node.right.value, key)
end
end
end
root = BST()
push!(root, 1)
push!(root, 2)
Of course it does not work with Julia 1.0 ! I certainly don't understand properly the use of union. Are they only abstract type ? What could be the correct way to define this data-structure ?
Julia documentation is poor at explaining this topic.
A previous question adressed the subject with the now deprecated Nullable type:
How to implement a Binary Search Tree in Julia?
Here is how the code should look like (it assumes that you do not want to store duplicate values in your BST, but I guess this is what you wanted):
BST(key::Int) = BST(key, nothing, nothing)
BST() = BST(0)
function Base.push!(node::BST, key)
if key < node.key
if node.left === nothing
node.left = BST(key)
else
push!(node.left, key)
end
elseif key > node.key
if node.right === nothing
node.right = BST(key)
else
push!(node.right, key)
end
end
end
Actually your definitions were almost OK, with minor syntactic problems:
nothing is a value and Nothing is a type so you had to write BST(key, nothing, nothing) not BST(key, Nothing, Nothing)
you test if something is nothing using this kind of comparison node.left === nothing (use === as then compiler can optimize this code more easily)
you had to push! to a BST object not to a value stored in it so push!(node.right, key) not push!(node.right.value, key)

Ada String Concatenation

I have a function that returns a string for a particular item, and I need to call that function numerous times and combine those strings into one. The combined string is bounded. I've made sure to fill it when space characters when it initializes but I keep getting "length check failed" errors. Is there something basic I'm doing wrong here?
FOR I IN 1..Collection.Size LOOP
Combined_String := combined_string & Tostring(Collection.Book(I));
END LOOP;
Unbounded_String is probably the easiest way to go:
with Ada.Strings.Unbounded;
use Ada.Strings.unbounded;
...
Temp_Unbounded_String : Unbounded_String; -- Is empty by default.
...
for I in 1 .. Collection.Size loop
Append(Temp_Unbounded_String, ToString(Collection.Book(I));
end loop;
If you then need to have the result placed in your fixed length standard string:
declare
Temp_String : constant String := To_String(Temp_Unbounded_String);
begin
-- Beware! If the length of the Temp_String is greater than that of the
-- fixed-length string, a Constraint_Error will be raised. Some verification
-- of source and target string lengths must be performed!
Combined_String(Temp_String'Range) := Temp_String;
end;
Alternatively, you can use the Ada.Strings.Fixed Move() procedure to bring the Unbounded_String into the target fixed-length string:
Ada.Strings.Fixed.Move(To_String(Temp_Unbounded_String), Combined_String);
In this case, if the source string is "too long", by default a Length_Error exception is raised. There are other parameters to Move() that can modify the behavior in that situation, see the provided link on Move for more detail.
In order to assign Combined_String, you must assign the full correct length at once. You can't "build up" a string and assign it that way in Ada.
Without seeing the rest of your code, I think Ada.Strings.Unbounded is probably what you should be using.
I know this is an ancient question, but now that Ada 2012 is out I thought I'd share an idiom I've been finding myself using...
declare
function Concatenate(i: Collection'index)
is
(tostring(Collection(i) &
if (i = Collection'last) then
("")
else
(Concatenate(i+1))
);
s: string := Concatenate(Collection'first);
begin
Put_Line(s);
end;
Typed off the top of my head, so it'll be full of typos; and if you want it to work on empty collections you'll need to tweak the logic (should be obvious).
Ada 2012's expression functions are awesome!
Ada works best when you can use perfectly-sized arrays and strings. This works wonderfully for 99% of string uses, but causes problems any time you need to progressively build a string from something else.
Given that, I'd really like to know why you need that combined string.
If you really need it like that, there are two good ways I know of to do it. The first is to use "unbounded" (dynamically-sized) strings from Ada.Strings.Unbounded, as Dave and Marc C suggested.
The other is to use a bit of functional programming (in this case, recursion) to create your fixed string. Eg:
function Combined_String (String_Collection : in String_Collection_Type) return String is
begin
if String_Collection'length = 1 then
return String_Collection(String_Collection'first);
end if;
return String_Collection(String_Collection'first) &
Combined_String (String_Collection'first + 1 .. String_Collection'last);
end Combined_String;
I don't know what type you used for Collection, so I'm making some guesses. In particular, I'm assuming its an unconstrained array of fixed strings. If it's not, you will need to replace some of the above code with whatever your container uses to return its bounds, access elements, and perform slicing.
From AdaPower.com:
function Next_Line(File : in Ada.Text_IO.File_Type :=
Ada.Text_Io.Standard_Input) return String is
Answer : String(1..256);
Last : Natural;
begin
Ada.Text_IO.Get_Line(File => File,
Item => Answer,
Last => Last);
if Last = Answer'Last then
return Answer & Next_Line(File);
else
return Answer(1..Last);
end if;
end Next_Line;
As you can see, this method builds a string (using Get_Line) of unlimited* length from the file it's reading from. So what you'll need to do, in order to keep what you have is something on the order of:
function Combined_String (String_Collection : in String_Collection_Type)
Return String is
begin
if String_Collection'length = 1 then
Return String_Collection(String_Collection'First).All;
end if;
Recursion:
Declare
Data : String:= String_Collection(String_Collection'First).All;
SubType Constraint is Positive Range
Positive'Succ(String_Collection'First)..String_Collection'Last;
Begin
Return Data & Combined_String( String_Collection(Constraint'Range) );
End Recursion;
end Combined_String;
Assuming that String_Collection is defined as:
Type String_Collection is Array (Positive Range <>) of Access String;
*Actually limited by Integer'Range, IIRC

Delete key in map

I have a map:
var sessions = map[string] chan int{}
How do I delete sessions[key]? I tried:
sessions[key] = nil,false;
That didn't work.
Update (November 2011):
The special syntax for deleting map entries is removed in Go version 1:
Go 1 will remove the special map assignment and introduce a new built-in function, delete: delete(m, x) will delete the map entry retrieved by the expression m[x]. ...
Go introduced a delete(map, key) function:
package main
func main () {
var sessions = map[string] chan int{};
delete(sessions, "moo");
}
Copied from Go 1 release notes
In the old language, to delete the entry with key k from the map represented by m, one wrote the statement,
m[k] = value, false
This syntax was a peculiar special case, the only two-to-one assignment. It required passing a value (usually ignored) that is evaluated but discarded, plus a boolean that was nearly always the constant false. It did the job but was odd and a point of contention.
In Go 1, that syntax has gone; instead there is a new built-in function, delete. The call
delete(m, k)
will delete the map entry retrieved by the expression m[k]. There is no return value. Deleting a non-existent entry is a no-op.
Updating: Running go fix will convert expressions of the form m[k] = value, false into delete(m, k) when it is clear that the ignored value can be safely discarded from the program and false refers to the predefined boolean constant. The fix tool will flag other uses of the syntax for inspection by the programmer.
From Effective Go:
To delete a map entry, use the delete built-in function, whose arguments are the map and the key to be deleted. It's safe to do this even if the key is already absent from the map.
delete(timeZone, "PDT") // Now on Standard Time
delete(sessions, "anykey")
These days, nothing will crash.
Use make (chan int) instead of nil. The first value has to be the same type that your map holds.
package main
import "fmt"
func main() {
var sessions = map[string] chan int{}
sessions["somekey"] = make(chan int)
fmt.Printf ("%d\n", len(sessions)) // 1
// Remove somekey's value from sessions
delete(sessions, "somekey")
fmt.Printf ("%d\n", len(sessions)) // 0
}
UPDATE: Corrected my answer.

Resources