YES, this is a homework project.
That being said, I'm looking to learn from my mistakes rather than just have someone do it for me.
My project is a word frequency list - I accept a text file (or website URL) and count the:
- Number of unique words, and
- How many times they appear.
All methods are provided for me except for one: the insert(E word) method, where the argument is a generic type word.
The word is stored in a Node (Linked List project) that also has a 'count' value, which is the value representing the number of times the word appears in the text being read.
What this method has to do is the following:
If the argument is already in the list, increment the count of that element. I have done this part
If the argument is not found in the list, append it to the list. I also have done this part.
sort the list by descending count value. i.e. highest -> lowest count
3.5. If two elements have the same count value, they are sorted by the dictionary order of their word.
I am VERY unfamiliar with Linked Lists, so as such I am running into a lot of NullPointerExceptions. This is my current insert method:
public void insert(E word){
if(word.equals("")){
return;
}
if(first == null){//if list is null (no elements)
/*Node item = new Node(word);
first = item;*/
first = new Node(word);
}
else{//first != null
Node itemToAdd = new Node(word);
boolean inList = false;
for(Node x = first; x != null; x=x.next){
if (x.key.equals(word)){// if word is found in list
x.count++;//incr
inList = true;//found in list
break;//get out of for
}//end IF
if(x.next == null && inList == false){//if end of list && not found
x.next = itemToAdd;//add to end of list
break;
}//end IF
}//end FOR
//EVERYTHING ABOVE THIS LINE WORKS.
if (!isSorted()){
countSort();
}
}//end ELSE
}//end method
My isSorted() method:
public boolean isSorted(){
for(Node copy = first; copy.next != null; copy = copy.next){
if (copy.count < copy.next.count){
return false;
}
}
return true;
}
and last but not least, the part where I'm struggling, the sort method:
public void countSort(){
for (Node x = first, p = x.next; p != null; x=x.next, p=p.next){
// x will start at the first Node, P will always be 1 node ahead of X.
if(x == first && (x.count < p.count)){
Node oldfirst = first;
x.next = p.next;
first = p;
first.next = oldfirst;
break;
}
if (x.count < p.count){
//copy.next == x.
Node oldfirst = first;
oldfirst.next = first.next;
x.next = p.next;
first = p;
first.next = oldfirst;
break;
}
if (x.count == p.count){
if(x.toString().charAt(0) < p.toString().charAt(0)){
//[x]->[p]->[q]
Node oldfirst = first;
x.next = p.next;
first = p;
first.next = oldfirst;
break;
}
}
}
}
Here is the output of my insert method when called by the classes/methods given to me:
Elapsed time:0.084
(the,60)
(of,49)
(a,39)
(is,46)
(to,36)
(and,31)
(can,9)
(in,19)
(more,7)
(thing,7)
(violent,3)
(things,3)
(from,9)
(collected,1)
(quotes,1)
(albert,1)
(einstein,2)
(any,2)
(intelligent,1)
(fool,1)
(make,1)
(bigger,1)
(complex,1)
(it,11)
(takes,1)
(touch,1)
(genius,1)
(lot,1)
(courage,1)
(move,1)
(opposite,1)
(direction,1)
(imagination,1)
(important,5)
(than,3)
(knowledge,3)
(gravitation,1)
(not,17)
(responsible,1)
(for,14)
(people,2)
(falling,1)
(love,2)
(i,13)
(want,1)
(know,3)
(god,4)
(s,8)
(thoughts,2)
(rest,2)
(are,11)
(details,2)
(hardest,1)
(world,7)
(understand,3)
(income,1)
(tax,1)
(reality,3)
(merely,1)
(an,7)
(illusion,2)
(albeit,1)
(very,3)
(persistent,2)
(one,12)
(only,7)
(real,1)
(valuable,1)
(intuition,1)
(person,1)
(starts,1)
(live,2)
(when,3)
(he,11)
(outside,1)
(himself,4)
(am,1)
(convinced,1)
(that,14)
(does,5)
(play,2)
(dice,1)
(subtle,1)
(but,8)
(malicious,1)
(weakness,2)
(attitude,1)
(becomes,1)
(character,1)
(never,3)
(think,1)
(future,2)
(comes,1)
(soon,1)
(enough,1)
(eternal,1)
(mystery,1)
(its,4)
(comprehensibility,1)
(sometimes,1)
My initial idea has been to try and loop the if(!isSorted()){ countSort();} part to just repeatedly run until it's sorted, but I seem to run into an infinite loop when doing that. I've tried following my professor's lecture notes, but unfortunately he posted the previous lecture's notes twice so I'm at a loss.
I'm not sure if it's worth mentioning, but they provided me an iterator with methods hasNext() and next() - how can I use this as well? I can't imagine they'd provide it if it were useless.
Where am I going wrong?
You are close. First the function to compare the items is not complete, so isSorted() could yield wrong results (if the count is the same but the words are in wrong order). This is also used to sort, so it's best to extract a method for the comparison:
// returns a value < 0 if a < b, a value > 0 if a > b and 0 if a == b
public int compare(Node a, Node b) {
if (a.count == b.count)
return a.word.compareTo(b.word);
// case-insensitive: a.word.toLoweCase().compareTo(b.word.toLowerCase())
} else {
return a.count - b.count;
}
}
Or simplified which is enough in your case:
public boolean correctOrder(Node a, Node b) {
if (a.count > b.count)
return true;
else if (a.count < b.count)
return false;
else
return a.word.compareTo(b.word) <= 0;
}
For the sort you seem to have chosen bubble sort, but you are missing the outer part:
boolean change;
do {
change = false;
Node oldX = null;
// your for:
for (Node x = first; x.next != null; x = x.next) {
if (!correctOrder(x, x.next)) {
// swap x and x.next, if oldX == null then x == first
change = true;
}
oldX = x;
}
} while (change);
We could use the help of Java native library implementation or more efficient sort algorithms, but judging from the exercise the performance of the sort algorithm is of no concern yet, first need to grasp basic concepts.
With looking your codes, it sounds like to me that two things can be done:
Firstly, you can make use of Comparable class method. So, I assume you wrote the class Node, thus you may want to inherit from Comparable class. When you inherited from that class, java will automatically provide you the compareTo method, and all you need to do is to specify in that method that "I want to compare according to your counts and I want it to be in ascending order."
**Edit(1):By the way, I forgot the mention before but after you impelement your compareTo method, you can use Collections.sort(LinkedList list), and it will be done.
The second solution came to mind is that you can sort your list during the countSort() operation with the technique of adding all to an another list with sorting and after add all them back to the real list. The sorting technique I'm trying to say is, keep going towards to the end of the list until you find a Node in the list that has a count smaller than currently adding Node's counts. Hope that doesn't confuse your head, but by this way you can achieve more clear method and less complicated view. To be clear I want to repeat the procedure:
Look the next
If (next is null), add it //You are at the end.
else{
if (count is smaller than current count), add it there
else, keep moving to the next Node. //while can be used for that.
}
Related
The answer needs to be iterative, not recursive and the trees don't have to have the same structure, only the same numbers. I think I need to use a vertex traversal, but I am not sure how to implement that without using recursion.
This is what I had, but it doesn't pass the given tests. Also, I can't use any helper functions.
Node leftTree = t1;
Node rightTree = t2;
if(t1 == null && t2 == null)
return true;
else if (t1 != null && t2 == null)
return false;
else if (t1 == null && t2 != null)
return false;
else
{
if(leftTree.key == rightTree.key && problem1(leftTree.left, rightTree.left) == true
&& problem1(leftTree.right, rightTree.right) == true)
return true;
}
return false;
The recursion, where you compare left with left and right with right, will not work, because you can have the same keys but in a different topology. You need to visit the nodes in-order in the two trees in parallel.
One way of going through a tree without using recursion or extra memory is via a Morris traversal, where you temporarily put a tree in the rightmost position of its left subtree, and "return" from the recursion by following the right pointer there.
Here is an implementation in C, because I have one lying around. In Java it won't be that different. The rightmost_to() function returns the rightmost node in the left child of the current node, or the current node itself. You use it put the current node in the right child there, so when you get down to that point, going right emulates returning from the recursion.
void morris(stree *t)
{
struct node *curr = *t;
while (curr) {
if (!curr->left) {
printf("%d\n", curr->value);
curr = curr->right;
} else {
stree pred = *rightmost_to(&curr->left, curr);
assert(pred->right == 0 || pred->right == curr);
if (pred->right == 0) {
pred->right = curr;
curr = curr->left;
} else {
printf("%d\n", curr->value);
pred->right = 0;
curr = curr->right;
}
}
}
}
You will visit each node in order, without recursion, and without using extra memory. Whenever you recurse, you put the node you are in at the rightmost position, so you automatically come back to it. You can recognise that you are seeing the node for the second time because you find it when searching for the rightmost. Then you restore the tree instead of going left once more.
If you need to compare two trees, have two current nodes, and you should be fine. It does use an extra function, rightmost_to(), but it is a simple loop that you can easily embed without any issues. It is a line or two if you do that.
If you are allowed to put a parent pointer in the nodes, I think you can also traverse the trees without using extra memory doing something like this:
#define left_child(t) \
((t)->parent && (t)->parent->left == (t))
void parent_traverse(stree t)
{
enum { DOWN, UP } state = DOWN;
while (t) {
switch (state) {
case DOWN:
// Recurse as far left as we can...
while (t->left) { t = t->left; }
// Emit the leaf we find there
printf("(,%d,", t->value); // VISIT
// Then go right, if we can, or up if we can't.
if (t->right) { t = t->right; }
else { state = UP; }
break;
case UP:
if (!t->parent) return; // we have returned to the root...
if (left_child(t)) {
// Returning from a left child, we emit the parent
t = t->parent;
printf(",%d,", t->value); // VISIT
// Then we go right if we can't, or continue up
// (t is already the parent) if we cannot.
if (t->right) { t = t->right; state = DOWN; }
} else {
// Returning from a right child just means going up
t = t->parent;
}
break;
}
}
}
Sorry, it is C again, but just look at how t is updated to its left, right or parent node as we run through the tree. I cut that out of some code I have, and I might have copied it wrong, but you should get the idea. You can keep track of which direction you are moving, and essentially move along the "edge" of the tree, down left edges, under them and up, then down to the right, turn, and move up, and so on. If you have the state for both trees, you should be able to do that traversal in parallel in the two. Everwhere the code "visits" a node, you will compare the two nodes.
I don't know how useful this is, but it is at least a couple of ways that you can compare two trees with only constant extra memory usage and no recursion.
Of course, if it is a simple assignment and the time complexity doesn't matter, run through one tree and look up in the other in O(n log n) (balanced) or O(n^2). :)
I'm trying to find a value in a binary tree and returning the node that has the value I'm looking for.
I did an algorithm that works well when the value is not in a very deep level of the tree, but when the value is in a deep position I get a java.lang.StackOverflowError. Here is my code:
class Nope {
Nope left, right;
int value;
public Nope find(int v){
if(v > this.value && this.right != null)
return right.find(v);
if(v < this.value && this.left != null)
return left.find(v);
if(this.value == v)
return this;
return null;
}
}
Can any one suggest me a solution about this issue (I heard about something like tail optimization recursion) but I'm not sure of it working in Java.
The simplest approach is to convert this into a while loop, which just maintains state of "the current node we're testing".
On each iteration of the loop, there are three possibilities:
The current node has the right value, in which case you can return it
The current node has a subnode on the correct "side", in which case you can continue iterating with that subnode as the new "current node"
Neither of the above is the case, in which case the value isn't found and you can return null
So something like:
public Nope find(int v) {
Nope current = this;
while (current != null) {
if (current.value == v) {
return current;
}
// This will drop out of the loop naturally if there's no appropriate subnode
current = v < current.value ? current.left : current.right;
}
return null;
}
Or with even less code, but perhaps less readably:
public Nope find(int v) {
Nope current = this;
// Keep navigating down the tree until either we've run
// out of nodes to look at, or we've found the right value.
while (current != null && current.value != v) {
current = v < current.value ? current.left : current.right;
}
return current;
}
An example of your code recast as iteration:
class Nope {
// keep these fields
Nope left, right;
int value;
public Nope find(int v){
Nope n = this;
while (n != null)
{
if (v > n.value)
n = n.right;
else if (v < n.value)
n = n.left;
else // v == n.value
return n;
}
return null;
}
}
Edit: just a note on how this works, in case it's unclear. Since you never need to remember anything about how you got to the current node, we only keep track of the root of the current subtree we need to search. At each step, we've either determined there is no subtree left to search (first condition), there might be a subtree to the left or right (middle two conditions), or that we have actually found the value at the root of the current subtree (last condition). We keep looking until we run out of subtrees (while condition) and, if we do run out, we know the value isn't in the tree and we return null.
Edit: As pointed out in the comments, the use of consecutive ifs is a problem. I have updated the code to use if/else if/else.
Tree searches are used to avoid iterating over large arrays.
The weakness of the tree approach is when the node values are ordered. As the tree is loaded, every node goes to the left or right, causing a lot of recursion. Having said that, stack overflow takes a lot of recursion.
You can either hash the values, which will tend to balance the tree, or you can enhance your tree building algorithm to balance the tree if a particular branch gets too long.
Having said that, you should also look at how many nodes are in your tree that there are enough to cause a stack overflow. You may have a bug in your code that is not shown here.
You can use Xss JVM argument to increase the memory allocated to the thread stack. This will allow you to have a larger method call stack.
-Xsssize
Sets the thread stack size (in bytes). Append the letter k or K to indicate KB, m or M to indicate MB, g or G to indicate GB. The
default value depends on virtual memory.
The following examples set the thread stack size to 1024 KB in
different units:
-Xss1m
-Xss1024k
-Xss1048576
Ref: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
Otherwise you can always convert the recursion to the a loop, that would mean you would have to manage the call stack of the method (arguments and return values) yourself in a stack, that can become messy.
Note: For search operation there's no need for a stack as mentioned by Jon Skeet. Search doesn't need to keep track of where it's been. However for backtracking a reference to parent would be required, and we will have to make sure that we always start with left child.
I keep seeing null pointer exceptions in my search method for the skip list I'm implementing.
public V find(K key, SkiplistMapNode<K,V> header, int level){
SkiplistMapNode<K,V> N = header;
for (int i = level-1; i >= 0; i--){
if ((N != null) && (N.getNext()[i] != null)){
while (N.getNext()[i].getKey().compareTo(key) < 0){
N = N.getNext()[i];
}
}
}
N = N.getNext()[0];
if ((N != null) && (N.getKey().compareTo(key) == 0)) return N.getValue();
else return null;
}
The line with the exception is:
while (N.getNext()[i].getKey().compareTo(key) < 0)
I pretty much copied this from this page though, so I'm not sure what would be wrong with it.
Supposing that N.getNext() advances to the next node, you need to memorize its value without advancing if you access the value more than once.
Same with iterator:
while (iterator.hasNext()) {
if (iterator.next()!=null) {
iterator.next().toString() // advances to the next item, which may be null
}
}
Fixed:
while (iterator.hasNext()) {
Object next=iterator.next(); // advance once
if (next!=null) { // check value
next.toString() // use same value, without advancing
}
}
It's hard to tell from your code where you really want to advance to the next element, and where you need the elements values again. Store the next value in a variable, and check and use this value afterwards, same as in the Iterator example above.
If you access an objects method, you should really make sure that the object isn't null. In your case, in...
while (N.getNext()[i].getKey().compareTo(key) < 0)
These...
N.getNext() //the only really important one you seem not to be checking
N.getNext()[i]
could be null and should be checked and possibly even (though less likely and debatably)
N
N.getNext()[i].getKey()
key
I'm looking into depth first search and the examples I found are looking for a particular answer, lets say the number 10.
It goes through the tree discarding every node that isn't 10 and stop when it finds 10.
Is it possible to use depth first search or another algorithm to search every branch of the tree? I would like it to run a scenario and come up with a value and store that into a variable possibly named highestValue.
It would then search the next branch and get a value and store that into a variable possibly named Value. Then it would compare highestValue to Value and if (Value > highestValue) highestValue = Value.
It would repeat the process until it is finished running every possible scenario. Any ideas? I should mention I'm writing this in Java.
DFS is easiest if we want to visit every node in the graph. However, if we have a very large tree and want to be prepared to quit when we get too far from the original node, DFS can search thousands of ancestors of the node but never search all of the nodes children.
Strictly speaking, it depends on how the data in your graph is organize. Source
Since you're still wondering how it might work, this piece of code might help you figure that out. This works for graphs, take a look. It DFSes every node, but stops when it reaches the node we want to find.
To get the highest value, just store the max value into an int variable, and continue searching and comparing each node's data to the current max inside the int variable.
public static boolean search(Graph g, Node start, Node end) {
LinkedList<Node> stack = new LinkedList<Node>();
for (Node u : g.getNodes()) {
u.state = State.Unvisited;
}
start.state = State.Visiting;
stack.add(start);
Node u;
while (!stack.isEmpty()) {
u = stack.removeFirst();
if (u != null) {
for ( Node v : u.getAdjacent() ) {
if (v.state == State.Unvisited) {
if (v == end) {
return true;
}
else {
v.state = State.Visiting;
stack.add(v);
}
}
}
u.state = State.Visited;
}
}
return false;
}
I have the following code for detecting a cycle in a linked list:
public Class Node {
Object data;
Node next = null;
}
boolean containCycle() {
boolean retVal = true;
Node head = this;
Node slower = head;
Node faster = head;
if(faster != null && faster.next != null) {
faster = faster.next;
} else { // there is only one element or zero element
retVal = false;
}
if (faster.next != null) {
faster = faster.next;
} else { // there are only 2 elements
retVal = false;
}
while (slower != faster && slower != null && faster != null) {
faster = (faster.next != null && faster.next.next != null) ? faster.next.next : null;
slower = (slower.next != null) ? slower.next : null;
}
if (slower == faster) {
retVal = true;
System.out.printf("The two pointers meet at: %d\n", faster.data);
} else {
retVal = false;
}
if (retVal) { // this is the part for detecting where the loop begins
slower = head;
while(slower.next != faster.next) {
slower = slower.next;
faster = faster.next;
}
System.out.println("The cycle starts at: " + slower.data);
}
return retVal;
}
This code runs fine up until the part where I actually start detecting where the loop begins, which I commented in the code. Somehow, this runs into an infinite loop.
I suspect that this is somehow related to pass by reference in Java? Am I updating the value that head refers to while I was detecting the loop? I am really out of ideas here. Please help!
I dont know the exact algorithm, but you could use the following way to find the meeting point.
Let us call the Node at which slower and faster meet as meeting point.
Have two pointers one starting from head, another starting from meeting point .
And keep count of how many nodes you need to traverse from head to meeting point(let us call this count as a) and
meeting point's next node to meeting point. (Lets call this count b)
Now the difference |a-b| in these two counts represents the common part -right? (ie part between the start of the loop and the meeting point of slower and faster).
So now again start afresh.Reset the two pointers, one to head and other to meeting point + 1.
for example if a>b, move pointer from head |a-b| times else move pointer from meeting piont + 1 |a-b| times.
Now move two pointers together till they meet.
ANOTHER Way of explaining this
Since what you are looking for is similar to the case where you have two linked lists and they merge at some node and you need to identify that node.
All you have is the starting points of the two linked lists.
So you start from head1 and count till end of list.
Next you start from head2 and count till end of list.
The calculate the diff in the lengths. Increment the longer path diff times. And then start moving pointers starting from shorter paths head and the diff till the two pointers meet.
This is essentially the same thing what you are doing in the other case.