在解决链接列表的第一个K元素的反转问题时,我编写了下面的递归代码,但最后一次迭代执行了两次,即k = 1,函数调用reverseNode()发生了两次。任何身体都可以这样发生。如果我做错了,请纠正我。
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;
}
}
我的逻辑的工作代码正在工作中。但是当我尝试在“if”条件而不是“presentCounter”中使用变量“k”时,它就会出错。任何人都可以告诉我原因。
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;
}
答案 0 :(得分:0)
你的递归应该是
if (k > 0) { // and not while
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
...
答案 1 :(得分:0)
您在问题中提供的此代码存在以下几个问题:
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
块中,next
的{{1}}属性设置为... nextNode
(请参阅上一点,其中显示{{1} } {}为nextNode
)的同义词。所以现在你有一个自引用节点,这真的是你永远不想拥有的。此代码使第一个k + 1个节点自引用,从而有效地将它们从原始链表中分离出来。
使用 headNode 作为第二个参数进行初始调用。此变量显然是您所在类的私有成员。但是,执行反转后, headNode 仍将引用它在调用之前引用的节点。该名称表明它应该指向列表中的第一个节点,但由于反转将移动前面的另一个节点, headNode 将在完成后指向错误的节点。没有其他变量或属性将指向反转后列表中的第一个节点。 this.kNode 可能是它,但是this.kNode
和nextNode
语句不是您对列表的第一个节点所做的事情。
此代码存在太多问题,无法清楚地了解您实际尝试的内容。
我建议使用这个算法,例如:
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
当k = 1时,不必再进行任何移动。
这就是你的代码的样子:
list = 3 2 1 4 5 6 7 8
k = 2
这个解决方案的好处是list = 4 3 2 1 5 6 7 8
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
这将反转给定节点之后的节点。
这是一个实时代码段,将相同的代码转换为JavaScript(仅用于演示):
this.headNode
&#13;