Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 检查两个链接列表是否合并。如果是,在哪里?_Algorithm_Linked List_Data Structures - Fatal编程技术网

Algorithm 检查两个链接列表是否合并。如果是,在哪里?

Algorithm 检查两个链接列表是否合并。如果是,在哪里?,algorithm,linked-list,data-structures,Algorithm,Linked List,Data Structures,这个问题可能很老,但我想不出答案 比如说,有两个长度不同的列表,在一个点合并;我们如何知道合并点在哪里 条件: 我们不知道长度 我们应该只解析每个列表一次 也许我过于简化了,但只需迭代最小的列表并使用最后的节点链接作为合并点 因此,其中Data->Link->Link==NULL是终点,将Data->Link作为合并点(在列表的末尾) 编辑: 好的,从你发布的图片,你分析两个列表,最小的第一个。使用最小的列表,可以维护对以下节点的引用。现在,当您解析第二个列表时,您将对引用进行比较,以找到引用[

这个问题可能很老,但我想不出答案

比如说,有两个长度不同的列表,在一个点合并;我们如何知道合并点在哪里

条件:

  • 我们不知道长度
  • 我们应该只解析每个列表一次

  • 也许我过于简化了,但只需迭代最小的列表并使用最后的节点
    链接
    作为合并点

    因此,其中
    Data->Link->Link==NULL
    是终点,将
    Data->Link
    作为合并点(在列表的末尾)

    编辑:

    好的,从你发布的图片,你分析两个列表,最小的第一个。使用最小的列表,可以维护对以下节点的引用。现在,当您解析第二个列表时,您将对引用进行比较,以找到引用[i]在LinkedList[i]->Link处的引用位置。这将给出合并点。用图片解释的时间(将数值叠加在OP的图片上)

    您有一个链接列表(参考资料如下所示):

    A->B->C->D->E

    您还有第二个链接列表:

    1->2->

    对于合并列表,引用将如下所示:

    x = a+c
    y = b+c
    
    1->2->D->E->

    因此,您映射了第一个“较小”列表(因为合并列表的长度为4,主列表的长度为5)

    循环浏览第一个列表,维护引用的引用

    该列表将包含以下引用
    指针{1,2,D,E}

    现在我们来看第二个列表:

    -> A - Contains reference in Pointers? No, move on
    -> B - Contains reference in Pointers? No, move on
    -> C - Contains reference in Pointers? No, move on
    -> D - Contains reference in Pointers? Yes, merge point found, break.
    

    当然,您维护了一个新的指针列表,但这并不在规范之外。但是,第一个列表只解析一次,第二个列表只有在没有合并点的情况下才会被完全解析。否则,它将更快地结束(在合并点)。

    这可能违反了“仅解析每个列表一次”的条件,但实现了(用于查找循环列表的合并点和循环长度),因此从列表a开始,当在末尾达到空值时,假装它是指向列表B开头的指针,从而创建循环列表的外观。然后,该算法将告诉您合并列表到底有多远(根据维基百科的描述,变量“mu”)


    另外,“lambda”值告诉您列表B的长度,如果需要,您可以在算法过程中计算出列表A的长度(当您重定向空链接时)。

    如果您知道它们将合并:

    假设您从以下内容开始:

    A-->B-->C
            |
            V
    1-->2-->3-->4-->5
    
    1) 浏览第一个列表,将下一个指针设置为NULL

    现在你有:

    A   B   C
    
    1-->2-->3   4   5
    
    2) 现在浏览第二个列表,直到看到一个空值,这是您的合并点

    如果您不能确定它们是否合并,您可以使用sentinel值作为指针值,但这并没有那么优雅。

    如果

    • “不允许修改”的意思是“您可以更改,但最终应该恢复”,以及
    • 我们可以迭代列表两次
    下面的算法就是解决方案

    首先是数字。假设第一个列表的长度为
    a+c
    ,第二个列表的长度为
    b+c
    ,其中
    c
    是它们共同的“尾巴”(在合并点之后)的长度。让我们将它们表示为:

    x = a+c
    y = b+c
    
    由于我们不知道长度,我们将计算
    x
    y
    ,无需额外迭代;你会明白的

    然后,我们迭代每个列表,并在迭代时反转它们!如果两个迭代器同时到达合并点,那么我们仅通过比较就可以找到它。否则,一个指针将在另一个指针之前到达合并点

    之后,当另一个迭代器到达合并点时,它将不会继续到公共尾部。相反,它将返回到列表的前一个开始处,该列表以前已到达合并点!因此,在它到达更改列表的末尾(即另一个列表的前一个开头)之前,他将进行
    a+b+1
    iterations合计。让我们称之为
    z+1

    首先到达合并点的指针将继续迭代,直到到达列表的末尾。应计算其进行的迭代次数,并等于
    x

    然后,该指针会往回迭代并再次反转列表。但现在它不会回到它最初开始的列表的开头!相反,它将转到另一个列表的开头!它进行的迭代次数应计算并等于
    y

    因此,我们知道以下数字:

    x = a+c
    y = b+c
    z = a+b
    
    从中我们可以确定

    a = (+x-y+z)/2
    b = (-x+y+z)/2
    c = (+x+y-z)/2
    

    这解决了问题。

    这里有一个解决方案,计算速度快(每个列表迭代一次),但占用大量内存:

    for each item in list a
      push pointer to item onto stack_a
    
    for each item in list b
      push pointer to item onto stack_b
    
    while (stack_a top == stack_b top) // where top is the item to be popped next
      pop stack_a
      pop stack_b
    
    // values at the top of each stack are the items prior to the merged item
    

    我在FC9 x86_64上测试了一个合并案例,并打印了每个节点地址,如下所示:

    Head A 0x7fffb2f3c4b0
    0x214f010
    0x214f030
    0x214f050
    0x214f070
    0x214f090
    0x214f0f0
    0x214f110
    0x214f130
    0x214f150
    0x214f170
    
    
    Head B 0x7fffb2f3c4a0
    0x214f0b0
    0x214f0d0
    0x214f0f0
    0x214f110
    0x214f130
    0x214f150
    0x214f170
    
    注意,因为我已经对齐了节点结构,所以当malloc()是一个节点时,地址与16字节对齐,请参阅至少4位。 最小位为0,即0x0或000b。 因此,如果您的节点也处于相同的特殊情况(对齐节点地址),则可以使用这些至少4位。 例如,当从头部到尾部移动两个列表时,设置访问节点地址的4位中的1位或2位,即设置标志

    next_node = node->next;
    node = (struct node*)((unsigned long)node | 0x1UL);
    
    注意:以上标志不会影响实际节点地址,只会影响保存的节点指针值

    一旦发现有人设置了标志位,那么第一个找到的节点应该是合并点。 完成后,通过清除已设置的标志位来恢复节点地址。而重要的一点是,在迭代(例如node=node->next)执行clean时,应该小心。记住你已经设置了标志位,所以这样做

    real_node = (struct node*)((unsigned long)node) & ~0x1UL);
    real_node = real_node->next;
    node = real_node;
    

    由于此方案将恢复修改后的节点地址,因此可将其视为“无修改”。

    Pavel的回答需要修改
    //pseudocode
    //for the first list
    p1=list1;
    unsigned int addr[];//to store addresses
    i=0;
    while(p1!=null){
      addr[i]=&p1;
      p1=p1->next;
    }
    int len=sizeof(addr)/sizeof(int);//calculates length of array addr
    //for the second list
    p2=list2;
    while(p2!=null){
      if(search(addr[],len,&p2)==1)//match found
      {
        //this is the merging node
        return (p2);
      }
      p2=p2->next;
    }
    
    int search(addr,len,p2){
      i=0;  
      while(i<len){
        if(addr[i]==p2)
          return 1;
        i++;
      }
     return 0;
    } 
    
    struct node {
        int data;   
        int flag;  //initially set the flag to zero  for all nodes
        struct node *next;
    };
    
      if (node->next->field==1)//possibly longer list will have this opportunity
          //this will be your required node. 
    
    //Psuedocode
    def findmergepoint(list1, list2):
    lendiff = list1.length() > list2.length() : list1.length() - list2.length() ? list2.lenght()-list1.lenght()
    biggerlist = list1.length() > list2.length() : list1 ? list2  # list with biggest length
    smallerlist = list1.length() < list2.length() : list2 ? list1 # list with smallest length
    
    
    # move the biggest length to the diff position to level both the list at the same position
    for i in range(0,lendiff-1):
        biggerlist = biggerlist.next
    #Looped only once.  
    while ( biggerlist is not None and smallerlist is not None ):
        if biggerlist == smallerlist :
            return biggerlist #point of intersection
    
    
    return None // No intersection found
    
    int FindMergeNode(Node *headA, Node *headB)
    {
        Node *tempB=new Node;
        tempB=headB;
       while(headA->next!=NULL)
           {
           while(tempB->next!=NULL)
               {
               if(tempB==headA)
                   return tempB->data;
               tempB=tempB->next;
           }
           headA=headA->next;
           tempB=headB;
       }
        return headA->data;
    }
    
    int FindMergeNode(Node headA, Node headB) {
    
    Map<Object, Integer> map = new HashMap<Object, Integer>();
    
    while(headA != null || headB != null)
    {
        if(headA != null && map.containsKey(headA.next))
        {
            return map.get(headA.next);
        }
    
        if(headA != null && headA.next != null)
        {
             map.put(headA.next, headA.next.data);
             headA = headA.next;
        }
    
        if(headB != null && map.containsKey(headB.next))
        {
            return map.get(headB.next);
        }
    
        if(headB != null && headB.next != null)
        {
            map.put(headB.next, headB.next.data);
            headB = headB.next;
        }
    }
    
    return 0;
    }
    
    static int findMergeNode(SinglyLinkedListNode head1, SinglyLinkedListNode head2) {
    
        SinglyLinkedListNode current = head1; //head1 is give to be not null.
    
        //mark all head1 nodes as negative
        while(true){
            current.data = -current.data;
            current = current.next;
            if(current==null) break;
        }
    
        current=head2; //given as not null
        while(true){
            if(current.data<0) return -current.data;
            current = current.next;
        }
    
    }
    
    int FindMergeNode(Node headA, Node headB) {
      Node currentA = headA;
      Node currentB = headB;
    
      // Do till the two nodes are the same
      while (currentA != currentB) {
        // If you reached the end of one list start at the beginning of the other
        // one currentA
        if (currentA.next == null) {
          currentA = headA;
        } else {
          currentA = currentA.next;
        }
        // currentB
        if (currentB.next == null) {
          currentB = headB;
        } else {
          currentB = currentB.next;
        }
      }
      return currentB.data;
    }
    
    int findMergeNode(SinglyLinkedListNode* head1, SinglyLinkedListNode* head2) {
        SinglyLinkedListNode* start1=head1;
        SinglyLinkedListNode* start2=head2;
        while (start1!=start2){
            start1=start1->next;
            start2=start2->next;
            if (!start1)
            start1=head2;
            if (!start2)
            start2=head1;
        }
        return start1->data;
    }
    
    static int findMergeNode(SinglyLinkedListNode head1, SinglyLinkedListNode head2) {
        HashSet<SinglyLinkedListNode> set=new HashSet<SinglyLinkedListNode>();
        while(head1!=null)
        {
            set.add(head1);
            head1=head1.next;
        }
        while(head2!=null){
            if(set.contains(head2){
                return head2.data;
            }
        }
        return -1;
    }