Binary Search Tree - Delete - binary-search-tree

I am trying to write a program that takes in strings and places them in a binary search tree in alphabetical order once these are inserted into the tree, a user prompts for one word to be deleted, thus deleting that node from the tree, and then output the tree without that node back in order.
Everything works for this up to the delete function, the delete function does work, but its very weird how it deletes. I think currently it deletes a full side of the tree, because when I delete the last word, it typically works. I will upload my delete function and if more is needed I can upload the rest of my code.
Thanks!
template<typename T> void Delete(TreeNode<T>*& root, const T& data)
{
if (root == NULL)
return;
if(data < root->Value)
return Delete(root->Left, data);
else if (root->Value > data)
return Delete(root->Right, data);
else
{
TreeNode<T>* old_root = root;
if (root->Left == NULL)
{
root = root->Right;
}
else if (root->Right == NULL)
{
root = root->Left;
}
else
{
replace_parent(old_root, old_root->Left);
}
delete old_root;
}
};
template<typename T> void replace_parent(TreeNode<T>*& old_root, TreeNode<T>*& root)
{
if (root->Right != NULL)
{
replace_parent(old_root, root->Right);
}
else
{
old_root->Value = root->Value;
old_root = root;
root = root->Left;
}
};

Lacqui is correct in his points.
let me tell you you that while deleting a node you need to replace it with either the max node in left sub tree or the minimum node in the right sub tree. for example:
if you see the below picture:
if you want to delete the node 90,you need to take care that you replace it with either 80 which is its max node in the left subtree or the 92 which the minimum node in the right sub tree. you can keep any one approach.
so the algo will be :
considering the left sub tree:
->if you find the node to delete,navigate to the max value in its left sub tree.
->assign the node's left as 50 and node right to be 150
->make 75->next as null and delete 90

Your cases for either left or right being NULL are good. However, your logic for neither of them being NULL is, unfortunately, failing.
If I'm reading your code (and understanding the function replace_parent() correctly, then if neither tree is empty you are replacing the current root with Left.
Ask yourself - what is happening to the values that are in the Right subtree?
What you need to do in order to delete a node is as follows:
Enter one of the subtrees. It looks like you've chosen your Left subtree, so we'll go from there.
Follow the opposite line of branches. In this example, keep going down the Right subtrees from your original Left. Keep going until you find a right-leaf node (no Right subtrees; Left is OK)
Remember the value of your right-leaf in a tmp variable.
Transfer the right-leaf's Left (whether NULL or not) to the right-leaf's position.
Take the tmp value and put it into your original 'to-delete' node.

Related

How to implement Linked List Recursion in KOtlin

I am learning linked list and came across a problem where you are required to reverse a linked list using recursion. Here is the code I wrote:
fun reverseRecurseTraverse1(firstNode: Node<Int>?): Node<Int>? {
if (firstNode?.next == null) {
return firstNode
} else {
val finalNode = reverseRecurseTraverse1(firstNode.next)
finalNode?.next = firstNode
firstNode.next = null
return finalNode
}
}
Input:
01234
Output:
40
I get the desired output If I change the line from
finalNode?.next = firstNode
to
firstNode.next!!.next = firstNode
What am I doing wrong here?
When I try to whiteboard finalNode?.next = firstNode makes perfect sense to me and based on my understanding those two lines are essentially doing the same thing.
Kindly help me understand this.
It would be useful if you share your "whiteboard logic" and why do you assume finalNode?.next = firstNode is correct and functionally the same as firstNode.next!!.next = firstNode.
Let's get your example: 01234. In the first step firstNode is 0 and after reversing of the remaining sublist, we get 4321. finalNode points at the first element of this reversed sublist, so at 4. Then you add 0 after 4 which is wrong. You should add 0 after 1.
On the other hand, firstNode.next is still pointing at the item that was next to 0 in the original list. It points at 1. By assigning to its next we add 0 where it should be - after 1.
You are almost there, but one line is wrong.
What you are doing is:
If your item is null, return it. That seems okay.
If your item is already the last item, return it as first item. Also looks okay.
If your item is not the last item, reverse the rest of the list. Okay.
Take the old last and now first item, and append your old first now last item to it? That doesn't seem right. Don't you want to append your old first and now last item to the last item of the reversed rest?
It would probably help to write a function
fun Node.last(): Node? = if(next == null) this else next!!.last()
that provides the last item of a linked list.
You could use that to append your previously first item to the last item of the reversed rest.
Considering a call reverseRecurseTraverse1(x), can we maybe always tell what reverseRecurseTraverse1(x).last() is without calculating it?

Non-greedy configurations across steps

I'm using late acceptance as local search algorithm and here is how it actually picks moves:
If my forager is 5, it'll pick 5 moves and then get 1 random move to be applied for every step.
At every step it only picks moves that are increasing scores ie greedy picking across steps.
Forager.pickMove()
public LocalSearchMoveScope pickMove(LocalSearchStepScope stepScope) {
stepScope.setSelectedMoveCount(selectedMoveCount);
stepScope.setAcceptedMoveCount(acceptedMoveCount);
if (earlyPickedMoveScope != null) {
return earlyPickedMoveScope;
}
List<LocalSearchMoveScope> finalistList = finalistPodium.getFinalistList();
if (finalistList.isEmpty()) {
return null;
}
if (finalistList.size() == 1 || !breakTieRandomly) {
return finalistList.get(0);
}
int randomIndex = stepScope.getWorkingRandom().nextInt(finalistList.size());// should have checked for best here
return finalistList.get(randomIndex);
}
I have two questions:
In first, can we make forager to pick the best of 5 instead of pick 1 randomly.
Can we allow move to pick that degrades score but can increase score later(no way to know it)?
Look for acceptedCountLimit and selectedCountLimit in the docs. Those do exactly that.
That's already the case (especially with Late Acceptance and Simulated Annealing). In the DEBUG log, just look at the step score vs the best score. Or ask for the step score statistic in optaplanner-benchmark.

How to check if a Gun unordered list is empty?

Given the following, how would one go about determining if the machines list is empty in order to add a machine?
let gun = new Gun();
let machines = gun.get('machines');
How do I check if the machines list is empty?
This from Mark Nadal:
// machineId and location defined elsewhere
machines.val(table => {
if (Gun.obj.empty(table, '_') {
// table is empty so we can add something to it
let machine = gun.get('machine/' + machineId);
machine.put({machineId, location}};
machines.set(machine);
} else {
// table is not empty
})
table is a data node that has all the row pointers in it (not the actual sub-objects)
so if table has 0 items on it, then it is empty! Or if table is null or undefined
HOWEVER, gun has its {_: {...}} meta data it includes on every node, so you need to ignore that.
Gun.obj.empty({}) tests if an object is empty (you can use lodash or something else), the second parameter tells it to IGNORE a key, like in this case '_'. So it will still say that yes it is empty if it has 0 properties other than the metadata property.

Searching through two for loops without repeating the result.

I have a task where I am trying to check an array list of "jobs" against an array list of "machines" (all different types) and if the first three letters off the job match the first three letters off the machine (e.g. a PRT job code could only be assigned to a machine with code PRT). I want it to accept the job but if not I would like it to print out a message saying that there is no available machine. I have only been learning Java for a couple of weeks so this might not be the best way:
public void assignJob() {
for(Job j : jobs) {
String jobCode = j.getCode().substring(0, 3);
for(Machine m : machines) {
String machineCode = m.getCode().substring(0,3);
if (jobCode.equals(machineCode)){
m.acceptJob(j);
System.out.println("The job " + j.getCode() + " has been
assigned to a machine.");
break;
}
else {
System.out.println("Sorry there is no machine available to accept the type of job: " + j.getCode() );
}
}
}
}
The issue I am getting is that it is printing out the message every time it goes around the loop so it will say there is no machine available 3 times before it finds the correct machine the fourth time and then says the job has been accepted. I only really want the message one time and only after it has searched and not found anything.
Any help would be appreciated.
Use a boolean found = false; above the outer for loop, move else part of if statement below the outer for loop and make it an if statement. If you've found your match then set found = true; and break loops. Then check if it is found, display message if not found...

BaseX - insert node {...} into //.. for multiple nodes

I am currently facing a problem with the BaseX native XML-Database.
I have got a sample dataset where I want to check whether a certain attribute in a certain node exists and if it does then set a value "true". If it doesn't exist I want to insert a new attribute. This is my code for a single Node:
if(fn:exists(//Dataset[#attribute="2"]/#b)) then
replace value of node //Dataset[#attribute="2"]/#b with "true"
else
insert node (attribute { 'b' } { "CREATED!" }) into //Dataset[#attribute="2"]
The problem I am facing at the moment is that I cannot find a way of iterating through all nodes of the type "Dataset" for example and check every single node.. It always says "Single element or document expected as insert target".
Okay, Googled for a long time but 15 minutes more would have saved me from posting this question:
for $dataset in //mondial/Dataset
let $DOCH := $dataset/#DOCH
return
if(fn:exists($DOCH)) then (
replace value of node $DOCH with "true")
else (
insert node (attribute DOCH {"true"}) into $dataset)