问题
While solving the problem that reverse first K elements of linked list i have written the below recursive code but the last iteration executing twice i.e for k=1, function call reverseNode() happening twice. Can any body why it happening like that. Please correct me if i did any thing wrong in it.
Example :
If input is
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
and k = 4 then output is
4 -> 3 -> 2 -> 1 -> 5 -> 6 -> 7 -> 8
public void reverseListRecursion(int k) {
this.reverseNode(null, headNode,k);
}
public void reverseNode(Node node, Node nextNode,int k) {
while (k > 0) {
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
if (k == 0) {
this.kNode = nextNode;
this.kNode.next = null;
}
if (node == null) {
nextNode.next = this.kNode;
} else {
nextNode.next = node;
}
}
Working code for my logic it is working expected. but when i try to use variable "k" in "if" condition instead of "presentCounter" then it is going wrong. Can any body tell me the reason.
public void reverseListRecursion(int count) {
this.reverseNode(null, headNode, count);
System.out.println("\n");
this.display(this.headNode);
}
/*
* Condition K <= Length of linked list.
*/
public void reverseNode(Node node, Node nextNode, int k) {
int presentCounter = k;
if (k > 1) {
k = k - 1;
this.reverseNode(nextNode, nextNode.next, k);
}
if (presentCounter == 1) {
this.kNode = nextNode.next; // Saving K's Next Node
this.headNode = nextNode; // Setting K node as head node
}
if (node == null) {
nextNode.next = this.kNode;
} else
nextNode.next = node;
}
回答1:
Your recursion should be
if (k > 0) { // and not while
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
...
回答2:
There are several issues with this code you provided in your question:
public void reverseListRecursion(int k) {
this.reverseNode(null, headNode,k);
}
public void reverseNode(Node node, Node nextNode,int k) {
while (k > 0) {
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
if (k == 0) {
this.kNode = nextNode;
this.kNode.next = null;
}
if (node == null) {
nextNode.next = this.kNode;
} else {
nextNode.next = node;
}
}
The wile loop will make the number of recursive calls grow to k!. Maybe this was your intention, but it certainly would not make an efficient algorithm. The job can be done by moving k-1 nodes, so making k! calls is not so efficient.
The first argument (node) never changes: the recursive call just passes the same argument, and so the value you pass in the initial call (
null) is what this argument will be in every call. The outcome of the lastifcondition will therefore always be the same. This doesn't look right.The first
ifcondition will always be true, because it is opposite to thewhilecondition that precedes it. So there should be no need to make the test fork == 0.The code within the first
ifblock makesthis.kNodea synonym fornextNodeand then itsnextproperty is set tonull. There should be no reason at all to set anynextproperty tonull. If anything, it will break the linked list.In the second
ifblock thenextproperty ofnextNodeis set to ...nextNode(see previous point, which shows thatthis.kNodewas made synonymous fornextNode). So now you have a self-referencing node, which really is something you'd never want to have. This code makes the first k+1 nodes self-referencing, thereby effectively detaching them from the original linked list.The initial call is made with headNode as second argument. This variable is apparently a private member of the class you are in. However, after execution the reversal, headNode will still reference the node it referred to before the call. The name suggests it should point to the first node in the list, but since the reversal will move another node at the front, headNode will point to the wrong node after completion. There is no other variable or property you have that will point to the first node in the list after the reversal. this.kNode could have been it, but the statements
this.kNode.next = nullandnextNode.next = this.kNodeare not things you would do with the first node of a list.
There are too many issues with this code to get a clear view on what you actually tried to do.
I would suggest to go for this algorithm, explained by example:
list = 1 2 3 4 5 6 7 8
k = 4
Move the node that follows the original first node to the head of the list
list = 2 1 3 4 5 6 7 8
k = 3
Move the node that follows the original first node to the head of the list
list = 3 2 1 4 5 6 7 8
k = 2
Move the node that follows the original first node to the head of the list
list = 4 3 2 1 5 6 7 8
k = 1
As k = 1 no more moves have to be made.
This is how your code would look:
public void reverseListRecursion(int k) {
// The reversal returns the node that took the first position
this.headNode = this.reverseNode(this.headNode, k, this.headNode);
};
public Node reverseNode(Node origFirstNode, int k, Node currFirstNode) {
// If 1 element needs to be reversed, there is nothing to do:
if (k <= 1) return currFirstNode;
// Move the node after the original first node before the current first node
Node movingNode = origFirstNode.next;
origFirstNode.next = movingNode.next;
movingNode.next = currFirstNode;
// The moved node is now the current first node. Repeat:
return this.reverseNode(origFirstNode, k-1, movingNode);
};
The nice thing about this solution is that the reverseNode method does not need to reference this.headNode, and so it can be used to reverse elements in the middle of the list as well. You could add this method which takes a node as second argument:
public void reverseListRecursionAfter(int k, Node afterNode) {
afterNode.next = this.reverseNode(afterNode.next, k, afterNode.next);
};
This will reverse the nodes following the given node.
Here is a live snippet, with the same code translated to JavaScript (just for demo):
// Node class
function Node(val, next) {
this.val = val;
this.next = next;
this.toString = function (cascade) {
if (!cascade || this.next === null) return '(' + this.val + ')';
if (this.next === this) return '(' + this.val + ')-loop';
return '(' + this.val + ')->' + this.next.toString(true);
}
}
// List class
function List() {
this.headNode = null;
this.reverseListRecursion = function(k) {
// The reversal returns the node that took the first position
this.headNode = this.reverseNode(this.headNode, k, this.headNode);
};
this.reverseNode = function(origFirstNode, k, currFirstNode) {
// If 1 element needs to be reversed, there is nothing to do:
if (k <= 1) return currFirstNode;
// Move the node after the original first node before the current first node
var movingNode = origFirstNode.next;
origFirstNode.next = movingNode.next;
movingNode.next = currFirstNode;
// The moved node is now the current first node. Repeat:
return this.reverseNode(origFirstNode, k-1, movingNode);
};
this.insert = function (arr) {
for (var i = arr.length - 1; i >= 0; i--) {
this.headNode = new Node(arr[i], this.headNode);
}
}
this.toString = function () {
return '{' + this.headNode.toString(true) + '}';
}
}
var output = [];
// Sample data
var list = new List();
list.insert([1, 2, 3, 4, 5, 6, 7, 8]);
output.push('before: ' + list);
// Make the reversal call
list.reverseListRecursion(4);
output.push('after: ' + list);
// Show result in snippet
document.write(output.join('<br>'));
来源:https://stackoverflow.com/questions/36668348/reversing-first-k-nodes-of-linked-list-why-recursion-executing-twice-for-last-it