Binary Search Tree StudentDatabase - java

Consider that I have a generic binary search tree. I have students' class and I keep the student's id as a key in bst. Then I want to search these students according to their name and I want to delete one of them. But I keep students according to their id's. How can I search them according to their name? Please give me the information. (Java language)

You can have 2 BSTs, key of one is id and for another is name. So you can access an element by their name or id both in O(log n) time.
This will double the memory and time requirements for your data structure. (Only insertions and deletions will take double time. The other operations will take no extra time). However, recall that O(2 log n) is generally treated the same as O(log n).
You cannot do better than this using BSTs. Since you need to search based on name in O(log n) time, name must be the key for the tree. However, you also need to retrieve the users by id therefore, id must also be a key for the tree. Hence, you need two trees.

Assuming your BST contains student objects as a node with left and right pointers. You can implement search method as shown below:
public Student search(Student root, String key)
{
if (root == null)
{
return null;
}
Student result1 = search(root.left, key);
if(result1 != null)
{
return result1;
}
if(key.equals(root.studentName))
{
return root;
}
Student result2 = search(root.right, key);
if(result2 != null)
{
return result2;
}
return null;
}

Related

Deleting a node from a Binary Search Tree using only a node's key

I'm adding some functions/working with a pre-written program (a customer account database), which uses a Binary Search Tree, and I'm trying figure out how and why this remove method works:
public void deleteCustomer()
{
System.out.println("Enter the account number of the customer to be removed.");
String accountNumber = userInput.next();
try {
records.remove(new CustomerAccount(accountNumber));
}
catch(ElementNotFoundException e) {
System.out.println("There is no account with that number.");
}
}
Where CustomerAccount is an object that contains the accountNumber field, and records is a BST. The records' remove function looks like this:
public boolean remove(E target) {
return delete(target) != null;
}
and recursively calls a standard looking delete function for a BST. But my question is, what is actually happening with this line?
records.remove(new CustomerAccount(accountNumber));
It's calling the method using a new CustomerAccount? What's actually happening under the hood here? And is this a standard way of dealing with this situation? I've never seen anything like it, but I'm newish to working with data structures so I'm not sure. Any help or clarification would be fantastic, thank you!

Recursively finding words in a hashmap using tries

My method should add the associated key/value pair to the trie and if the key is already in the trie, the value should be updated. However I am not quite sure what Im doing wrong, its my first time using tries.
So I am currently working on my put method and I have the following:
public void put(TrieMapNode current, String curKey, String value){
if(current.getChildren().containsKey(curKey))
value = current.get(key);
curKey =value;
put(current.getChildren().get(curKey), curKey, value);
}
Any help would be greatly appreciated thanks!
In your current implementation, you will not benefit from the advantages of a trie. That is because at the root node, you have one child for each string you encounter.
That is not the way a trie is built. Each node of your trie can have at most one child per character (the elements that form strings).
So your method should look more like the following:
public void put(TrieMapNode current, String key, String value, int depth){
if (depth == key.length()){
current.value = value;
} else {
char curChar = key.charAt(depth);
if(!current.getChildren().containsKey(curChar)){
TrieMapNode newNode = new TrieMapNode();
current.getChildren().put(curChar, newNode);
}
put(current.getChildren().get(curChar), curKey, value, depth + 1);
}
The main mistake you did was to consider the key as a whole when inserting/updating in your trie. This would have resulted in a root node having one child node for each key in your map (so a ton of children), but with a very limited depth (the root node, its children and that's it).
In the implementation I proposed you, a node has one child per possible character (a bounded number, 26, 52, anyway a small and bounded number).
And its depth is not limited to one, because as you can see in the else block, we create a node if the one we look for did not exist (when you start you only have a root node, so you need to plan for the case where new node are created), and we also call recursively put on a child of the current node. So the value will be stored at a depth equal toi the length of its key.

"Simple" Trie Implementation

I need to implement a Trie (in Java) for a college project. The Trie should be able to add and remove Strings (for phase 1).
I have spent several hours each day (for the last few days) trying to figure out how to do this and FAILED miserably each time.
I require some help, the examples on the internet and my textbook (Data Structures and Algorithms in Java By Adam Drozdek) are not helping.
Information
Node classes I am working with:
class Node {
public boolean isLeaf;
}
class internalNode extends Node {
public String letters; //letter[0] = '$' always.
//See image -> if letter[1] = 'A' then children[1] refers to child node "AMMO"
//See image -> if letter[2] = 'B' then children[2] refers to internal node "#EU"
public TrieNode[] children = new TrieNode[2];
public TrieInternalNode(char ch)
{
letters = "#" + String.valueOf(ch);//letter[0] = '$' always.
isLeaf = false;
}
}
class leafNode extends Node
{
public String word;
public TrieLeafNode(String word)
{
this.word = new String(word);
isLeaf = true;
}
}
And here is the pseudo code for insert that I need to follow: (warning it is very vague)
trieInsert(String K)
{
i = 0;
p = the root;
while (not inserted)
{
if the end of word k is reached
set the end-of-word marker in p to true;
else if (p.ptrs[K[i]] == 0)
create a leaf containing K and put its address in p.ptrs[K[i]];
else if reference p.ptrs[K[i]] refers to a leaf
{
K_L = key in leaf p.ptrs[K[i]]
do
{
create a nonleaf and put its address in p.ptrs[K[i]];
p = the new nonleaf;
} while (K[i] == K_L[i++]);
}
create a leaf containing K and put its address in p.ptrs[K[--i]];
if the end of word k is reached
set the end-of-word marker in p to true;
else
create a leaf containing K_L and put its address in p.ptrs[K_L[i]];
else
p = p.ptrs[K[i++]];
}
}
I need to implement the following methods.
public boolean add(String word){...}//adds word to trie structure should return true if successful and false otherwise
public boolean remove(String word){...}//removes word from trie structure should return true if successful and false otherwise
I cant find pseudo code for remove, but if insert does not work delete wont help me.
Here is a image of how the Trie that I need to implement should look like.
I am aware that the Trie will still be inefficient if implemented like this, but at the moment I need not worry about this.
The book provides an implementation that is similar to what I need to do but doesn't use the end of word char ('$') and only stores the words without their prefixes in the child nodes http://mathcs.duq.edu/drozdek/DSinJava/SpellCheck.java
Constraints
I need to implement the trie in JAVA.
I may not import or use any of Java's built-in data structures. (ie. no Map, HashMap, ArrayList etc)
I may use Arrays, Java primitive Types and Java Strings.
The Trie must use a $ (dollar) symbol to indicate a end-of-word. (see the image below )
I may asume that now word containing the $symbol will be inserted.
I need to implement the Trie it in the same style as the book does.
Case of words doesn't matter ie. all words will be considered to be lowercase
The Trie should only store the end-of-word character and the characters applicable to a word and not the entire alphabet(like some implementations).
I do not expect anyone to do the implementation for me(unless they have one lying around :P) I just really need help.
First of all, I don't think you should make leaf nodes and internal nodes separate classes. I recommend making a universal node class with an isLeaf() method. This method would return true if a node has no children.
Here is some higher-level pseudocode for the functions you need to implement. For simplicity, I assume the existence of a method called getIndex() which returns the index corresponding to a character.
Insert(String str)
Node current = null
for each character in str
int index = getIndex(character)
if current.children[index] has not been initialized
initialize current.children[index] to be a new Node
current = current.children[index]
You can easily augment this pseudocode to fit your needs. For example, if you want to return false whenever insertion isn't successful:
Return false if the input string is null
Return false if the input string contains invalid characters
Now, here is some higher-level pseudocode for remove.
Remove(String str)
Node current = null
for each character in str
int index = getIndex(character)
current = current.children[index]
// At this point, we found the node we want to remove. However, we want to
// delete as many ancestor nodes as possible. We can delete an ancestor node
// if it is not need it any more. That is, we can delete an ancestor node
// if it has exactly one child.
Node ancestor = current
while ancestor is not null
if ancestor has 2 or more children
break out of loop
else if ancestor has less than 2 children
Node grandAncestor = ancestor.parent
if grandAncestor is not null
reinitialize grandAncestor.children // this has the effect of removing ancestor
ancestor = ancestor.parent
At a very high level, we follow the input string to the node we want to remove. After this, we traverse up the tree following parent pointers and delete every node with 1 child (since it is no longer needed). Once we reach a node with 2 children, we stop.
Like Insert, we can easily augment this pseudocode to return false whenever deletion isn't successful:
Return false if the input string is null
Return false if the input string contains invalid characters
Return false if the input string leads to a Node which doesn't exist
It is easiest to implement delete if your Node class has a parent field. However, it is possible to implement the method without parent points, but it is more difficult. You can see an example of the trickier implementation here.

Use binary search if sorted otherwise use linear search

I'm given a problem where the user is given an empty recipe book and they can input and sort the recipes.
I know that a book is sorted if it is empty, has one recipe, and two recipes(ascending/descending). These can use binary search.
But when the user inputs a third recipe it could be either "cookies, donut, turkey" (which is sorted) or "cookies, donut, apples" and that's not sorted. If it's not sorted then I have to use linear search.
This is what I have so far
public void sortBook(int choice, boolean ascend) {
RecipeBookComparator comparing = new RecipeBookComparator(choice, ascend);
mList.sort(comparing);}
public class RecipeBookComparator implements Comparator {
private int mSortRBook;
private boolean mAscend;
public RecipeBookComparator (int choice, boolean ascend) {
mSortRBook = choice;
mAscend = ascend;
}
public int compare(Object o1, Object o2) {
Recipe s1 = (Recipe)o1, s2 = (Recipe)o2;
switch (mSortRBook) {
case 1:
if (mAscend == true) {
int compareName = s1.getName().compareTo(s2.getName());
if (compareName != 0) {
return compareName;
}
}
else {
int compareName = s1.getName().compareTo(s2.getName());
if (compareName != 0) {
return compareName * -1;
}
} ///more cases...
I know what I'm supposed to do, but I don't know how to approach it "code-wise"
To find out if a list is sorted, you would have to compare each element with ist neighbors. If only one element of thousands is not in order, a binary search can fail. So you would have to check the complete list. But going through all the list to check if the list is sorted takes longer than to look for one element in the list with linear search, so that makes no sense. Use linear search, if you don't know for sure if a list is sorted or not. That's it.
Your code says:
mList.sort(comparing);
I believe you've misunderstood what you've been asked to do - assuming that "use binary search if sorted otherwise use linear search", the title of your question, is what you are supposed to do. You are not supposed to sort them at all. This problem requires no knowledge of how to sort things in Java whatsoever.
What you need to understand is searching, not sorting. And how to check whether a sequence of inputs is already sorted.
Now, admittedly, technically you can check if a sequence is already sorted by actually sorting it and then checking if the resulting sequence is in the same order as what you started with. But I wouldn't recommend that.
What I would recommend, instead, is using a Comparator to compare each pair of adjacent elements (if any) in the sequence, to check if the sequence is monotonically increasing or monotonically decreasing.

Test if two binary search trees has the same set of elements?

I am just starting out with java and recursive methods and i need some help:
I need to determine if two Binary Search Trees has exactly the same set of elements, regardless of the structure of the tree.
I have written a method that checks if the the tree contains an element and its called contains()
this is what i got so far:
public boolean sameContents(Node n2) {
if (contains(n2, n2.key) && n2.left == null && n2.right == null) { return true; }
if (contains(n2, n2.key) && n2.left != null) { sameContents(n2.left); }
if (contains(n2, n2.key) && n2.right != null) { sameContents(n2.right); }
return false;
}
Basicly my idea is that the method is running as long as a node still has a child, and if the trees match.
I call the method with for example testTree1.sameContents(testTree2); but the method always returns false...
Can someone point out how this should be done?
The best way to do this is with an Iterator object - if two binary search trees contain the same elements then their iterators' next methods should return the same values (even if their structures are different).
// returns true if the trees are equivalent, else false
Iterator itr1 = tree1.getIterator();
Iterator itr2 = tree2.getIterator();
while(itr1.hasNext() && itr2.hasNext()) {
if(!itr1.next().equals(itr2.next())) {
return false;
}
}
return !itr1.hasNext() && !itr2.hasNext(); // returns true if trees were the same size, else false
You ought to already have an inorder binary tree traversal method, so you've already got an Iterator - just add an ArrayList/Stack to take the place of the call stack so that you can pause the traversal (whenever you would be making a recursive method call, store the current node to your Stack)
There is another way to do that. You can convert your trees into string representations, using pre-order traversal or in-order traversal. It will take O(n) time. Than you can check whether these strings equal or not. It can be done in O(n) time too. So, the total running time is O(n).
This method looks similar to the solution with iterators but this one is more generic, since can be used for 'is-subtree' task (chechs wether tree t1 is subtree of t2). In this case use can use isSubstring() method instead of equals(). If tree t1 is subtree of t2 than t1's string representaion is substring of t2's. The isSubstring() can be done in O(log n) time.
Can you do a inorder traversal on both trees and check if the result of both the traversals are same. If same, could we assume that both trees have the same set of elements.

Categories

Resources