循环链表逻辑

时间:2017-04-14 05:51:15

标签: java algorithm linked-list

FROM tbl_products, user_custom, compatibility

为了检测循环链表,我们使用2指针技术,慢速和快速。

我的问题是,如果列表是循环列表,我怎么知道指针必须在某些点相交?

4 个答案:

答案 0 :(得分:2)

看一下手表。这是一个数字1到12的循环列表,然后回到1。

大手快速移动,小手移动缓慢,向同一方向移动,从同一点开始(顶部= 12)。

因为列表(边缘)是圆形的,所以大手最终会回到小手上。速度有多快取决于速度差异,但它会赶上来。如果它赶上,列表必须是循环的。

如果它没有赶上,但到达列表的末尾,则列表不是循环的。

即使列表没有圈回到开头,例如如果12圈回到9,快手将继续盘旋,直到小手进入圆圈,然后快手将最终赶上小手。

好的,对于最后一部分,手表的图像并不好,但我希望你明白这一点。

答案 1 :(得分:2)

证据并不像看起来那么明显。

实际上,通过稍微更改可以使快速指针更快,例如。使用fast = fast.next.next.next,该算法不再保证可以正常工作。

重要的是两个指针的相对速度。

在标准情况下,相对速度为2 - 1 = 1,这意味着在每一步,快速指针都会获得一个靠近慢速指针的单位。通过这种方式,可以保证快速的一个能够赶上而不会跳过另一个。

否则,例如如果相对速度为3 - 1 = 2,那么它们可能永远不会相交。如果我们从指针之间的奇数距离开始,并且周期长度是偶数,则会发生这种情况。在这种情况下,距离始终保持为奇数(因此它永远不会为零)。

为了清楚指示如果不注意速度差异,指针可能不相交,请考虑速度为3的快速指针和速度为1的慢速指针,在一个带有4个节点的循环中运行,标记为0,1 ,2,3,形成像这样的循环0 - > 1 - > 2 - > 3 - > 0

假设最初,慢速指针位于节点0,快速指针位于节点1.(请注意,这不是一个强大的假设,并且可能无法通过不同的初始化策略来缓解 - 无论初始化方法如何,可能是图中有一些额外的节点,而不是循环的一部分,这使得指针一旦到达循环就可以处于任意位置。)

k步之后,慢指针将位于节点k mod 4。快节点将位于节点(1 + 3k) mod 4。假设存在k使快速和慢速指针位于同一位置,则表示(1 + 3k) mod 4 = k mod 4 (1 + 2k) mod 4 = 0。但左侧是奇数,因此它不能为零。因此,指针可以指向同一节点的假设会导致矛盾。

答案 2 :(得分:0)

好吧,正如andreas提到的那样看看手表,但如果仍然没有意义,那么this可以提供帮助。

此外,您可以稍微简化一下代码:

<?php
$string='www.domain.com dsa dsad sad sad sa domain.com asdasds adas dsa www.domain.com/someurl/?d sad sadsad www.domain.com/someurl/ asd asd sa www.domain.com?id=123 sd asdsa d';
echo preg_replace("/((?:www\.)?[a-zA-Z]+\.com)(?!\/|\?)|(www\.?[a-zA-Z]+.com\/(?:[^\/]+\/)*)/", "$1$2?add_text", $string);

我还认为您应该使用 head 而非 head.next

初始化快速指针

答案 3 :(得分:-1)

这是C中循环链接列表的完整实现:​​

#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node* next;
};
void insert(struct node** head,int ele){
struct node* temp = (struct node*)malloc(sizeof(struct node));
struct node* ptr;
temp->data = ele;
temp->next = temp;
if(*head == NULL){
    *head = temp;
}else{
    ptr = *head;
    while(ptr->next != *head){
        ptr = ptr->next;
    }
    ptr->next = temp;
    temp->next = *head;
}
}
void deleteLastEle(struct node** head){
struct node* current = *head;
struct node* pre = *head;
while(current->next != *head){
    pre = current;
    current = current->next;
}
pre->next = current->next;
free(current);
}
void deleteAtPos(struct node** head,int pos){
struct node* current = *head;
struct node* pre = *head;
for(int i=0;i<pos-1;i++){
    pre = current;
    current = current->next;
}
pre->next = current->next;
free(current);
}
void deleteFirst(struct node** head){
struct node* current = *head;
struct node* temp = *head;
while(current->next != *head){
    current = current->next;
}
current->next = (*head)->next;
*head = (*head)->next;
free(temp);
}
printCLL(struct node** head){
struct node* ptr = *head;
do{
    printf("%d ",ptr->data);
    ptr = ptr->next;
}while(ptr != *head);
printf("\n");
}
// main() function.
int main(void) {
struct node* head = NULL;
for(int i=0;i<5;i++){
    //function to insert elements in linked list
    insert(&head,i);
}
printf("inseted linkedlist: \n");
//print the content of linked list.
printCLL(&head);

//function to delete last element
deleteLastEle(&head);
printf("after deleting last element: \n");
printCLL(&head);

//function to delete element at pos 3.
deleteAtPos(&head,3);
printf("after deleting at pos 3: \n");
printCLL(&head);

//function to delete first element of linkedlust
deleteFirst(&head);
printf("after deleting first element: \n");
printCLL(&head);
return 0;
}

这些是输出:

inseted linkedlist: 
0 1 2 3 4 
after deleting last element: 
0 1 2 3 
after deleting at pos 3: 
0 1 3 
after deleting first element: 
1 3