I have been given an assignment to create a 2-3 search tree that is supposed to support a few different operations each divided in to different stages of the assignment.
For stage 1 I'm supposed to suport the operations get, put and size. I'm curently trying to implement the get operation but I'm stuck and I can't wrap my head around how to continue so I'm questioning all of my code I have written and felt like a need someone elses input.
I have looked around how to develop a 2-3 search tree but what I found was alot of code that made no sence to me or it just did not do what I needed it to do, and I wanted to try and make it for my self from scratch and here we are now.
My Node class
package kth.id2010.lab.lab04;
public class Node {
boolean isLeaf = false;
int numberOfKeys;
String[] keys = new String[2]; //each node can contain up to 2 keys
int[] values = new int[2]; //every key contains 2 values
Node[] subtrees = new Node[3]; //every node can contain pointers to 3 different nodes
Node(Node n) {
n.numberOfKeys = 0;
n.isLeaf = true;
}
}
My Tree creating class
package kth.id2010.lab.lab04;
public class Tree {
Node root; // root node of the tree
int n; // number of elements in the tree
private Tree(){
root = new Node(root);
n = 0;
}
//Return the values of the key if we find it
public int[] get(String key){
//if the root has no subtrees check if it contain the right key
if(this.root.subtrees.length == 0){
if(this.root.keys[0] == key){
return(this.root.keys[0].values);
}
else if(this.root.keys[1] == key){
return(this.root.keys[1].values);
}
}
//if noot in root, check its subtree nodes
//and here I can't get my head around how to traverse down the tree
else{
for(int i = 0; i < this.root.subtrees.length; i++){
for(int j = 0; j < this.root.subtrees[i].keys.length; j++){
if(this.root.subtrees[i].keys[j] == key){
return(this.root.subtrees[i].keys[j].values);
}
}
}
}
return null;
}
}
What I can tell for my self is that I need to find a way to bind values[] to each key but I can't figure out a way how. Might be the lack of sleep or that I'm stuck in this way of thinking.
bind values[] to each key
It might make more sense to use a HashMap to do that mapping for you, since that's what it's for. Beyond that, if you have two keys and each key has two values, you have 4 values, not 2 ;)
In general, the get method in a tree structure is almost always implementable recursively. Here is a very general implementation of a get algorithm for a 2-3 tree in psudo-code.
V get<K, V>(Node<K, V> node, K key)
{
if(node.is_leaf())
{
return node.keys.get(key); // This will either return the value, or null if the key isn't in the leaf and thus not in the tree
}
if(key < node.left_key)
{
return get(node.left_child, key); // If our key goes to the left, go left recursively
}
else if(node.two_node && key <= node.right_key)
{
return get(node.center_child, key) // If we have two keys, and we're less than the second one, we go down the center recursively
}
else
{
return get(node.right_child, key); // If we've gotten here, we know we're going right, go down that path recursively
}
}
That should get you started in the right direction. Insertion/deletion for 2-3 trees is a bit more complicated, but this should at least get your head around how to think about it. Hint; Your Node class needs to be doubly-linked, that is each node/leaf needs to reference its parent node as well as its children, and the root is simply a node whose parent is null.
Related
I'm attempting to traverse through a B+ Tree and add the elements from the leaves into an ArrayList with the following code:
public void toArrayList(Node node){
Node currentNode = node;
if(currentNode instanceof InnerNode){
InnerNode inner = (InnerNode) currentNode;
int i = 0;
int temp = inner.children.length;
while(i < temp){
currentNode = inner.children[i];
toArrayList(currentNode);
i++;
}
}
if(currentNode instanceof LeafNode){
LeafNode leaf = (LeafNode) currentNode;
int j = 0;
int temp = leaf.values.length;
while(j < temp){
if(leaf.values[j] != null) {
retArray.add(leaf.values[j]);
}
j++;
}
}
}
What it does is it checks if the node is an instance of an Inner Node or a Leaf Node. If it is an Inner Node it recursively calls the function with each of its children. If it is a Leaf Node then it will add the values into the ArrayList. However while running this fucntion I end up getting a java.lang.OutOfMemoryError.
Is there a way to make my code more efficient or should I look to take a different approach to this method?
Unless your tree structure has a few million elements in it, what's going on here is that some InnerCode contains itself, and thus this code keeps going forever, or, at least, until your retArray fills up.
Also note that this code will add a leaf node twice if it's the last child of an inner node. I strongly suggest you don't overwrite locals like this. Also, for loops are just more compact here (note that making this code smaller is not going to make any difference at all for memory issues; OOMError refers to the heap, and locals don't live there).
Ok so i need to deleted items from a circular list,as part of a bigger program that isnt working, and i cant seem to delete the last node passed in to the delete method, if the index passed in is 1 it will delete the 1st node in list and replace it, but when there is only one node left it has nothing to reference off, been at this hours. i will leave my delete method here
public void delete(int index)
{
if(Node.numOfUsers == 1)
{
first=null;
return;
}
//make curr the same as first node
int i = 1;
curr=first;
//if index passed in is 1, make temporary node same as one after first node
// if(size<1)
// {
// System.out.println("ok so this is where we are at");
// }
if(index==1)
{
temp=first.nextNode;
while(temp.nextNode!=first)
{
temp=temp.nextNode;
}
temp.nextNode=temp.nextNode.nextNode;
first=curr.nextNode;
}
else
{
//as long as i is not equal to node index-1 move current on 1 and increment i by 1
while(i != index-1)
{
curr=curr.nextNode;
i++;
}
//curr.nextNode is pointing to the node index we want and making it equal to one index above it
curr.nextNode=curr.nextNode.nextNode;
}
Node.numOfUsers--;
int size=size();
}
}
Looks like you're keeping track globally of a number of users. If this behaves the way I think it would, you could just have a small check at the beginning of this method so that if it is zero, you don't follow through with any of the logic following it.
if(Node.numOfUsers == 0) return;
This will make it so you don't bother executing any of the other logic.
A slightly better methodology to this problem might be to use the Node you want to delete as a parameter, rather than its index. This way you can avoid having to keep track of indices inside your data structure.
e.g.
public void delete(Node n) {
if(Node.numOfUsers == 0 || n == null) return; // 0 nodes or null parameter.
Node temp = first;
if(temp.next == null) { //only one node
temp = null; //simply delete it
} else {
while(temp.next != n) {
temp = temp.next;
if(temp == first) { //if we circle the entire list and don't find n, it doesn't exist.
return;
}
}
temp.next = n.next; // perform the switch, deleting n
}
}
EDIT: The above code follows the assumption that you'll have references to the node you want to delete. If this is not the case, using indices is just as good. You may also consider comparing values, however this would require you to assume that you have unique values in your nodes (and I don't know what you're restrictions are).
The logic for comparing values would be identical to the above, however instead of comparing if(temp == n) for example, you would compare if(temp.data.equals(n.data)). The use of the .equals() method is specifically for the String type, but you could modify it to work with whatever data type you are expecting, or better yet write a custom .equals method that allows the use of Generics for your abstract data type.
I am trying to change my recursive insert method of the BST into non-recursive( maybe While loop)
The reason for this changing because I want to see if it is possible.
Here is the code of insertion:
public void insert(String value)
{
//The node is stored in the root
root = insert(value,root);
}
private Character insert(String value,Character current)
{
if(current == null)
{
//Add the root if the tree empty
current = new Character(value);
}
else
//If the value that we want to insert < root value, then keep going to left till
//it's empty then inserted at left end. Done by recursion
if(value.compareTo(current.getElement())<=-1)
{
current.setLeft(insert(value,current.getLeft()));
}
else
//If the value that we want to insert > root value, then keep going to right till
//it's empty then inserted at right end. Done by recursion
if(value.compareTo(current.getElement())>=1)
{
current.setRight(insert(value,current.getRight()));
}
else
{
//Else, the number we want to insert in already in the tree
System.out.println("Duplicate numbers inserted" + current.getElement());
}
//returning the node tree so that we store it in the root
return current;
}
Could I change this code into non recursive ?
Cheers
Yes, but you need to alter the data structure a little bit to make it works.
The node has to know its left child and right child.
The algorithm looks like this:
current = root;
while(current != null){
if(value.compareTo(current.getElement())<=-1)
{
current = current.left_child;
}else if(value.compareTo(current.getElement())>=1){
current = current.right_child;
}else{
// Duplication
}
}
Actually there are some good examples before, you may want to check those out first:
Write a non-recursive traversal of a Binary Search Tree using constant space and O(n) run time
Nonrecursive/Iterative Binary Search Tree in C (Homework)
Yes, you could define your insert function non-recursively.
However, to do this, your insert function will have to define in-order traversal iterator for BST, which is recursively defined.
I believe there is a way to define in-order traversal non-recursively, but depending on implementation this can be very inefficient.
BST itself is basically recursively defined, and it is always efficient to define your insert function recursively. (I could write some pseudo-code if you really need it, but I think it is kind of meaningless and I do not know about the implementation detail of your in-order traversal iterator)
Please don't forget to select this as an answer :-)
Insert using while loop
public Node insert(Node root,int n) {
while (true) {
if (root.data>n) {
if (root.left==null) {
root.left= new Node(n);
return (root.left);
}
root=root.left;
}
else if (root.data<n) {
if (root.right == null) {
root.right= new Node(n);
}
}
}
}
I am currently trying to implement a trie data structure for integer tuples. And have implemented as follows:
import java.util.ArrayList;
public class TrieNode {
int num;
ArrayList<TrieNode> links;
boolean endOfTuple;
public TrieNode(int num)
{
this.num = num;
links = new ArrayList<TrieNode>();
this.endOfTuple = false;
}
}
I then have a trie class as follows:
public class Trie {
TrieNode root;
public Trie() {
root = new TrieNode(-1);
}
public void insertTuple(int[] tuple)
{
int l = tuple.length;
TrieNode curNode = root;
for (int i = 0; i < l; i++)
{
TrieNode node = new TrieNode(tuple[i]);
if(!curNode.links.contains(node)){
curNode.links.add(node);
}
curNode = curNode.links.get(curNode.links.indexOf(node));
}
curNode.endOfTuple = true;
}
}
I can add values to this trie, but i need to be able to iterate over this and was wondering how i could do this? For example if i wanted to print the tree using an iterator...Any help will be great...
All you need for an interator is to implement the Iterator interface, which only requires that you supply boolean hasNext() and Integer next(). So the question to ask is: how do represent a position in your trie, such that it's possible to (a) fetch the value associated with that position, and (b) figure out the "next" position given a current one?
I'll refrain from posting an actual solution since I'm not sure whether this is homework. But consider: you can represent a "current position" in your trie just by choosing a particular trie node, and the path of trie nodes you used to reach it. Then you can compute the "next" element recursively: if the current element is a node that has children, then find the first child for which endOfTuple is true. If the current element doesn't have children, then go to its parent and advance to that parent's next child. If that parent doesn't have next children, then go it its parent's next child, etc.
Alright, my professor (Data Structures class) assigned this: Your task is to write a program that can update character access frequencies in a doubly-Link list. The program should read one character at a time from a text file that contain many characters. To make it easier, do not count spaces. Every time a character is accessed, increment its access frequency by one in the node of the list. If the frequency of the current node is higher than of its previous node, the two nodes need to be swapped in the list. Continue doing so for all the previous nodes until no more previous node has lower access frequency. Eventually, the character with the highest frequency will appear at the beginning of the list, the next highest will be in the next node, etc. Your program also need to print out the characters in the list according to the order of the list.
Here is the program I have made so far. It's just a doubly linked list as of right now.
My main question is how should I go about the "Every time a character is accessed, increment its access frequency by one in the node of the list. If the frequency of the current node is higher than of its previous node, the two nodes need to be swapped in the list."?
I know there aren't any lines getting the info from a file. I'm going to add that later.
Any help is appreciated!
public class DoublyLinkedList {
private class Node {
String value;
Node next,prev;
public Node(String val, Node n, Node p) {
value = val;
next = n;
prev=p;
}
Node(String val) {
this(val, null, null);
}
}
private Node first;
private Node last;
public DoublyLinkedList() {
first = null;
last = null;
}
public boolean isEmpty(){
return first==null;
}
public int size(){
int count=0;
Node p=first;
while(p!=null){
count++;
p=p.next;
}
return count;
}
public void add(String e) {
if(isEmpty()){
last=new Node(e);
first=last;
}
else{
last.next=new Node(e, null, last);
last=last.next;
}
}
public void add(int index, String e){
if(index<0||index>size()){
String message=String.valueOf(index);
throw new IndexOutOfBoundsException(message);
}
if(index==0){
Node p=first;
first=new Node(e,p,null);
if(p!=null)
p.prev=first;
if(last==null)
last=first;
return;
}
Node pred=first;
for(int k=1; k<=index-1;k++){
pred=pred.next;
}
Node succ=pred.next;
Node middle=new Node(e,succ,pred);
pred.next=middle;
if(succ==null)
last=middle;
else
succ.prev=middle;
}
public String toString(){
StringBuilder strBuilder=new StringBuilder();
Node p=first;
while(p!=null){
strBuilder.append(p.value+"\n");
p=p.next;
}
return strBuilder.toString();
}
public String remove(int index){
if(index<0||index>=size()){
String message=String.valueOf(index);
throw new IndexOutOfBoundsException(message);
}
Node target=first;
for(int k=1; k<=index;k++){
target=target.next;
}
String element=target.value;
Node pred=target.prev;
Node succ=target.next;
if(pred==null)
first=succ;
else
pred.next=succ;
if(succ==null)
last=pred;
else
succ.prev=pred;
return element;
}
public boolean remove(String element){
if(isEmpty())
return false;
Node target=first;
while(target!=null&&!element.equals(target.value))
target=target.next;
if(target==null)
return false;
Node pred=target.prev;
Node succ=target.next;
if(pred==null)
first=succ;
else
pred.next=succ;
if(succ==null)
last=pred;
else
succ.prev=pred;
return true;
}
public static void main(String[] args){
DoublyLinkedList list1=new DoublyLinkedList();
String[] array={"a","c","e","f"};
for(int i=0; i<array.length; i++){
list1.add(array[i]);
}
list1.add(1,"b");
list1.add(3,"d");
System.out.println(list1);
}
}
Since this is a homework assigment, I'll only give hints:
Your Node class needs an extra field for a counter.
You need to iterate through the list to find the accessed character and increment its counter value.
You need a temporary Node object to swap nodes. Try it yourself first, then google it. It's an essential process every programmer must know.
I would recommend breaking down the procedure into the component parts. You know you need to keep and update a count, as Sebastian says above. You also know you need to be able to compare a node's count with the count of the node above it in the rankings. You know you need to be able to swap two nodes. You should have methods for those things. Think through what needs to happen in each broken-down method.
I always recommend a physical approach for these kinds of problems to get a feel for them: Try doing this with a set of note cards or post-it notes. On each one, write an object name and the fields for the Node object. Write field values in pencil. Jot down other fields (like the reference to the first element) on a sheet of paper. Then step through your algorithm and see what needs to change on each update. (note: Because this is a doubly-linked list, your changes should survive shuffling your stack of cards. Try that and see)
Good luck with the assignment!
Advice:
"I know there aren't any lines getting the info from a file.". You would be better off writing that code now, so that you can test what you have already written.
The other problem is that what you have written so far is a generic linked list, ignoring the requirement which say how the list is to be used. As a result, you have:
implemented a bunch of methods that appear to be unnecessary, and
not implemented the Node class correctly for the requirements.
Go back and look at the requirements, and work out what methods you actually need, and then implement them. (What you have done so far is a "bottom up" design that is largely ignoring what the top level needs. You would have been better of with a "top down" approach.)
The problem you are asked to solve is collating characters, not creating a "general purpose" linked list data structure.