我有一个循环的链表,我想找出这个列表中元素的总数。如何做到这一点?
5 回答
我能想到的一种解决方案是维护两个指针。第一个指针 (*start) 将始终指向起始节点,例如节点 A。另一个指针 (*current) 将被初始化为:current = start->next。
现在,只需使用 current -> next 迭代每个节点,直到它指向开始。并不断增加一个计数器:numberOfNodes++;
代码将如下所示:
public int countNumberOfItems(Node* start){
Node* current = start -> next;
int numberOfNodes = 1; //Atleast the starting node is there.
while(current->next != start){
numberOfNodes++;
current = current->next;
}
return numberOfNodes;
}
您只想计算链表中的节点对吗?我在下面举了一个例子。但是在您的情况下,存在一个循环,因此您还需要检测到这一点,以免多次计算某些节点。我已经更正了我的答案,现在有一个普通的计数和循环计数(使用快速和慢速指针)。
static int count( Node n)
{
int res = 1;
Node temp = n;
while (temp.next != n)
{
res++;
temp = temp.next;
}
return res;
}
static int countInLoop( Node list)
{
Node s_pointer = list, f_pointer = list;
while (s_pointer !=null && f_pointer!=null && f_pointer.next!=null)
{
s_pointer = s_pointer.next;
f_pointer = f_pointer.next.next;
if (s_pointer == f_pointer)
return count(s_pointer);
}
return 0;
}
假设列表x
在循环之前有节点,在循环中有节点y
。运行 Floyd 循环检测,计算慢步数s
。一旦你检测到一个交汇点,再绕圈跑一次得到y
.
现在,从列表头开始,s - y
逐步到达节点N
。最后,运行两个慢速指针N
,M
直到它们相遇,作为t
步骤。说服自己(或更好地证明)他们在列表的初始部分进入循环的地方相遇。
因此,初始部分有s - y + t + 1
节点,循环由y
节点组成,给出s + t + 1
总数。
首先使用弗洛伊德循环检测算法找到循环,并在检查循环时保持计数,一旦找到循环,然后打印相同的计数。
function LinkedList() {
let length = 0;
let head = null;
let Node = function(element) {
this.element = element;
this.next = null;
}
this.head = function() {
return head;
};
this.add = function(element) {
let node = new Node(element);
if(head === null){
head = node;
} else {
let currentNode = head;
while(currentNode.next) {
currentNode = currentNode.next;
}
currentNode.next = node;
}
};
this.detectLoopWithCount = function() {
head.next.next.next.next.next.next.next.next = head; // make cycle
let fastPtr = head;
let slowPtr = head;
let count = 0;
while(slowPtr && fastPtr && fastPtr.next) {
count++;
slowPtr = slowPtr.next;
fastPtr = fastPtr.next.next;
if (slowPtr == fastPtr) {
console.log("\n Bingo :-) Cycle found ..!! \n ");
console.log('Total no. of elements = ', count);
return;
}
}
}
}
let mylist = new LinkedList();
mylist.add('list1');
mylist.add('list2');
mylist.add('list3');
mylist.add('list4');
mylist.add('list5');
mylist.add('list6');
mylist.add('list7');
mylist.add('list8');
mylist.detectLoopWithCount();
有一个“慢”指针一次移动一个节点。有一个“快速”指针以两倍的速度移动,一次两个节点。
作为慢速和快速指针在具有 10 个节点的链表中移动的可视化:
1: |sf--------|
2: |-s-f------|
3: |--s--f----|
4: |---s---f--|
5: |----s----f|
在这一点上,有两件事之一是正确的:1) 链表不循环(用 fast != null && fast.next != null 检查)或 2) 它循环。假设它确实循环,让我们继续可视化:
6: |-f----s---|
7: |---f---s--|
8: |-----f--s-|
9: |-------f-s|
10: s == f
如果链表没有循环,则快速指针在 O(n/2) 时间完成竞争;我们可以删除常数并将其称为 O(n)。如果链表确实循环,则慢指针在整个链表中移动,并最终在 O(n) 时间等于快指针。