i wanna swap 2 nodes in java here is my node class
public class Node {
int freq;
Node left,right,parent;
}
i wanna swap 2 Nodes in my tree
public void swap(Node a, Node b){
Node temp;
temp.freq=a.freq;
temp.parent=a.parent;
temp.left=a.left;
temp.right= a.right;
a.freq=b.freq;
a.left=b.left;
a.right=b.right;
a.parent=b.parent;
b.freq=temp.freq;
b.left=temp.left;
b.right=temp.right;
b.parent=temp.parent;
}
but i found that parent of both nodes becomes b.parent
any hint ????
Looking at your object, Node temp doesn't point to anything besides null. I don't know why your compiler isn't catching this error because using a dot call on a null object will throw a nullpointerexception(e.g. temp.freq; it will have nothing to point to and no internal variables at this point). Make sure that temp points to a new node and try going from there.
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).
I'm familiar with the 'this' keyword used in java, it is used to reference the current object. The following piece of code shows how a node of a LinkedList is created:
class Node {
Node next = null;
int data;
public Node(int d) {
data = d;
}
void appendToTail(int d) {
Node end = new Node(d);
Node n = this;
while (n.next != null) {
n = n.next;
}
n.next = end;
}
}
But here I'm not sure what the following line in the above code states:
Node n = this;
I'm pretty sure that 'this' here is referenced to the current object, but is this object head, tail or any other node in the LinkedList? Not sure if my question makes perfect sense, but any help is greatly appreciated.
I assume the appendToTail(int d) method appends the newly created node to the end of the list regardless of which Node its called from.
What happens is that one must find the end of the list in order to append the new Node to the end of it. Since we know that the node it is called from is in the list, it's an ideal starting point. Hence we choose the starting point as "this" node. But, this node is not necessarily the end of the list (in fact, it can be anywhere in the list), so we store it in a temporary variable Node n = this and continue changing our temporary variable until its the last node in the list, to which the new node can be added.
It's equivalent to starting from a random point (this) in a list and moving from that point to the end, wherever that is.
Hope this answered your question.
I'm pretty sure that 'this' here is referenced to the current object
Yup.
but is this object head, tail or any other node in the LinkedList?
That depends where the method was called from or if the list contains this Node at all.
All the method does is assign a temporary reference to the current Node so it can be iterated over. You can't say which Node it is without more information.
From comments - If you call appendToTail() on the head, this will be the head. If you call it on the tail, this will be the tail. If you call it on a middle node, this will be that middle node.
I' studying linked lists. I'm practicing problems from this book : Cracking the coding interview. I'm stuck, I can't understand how the author is trying to implement the following code, its supposed to delete a node....
class Node {
Node next = null;
int data;
public Node (int d) {
data = d;
}
Node deleteNode(Node head, int d) {
Node n = head;
if (n.data == d) {
return head.next;
}
while (n.next != null) {
if (n.next.data == d) {
n.next = n.next.next;
return head;
}
n = n.next;
}
return head;
}
I've 3 questions...
Question 1 -
What are we going to pass as the argument for the function deleteNode? What purpose does Node head serve? and what purpose does int d serve? Is the node head the node we want to delete? Or is it our head node? I mean, we are supposed to use the method as following right?
"Name of node".deleteNode("Node name", "integer value");
"Name of node" being the node we want to delete...Isn't that right?
Question 2 - Its clear in the code that the function deleteNode uses only data to confirm the identity of the node we want to delete. E.g. if(n.data ==d). Is that normal practice? I mean what if I have 2 different nodes containing the same integer as the data value? Shouldn't we use the name of the node to specify which node we want to delete?
Question 3 - function deleteNode returns a node. Why is that? In order to delete a node, we only gotta do 3 things...First, unlink the pointer of the node we want to delete. Second, put the pointer of the previous node, to the node where the pointer of the node we wanted to delete was originally pointing. Third, delete the node now that its not linked to the list. I don't see what purpose does return type node serves here...
Question 1 : All along your post, you keep talking about the "name" of the nodes, but the nodes have no name. They have an int value and a successor, that's all. In this deleteNode method, the first argument is the head of the linked list from which you want to remove the first occurrence of the value d.
Question 2 : As I said, the nodes have no name and are identified by their value. As soon as an occurrence of the wanted value is found, the corresponding node is deleted no matter how many occurrences of the same value are in the linked list.
Question 3 : the method returns the head of the list, so that you can chain multiple calls like this
myList.deleteNode(head,3).deleteNode(head,5).addNode(head,10)
If the method had a void return type, you should do
myList.deleteNode(head,3);
myList.deleteNode(head,5);
myList.addNode(head,10);
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.
I was just playing around with a binary tree and I was curious as to why the first implementation worked but the second didn't. What am I overlooking? I think it's trivial but I'm still missing it.
1:
//just a wrapper around the insertTree method.
public void insertKey(int key){
if(root==null) //a private 'Node' variable.
root = new Node(key);
else
insertTree(key, root);
}
//recursive insert - working
private void insertTree(int key, Node node)
{
if(key <= node.getKey())
{
if(node.left!=null)
insertTree(key, node.left);
else
node.left = new Node(key); //explicitly setting left child
}
else
{
if(node.right!=null)
insertTree(key, node.right);
else
node.right = new Node(key); //explicitly setting right child
}
}
The variant that is not working:
2:
private void insertTree(int key, Node node)
{ //if node is null, create a new node. Can be either node.left or node.right
if(node==null)
{
node = new Node(key);
return;
}
else
if(key <= node.getKey())
insertTree(key, node.left);
else
insertTree(key, node.right);
}
Node is just a simple class with public left, right members and a single int key data member. Nothing fancy. So #1 works just fine and the inorder traversal produces a sorted output. Now, #2 doesn't seem to work. The root is the only one that is initialized and its left/right children continue to be null. So if I do pass node.left as a parameter, why doesn't the recursive method call assign a new node to it? What am I missing here? Java is pass by reference (i.e. value of reference) so I'm guessing this should work, but maybe I'm missing something noob-ish over here.
The reason it doesn't work is because the node variable in the last recursive call to insertTree does not actually refer to the same memory location as node.left in the call that preceded it. Calling a function(/method) effectively creates new storage locations for all its parameters on the stack, and copies the parameter values there.
Therefore, insertTree in your second variant simply creates a new Node and assigns it to the local variable node in that function. That assignment affects no other memory location. Then it returns, and the new Node is lost forever.
You state that "Java is pass by reference", but that's not true. Java passes references by-value.
You should not be using recursion to add elements to a binary tree. Recursions involve implicit stacks which are expensive. You should simply iterate to find the correct location for adding the node. Plus, when you use iterating, you don't need two methods to do the work -- one is enough. Look at the following very simple code: http://www.geekviewpoint.com/java/bst/add