您在问题中提供的此代码存在几个问题:
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;
}
}
wile 循环将使递归调用的次数增加到 k!。也许这是你的意图,但它肯定不会成为一个有效的算法。这项工作可以通过移动 k-1 个节点来完成,因此进行 k! 次调用并不是那么高效。
第一个参数 (node) 永远不会改变:递归调用只是传递相同的参数,因此您在初始调用 (null) 中传递的值就是这个参数每次通话都会出现。因此,最后一个if 条件的结果将始终相同。这看起来不对。
第一个 if 条件将始终为真,因为它与前面的 while 条件相反。所以应该没有必要对k == 0进行测试。
第一个if 块中的代码使this.kNode 成为nextNode 的同义词,然后将其next 属性设置为null。根本没有理由将任何next 属性设置为null。如果有的话,它会破坏链表。
在第二个 if 块中,nextNode 的 next 属性设置为 ... nextNode(参见上一点,这表明 this.kNode 与 nextNode 同义) .所以现在你有了一个自引用节点,这确实是你永远不想拥有的东西。此代码使前 k+1 个节点自引用,从而有效地将它们从原始链表中分离出来。
初始调用使用 headNode 作为第二个参数。这个变量显然是你所在类的私有成员。但是,在执行反转之后,headNode 仍将引用它在调用之前引用的节点。顾名思义,它应该指向列表中的第一个节点,但是由于反转会将另一个节点移到最前面,所以 headNode 完成后会指向错误的节点。在反转之后,您没有其他变量或属性将指向列表中的第一个节点。 this.kNode 可能是它,但语句 this.kNode.next = null 和 nextNode.next = this.kNode 不是你会对列表的第一个节点执行的操作。
此代码存在太多问题,无法清楚地了解您实际尝试执行的操作。
我建议使用这个算法,通过例子来解释:
list = 1 2 3 4 5 6 7 8
k = 4
将原始第一个节点之后的节点移动到列表的头部
list = 2 1 3 4 5 6 7 8
k = 3
将原始第一个节点之后的节点移动到列表的头部
list = 3 2 1 4 5 6 7 8
k = 2
将原始第一个节点之后的节点移动到列表的头部
list = 4 3 2 1 5 6 7 8
k = 1
由于 k = 1,因此不必再进行移动。
这就是您的代码的外观:
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);
};
这个解决方案的好处是reverseNode 方法不需要引用this.headNode,因此它也可以用于反转列表中间的元素。您可以添加此方法,该方法将节点作为第二个参数:
public void reverseListRecursionAfter(int k, Node afterNode) {
afterNode.next = this.reverseNode(afterNode.next, k, afterNode.next);
};
这将反转给定节点之后的节点。
这是一个实时的 sn-p,将相同的代码翻译成 JavaScript(仅用于演示):
// 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>'));