我使用Javascript编写循环链表并检测并删除循环。它正常工作,直到循环检测的部分。怎么没有删除loopnode。更具体地说:此代码的removeLoop函数不起作用。
这是我的代码:
function Node(element){
this.element = element;
this.next = null;
}
//circular linked list class
function LList() {
this.head = new Node("head");
this.head.next = this.head;
this.find = find;
this.insert = insert;
this.display = display;
}
function find(item){
var curr = this.head;
while(curr.element != item){
curr = curr.next;
}
return curr;
}
//inserting items into linked list
function insert(newElem, after){
var newNode = new Node(newElem);
var curr = this.find(after);
newNode.next = curr.next;
curr.next = newNode;
}
function display() {
var currNode = this.head;
while ((currNode.next !== null) &&
(currNode.next.element !== "head")) {
console.log(currNode.next.element);
currNode = currNode.next;
}
}
function findPrevious(item){
var curr = this.head;
while(curr.next !== null && curr.next.element !== item){
curr =curr.next;
}
return curr;
}
//creating a linkedlist object
var furniture = new LList();
furniture.insert("chair","head");
furniture.insert("table", "chair");
furniture.insert("couch", "table");
furniture.insert("stool","couch");
//furniture.display();
//detecting if a linked list is circular
function detectALoop(list){
var slow = list.head;
var fast = list.head;
while(slow && fast && fast.next){
slow = slow.next;
fast = fast.next.next;
if(slow === fast){
removeLoop (slow, list);
return 1;
}
}
return 0;
}
//This part of the code doesnot work
function removeLoop(loopNode, list)
{
var ptr1 = loopNode;
var ptr2 = loopNode;
var looplen = 1,i;
// count the number of nodes in loop
while(ptr1.next != ptr2)
{
ptr1 = ptr1.next;
looplen++;
}
console.log(looplen)
ptr1 = list.head;
ptr2 = list.head;
for(i=0; i <= looplen; i++)
{
ptr2 = ptr2.next;
}
while(ptr2.next != ptr1.next)
{
ptr1 = ptr1.next;
ptr2 = ptr2.next;
}
ptr2.next = null; // breaking the loop
}
console.log(detectALoop(furniture))
furniture.display();
答案 0 :(得分:1)
如果循环必须回到第一个元素上,那么你要使它变得比它需要的复杂得多。
function breakLoop(list) {
var head = list.head, tail = head, len = 1;
while (tail.next != head) {
len++;
tail = tail.next;
}
tail.next = null;
console.log(len.toString());
}
现在如果你可能需要处理任意循环,我仍然不知道你需要3个循环。使用ES6 Set
;我相信大多数浏览器现在支持这一点。我将继续前进并返回长度而不是记录它。
function breakLoopAnywhere(list) {
var seen = new Set, node = list.head;
while (!seen.has(node.next)) {
seen.add(node);
node = node.next;
}
node.next = null;
return seen.size;
}
如果您没有套装,则可以使用数组进行破解,将has
替换为indexOf
,将add
替换为push
。
如果您觉得必须能够检测循环与非循环列表而不破坏它:
// takes a node, returns the node
// that points backwards on its next
function getLoopNode(node) {
var seen = new Set;
do {
seen.add(node);
} while (!seen.has(node.next) && node = node.next)
return node;
}
function detectLoop(node) {
return getLoopNode(node) != null;
}
function breakLoop(node) {
node = getLoopNode(node);
if (node) node.next = null;
}
您的detectALoop
不那么复杂,但是错了。这将检测的唯一循环是节点2i
是否循环回节点i
。但是这个列表可能是3个元素长的循环开始;它可能是很多不是2i
和i
的数字。由于可能有很多数字,太多而无法全部尝试,因此您无法修复此策略。没有聪明的方法可以在图表中找到比我上面写的更快或更直观的周期。据我所知。
答案 1 :(得分:0)
这个变量搞砸了......
var looplen = 1,i;
看起来你希望它是1。
答案 2 :(得分:0)
您的removeLoop
代码错误,永远不会终止:
让我们假设这个清单:
A -> B -> C -> A
循环长度为3.
您正确找到了循环长度3,然后将ptr1
和ptr2
设置到列表的开头,然后在.next
上为ptr2
调用<{1}} strong>循环的长度+ 1次(因为<=
)。
// for i = 0; i <= 3
A.next -> B // i = 0
B.next -> C // i = 1
C.next -> A // i = 2
A.next -> B // i = 33
所以最后你有ptr2
= B和ptr1
= A,即ptr2
=== ptr1.next
!
一个是下一个,在while循环中你前进到一个等于另一个,但它们永远不会,因为它们总是一个接下来的另一个!
如果您将<=
更改为<
它可以正常工作,但第二个while循环实际上没用。