I am already aware of various answers to this question. But I have a very confusing bug in my code. The following is a series of println() calls to see if the list I created is correctly sorted.
ListNode list_b = new ListNode(3, new ListNode(-2));
System.out.println("Checking the string conversion: " +
sut.convertToString(list_b)); //output is 3,-2, as expected. Expected result of sorting is -2,3.
System.out.println("Now checking the
string conversion of the sorted list: " +
sut.convertToString(sut.sort(list_b, int_comparator))); //output is -2,3 as expected.
System.out.println("Now this is list_b following the sorting,
by calling the element and next directly: "
+ list_b.element + "," + list_b.next); //3,null. How the hell did that happen!?!??!!?
The convertToString method is as follows:
public String convertToString(ListNode head) {
if (head != null) {
String representation = "";
if (!head.element.equals(null))
representation += head.element.toString();
ListNode next = null;
if (head.next != null)
next = head.next;
if (next != null && !next.element.equals(null))
representation += "," + next.element.toString();
while (next != null) {
if (next.next != null) {
next = next.next;
if (!next.element.equals(null))
representation += "," + next.element.toString();
}
else
break;
}
return representation;
}
else
return "";
}
And the actual sort method is still a work in progress, albeit fairly simple:
public ListNode sort(ListNode head, Comparator comparator) {
if (head != null) {
ListNode next = null;
if (head.next != null)
next = head.next;
else
return head;
if (comparator.compare(head.element, next.element) > 0) {
head.next = next.next;
next.next = head;
head = next;
}
return head;
}
return null;
}
Would anyone care to explain how I've managed to do the seemingly impossible? I'm speechless at how this could happen! Many thanks to anyone who can explain!
EDIT: thank you to those for your answers and suggestions. I should clarify that the following tests are then performed on the list:
assertTrue(sut.deepEquals(list_a, sut.sort(list_a, int_comparator)));
assertFalse(sut.deepEquals(list_b, sut.sort(list_b, int_comparator)));
assertTrue(sut.deepEquals(new ListNode(-2, new ListNode(3)), sut.sort(list_b, int_comparator)));
assertTrue(sut.deepEquals(new ListNode(-14, new ListNode(-2, new ListNode(3))), sut.sort(list_c, int_comparator)));
Clearly, this implies that any updating of list_b (i.e. list_b = sut.sort(list_b)) is unnecessary. What I'm asking is how you would change the sort method itself so that updating is unnecessary.
Pretty simple: you sort the list in this piece of code:
sut.convertToString(sut.sort(list_b, int_comparator)))
The list is transformed this way:
3 -> -2 -> null ====> -2 -> 3 -> null
^ ^
| |
list_b list_b
sut.sort returns the new front (head) of the list, which should be the new list_b, but since you don't update the value, it points to the second node in the list, thus producing "3 , null"
Well ... you are changing the internals of the passed node inside your sort method. The variable list_b is still referring to the node "3" that after sorting does not have a successor anymore.
Your sort method is returning the new head of the sorted list. But you do not use that afterwards!
Change your code snippet to:
list_b = sut.sort(list_b, int_comparator);
System.out.println(sut.convertToString(list_b));
list_b references the node containing 3, and having the node 2 as next element.
Then you sort the list. That changes the node containing 3: its next node is now null, since it becomes the last element of the list. It also changes the node 2, which now has the node 3 as next element. But list_b continues to be a reference to the node containing 3.
When you print the node list_b, you thus get 3, null as a result.
EDIT:
to answer your last question:
how you would change the sort method itself so that updating is unnecessary
You should have an actual LinkedList class (exactly as the standard java.util.LinkedList class). The class you have doesn't represent a list. It represents a node inside a chain of nodes.
The LinkedList class would have a reference to the head node, and would contain all the methods needed to iterate through the values stored in the list, transform it to a String, sort it, etc. Of course, sorting the list would imply changing the reference to the head node inside the LinkedList object. But that would be transparent to the user of the LinkedList class, which would never manipulated nodes directly.
Of course, if you start caring so much about having a proper LinkedList class, you should simply use the standard one, which is standard, documented, and tested.
Related
I am currently doing a Cracking the Coding Interview Problem (2.4) and I am supposed to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. However, I am really confused as to why a temporary variable "next" is needed and why is node.next nulled below it. Why can't I just do node = node.next at the end of the while loop?
I am simply creating two linked lists, before and after, and merging them together once the correct values are put into each list.
public static Node partition(Node node, int x) {
Node beforeStart = null;
Node beforeEnd = null;
Node afterStart = null;
Node afterEnd = null;
/* Partition list */
while (node != null) {
Node next = node.next;
node.next = null;
if (node.data < x) {
if (beforeStart == null) {
beforeStart = node;
beforeEnd = beforeStart;
} else {
beforeEnd.next = node;
beforeEnd = beforeEnd.next;
}
} else {
if (afterStart == null) {
afterStart = node;
afterEnd = afterStart;
} else {
afterEnd.next = node;
afterEnd = afterEnd.next;
}
}
node = next;
}
/* Merge before list and after list */
if (beforeStart == null) {
return afterStart;
}
beforeEnd.next = afterStart;
return beforeStart;
}
Why can't I just do node = node.next at the end of the while loop?
It can be done this way. After doing the partition, for each list, you need to set the last node's next pointer to NULL. This will just take two lines of code.
The example code is using next = node.next and node.next = NULL to terminate each list during the partition process, but in this case that's not needed, since the lists don't need NULL terminators until after the partition process is done.
The loop in your question removes nodes from the head of the original list, and appends them to the before list or the after list, until the original list is empty. Then it concatenates the before and after lists.
That's easy to explain and easy to understand.
It can be done without the temporary next or nulling out node.next in every iteration, but then the above description would no longer apply -- nodes would not be removed from the original list in every iteration, the before list and after list would not contain only the appropriate nodes, the operation you perform on them is not 'appending', and nodes would even appear in multiple lists for a while.
Your algorithm would suddenly be a lot more difficult to describe and understand. That is a bad thing in software development, and a bad thing in a coding interview.
The problem is to reverse a singly linked list, but I'm a bit stuck with the following code:
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null) return head;
ListNode temp = head.next;
head.next = null;
ListNode result = reverseList(temp);
temp.next = head;
return result;
}
What does line 6 do?
temp.next = head;
Without it, the result will only return the last element and not a reversed list.
The way I read it is that the code gets to line 5, gets result, goes through line 6, then returns the result at line 7, and keeps repeating until finish. How does line 6 actually affect the code?
I'm having a hard time visualizing this recursion. Can someone help?
A recursive function solves a problem by making use of smaller versions of the exact same problem. There are two main parts to a recursive function: the base case and the recursive case. The base case is the smallest version of the problem where we provide a solution without having to use recursion. It's where the recursion stops. The recursive case makes the assumption that the smaller versions of the problem provide correct solutions and we use those solutions to solve the larger versions.
reverseList() takes the head node of a linked list as input, reverses each node in the list, and returns the head node of the new reversed list.
Let's say you have a linked list:
a->b->c->d->e
head points to node a and temp points to node b.
On line 4, node a is disconnected from the original list resulting in two sublists, one containing only a and the other containing the other elements starting with b. Now, assuming that line 5 correctly reverses the sublist starting with b, we have:
a
e->d->c->b
head still points to a, temp still points to b, and result points to e (the head of the reversed sublist).
In order to correctly reverse our original list, we just add node a (head) to the end of the reversed sublist (temp).
Now the list is:
e->d->c->b->a
where the new head points to e.
Line 6 only make link between the nodes. recursion goes all the way to last node and make link reverse.
EDIT : Posted full code.
I wrote an alternative that you may understand better. I also set the function as static ( getters and setters not used for more straightforward explanation).
public class ListNode {
// should be private variables
int value;
ListNode next;
ListNode(int val, ListNode nodeList){
this.value = val;
this.next = nodeList;
}
public static ListNode reverseList(ListNode head) {
if( head.next.next != null)
reverseList (head.next);
head.next.next = head;
head.next = null;
return head;
}
#Override
public String toString(){
String ret = "";
if ( next != null ){
ret = next.toString();
}
ret += String.valueOf(value);
return ret;
}
}
public class Main {
public static void main(String[] args) {
ListNode n0 = new ListNode(4, null),
n1 = new ListNode(3, n0),
n2 = new ListNode(2, n1),
n3 = new ListNode(1, n2),
n4 = new ListNode(0, n3);
System.out.println(n4);
ListNode.reverseList(n4);
System.out.println(n0); // <-- n4 now is the last item, check n0 instead !
}
}
Output
43210
01234
It may be easier for you to understand it here. Drawing it the before and after always helps. Like this, but only changing the arrows insted of the position of the boxes.
I am still a little confused on how to implement a doubly linked list. After researching and finding some information about them, I've got a good visual of how some of the basic functions work, such as add, remove etc. However, If I wanted to write a method for a DLList called countEquals (E check) that walks the entire list and counts the number of items in the list that are equal to the "Check" data item passed to the method, how would I write this. The instructions say I cannot use a for-each loop or an iterator, but a loop of some sort must be used. After the list is fully traversed, return the number of items that are equal to "check". Here is some code that I have tried to write for this:
internal references of DLList: Fields (next, data, prev) Members (size), head and tail.
public int countEquals(E Check){
currentNode = head;
int count = 0;
while (currentNode != null) {
if (currentNode.data == check) {
count ++;
else {
currentNode.next = currentNode;
}
return count;
}
I'm not too sure if this will correctly walk a doubly linked list, if I have to write more pointer assignments? I was thinking that because I'm not adding any nodes, but just walking a list, I wouldnt need to do the pointers.
Almost there, good effort. However, just a couple of things. First, you may want to look into using something.equals() rather than == since the latter is for object identity rather than value equality.
Second. the logic for traversing the list is slightly off. It needs to be done regardless of whether an item was found, and the sides of the assignment should be reversed.
Have a look at the following pseudo-code for guidance:
def countEquals(check):
currentNode = head
count = 0
while currentNode != null:
if currentNode.data == check:
count = count + 1
currentNode = currentNode.next
return count;
do it this way, if data is integer
while (currentNode != null) {
if (currentNode.data == check) {
count ++;
currentNode.next = currentNode;
}
else {
currentNode.next = currentNode;
}
}
return count;
If the title is not confusing enough maybe this will be. I have a linked list which contains people who have first and last names as well as a few other variables. The list must be sorted by last name first, then by first name. So far I insert the people into the list in alphabetical order by last name. I then try to traverse the list, if two last names are the same, I check the first names and swap. But I have a bug.
Inserted alphabetically into the list by last name, last,first
Acy,Mary
Acy,Clayton
Bob,Lonnie
Toni,Lonnie
After my so call "sort" of first names
Acy,Mary
Bob,Lonnie
Acy,Clayton
Toni,Lonnie
You can see it is sorted by last name. I am trying to sort each same last name by first name. And this is what I get as output from
public void sortFirstNames(){
System.out.println("here");
PeopleNode previous = null;
PeopleNode current = head;
PeopleNode temp;
if(head == null || head.next == null){
return;
}
while(current != null && current.next != null && current.lastName.compareTo(current.next.lastName) == 0){ //traverse the list
if((current.firstName).compareTo(current.next.firstName) > 0){ //see which first name goes first
temp = current.next.next;
current.next.next = temp.next;
temp.next = current.next;
current.next = temp;
current = temp.next;
}
current = current.next;
}
}
It doesn't change the list at all, I have taken advise of commenters but have yet to make it work. Does anyone have any idea?
Basically I am trying to say while two last names are the same check the first names, then swap them if need be.
The heart of your problem lies here:
if(previous.firstName.compareTo(current.firstName) >= 0){
temp = current;
current = previous;
previous = temp;
}
Firstly - >=. That's probably not so much a problem as just unnecessary - there's no need to swap elements that are equal - just make it > instead.
Next, that code doesn't change the linked-list at all. All it does is change the values of the local variables, so previous ends up pointing to the node after current in the actual linked-list, and then, because of the >=, if you have equal values, you'll just continuously process the same two nodes.
This post elaborates a bit on that: Is Java "pass-by-reference" or "pass-by-value"?
What you need to do is compare something.next and something.next.next (no need for 2 separate variables), and then you can swap these, which will change the linked-list.
I am tring to insert string into doubly linked list in reverse order. But I am not sure how can I maintain the insertion order in reverse order.
This is my below code.
theList.insertReverseLexicographicalOrder("B");
theList.insertReverseLexicographicalOrder("A");
theList.insertReverseLexicographicalOrder("H");
theList.insertReverseLexicographicalOrder("D");
theList.insertReverseLexicographicalOrder("E");
public void insertReverseLexicographicalOrder(String dd) {
Link newLink = new Link(dd);
if (isEmpty()){
last = newLink;
}
first.previous = newLink;
}
newLink.next = first;
first = newLink;
}
Any suggestions will be appreciated with some code based on my solution..
Well you assume that its already in reverse order, so you're going to need some sort of loop through until you find where it should go.. i.e.
Z, Y, X, W, L, K, A
if you're inserting M, then you should loop until you find L, which is lexicographically larger than M, and therefore insert it there. Because the nodes have previous pointers, insertion shouldn't be too hard to figure out on your own
You would need to look through the list comparing each of the elements. Stop when you find the element that goes after the element you are trying to insert. I suggest you implement the compareTo method in your node class: http://www.javapractices.com/topic/TopicAction.do?Id=10
and use it to make the comparisons
Good Luck.
How to insert a node into a linked list:
If the list is empty, the new node will become the first, and if we keep track of that, also the last
Otherwise find the position where to insert, there are three possibilities,
a) the new node has to be inserted before the first
b) the new node has to be inserted after the last
c) the new node has to be inserted between two existing nodes
Update the appropriate references, that may be first, last and some next and previous fields, depending on where it has to be inserted
if (first == null) {
// the list is empty so far
} else
To find the position, first compare the data with the first node's data to see whether it has to be inserted before the first node.
if (newLink.iData.compareTo(first.iData) > 0) {
// put newLink before first
} else {
You have to keep a focus on some list node. Follow the list from the start until you reach the point of insertion:
Link focus = first; // focus first node
while(focus.next != null && newLink.iData.compareTo(focus.next.iData) < 0) {
focus = focus.next;
}
// now you have to insert the new value behind focus, left as exercise
if (focus.next == null) {
// newLink becomes the last node in the list
} else {
// newLink has to be inserted between focus and focus.next
}
}
Then insert. Beware of edge cases, inserting at the front and the end are slightly different.