📜  用于查找两个链表的交点的 C++ 程序

📅  最后修改于: 2022-05-13 01:55:19.795000             🧑  作者: Mango

用于查找两个链表的交点的 C++ 程序

一个系统中有两个单链表。由于一些编程错误,其中一个链表的结束节点链接到了第二个链表,形成了一个倒 Y 形链表。编写一个程序来获取两个链表合并的点。

Y形链表

上图显示了一个示例,其中两个链表具有 15 个作为交点。

方法1(只需使用两个循环):
使用 2 个嵌套的 for 循环。外部循环将针对第一个列表的每个节点,内部循环将针对第二个列表。在内部循环中,检查第二个链表的任何节点是否与第一个链表的当前节点相同。此方法的时间复杂度为 O(M * N),其中 m 和 n 是两个列表中的节点数。

方法2(标记访问节点):
该解决方案需要修改基本的链表数据结构。每个节点都有一个已访问标志。遍历第一个链表并不断标记访问过的节点。现在遍历第二个链表,如果再次看到访问过的节点,则有一个交点,返回相交的节点。此解决方案在O(m+n)中有效,但需要每个节点的附加信息。不需要修改基本数据结构的该解决方案的变体可以使用散列来实现。遍历第一个链表并将访问节点的地址存储在哈希中。现在遍历第二个链表,如果您看到哈希中已经存在的地址,则返回相交节点。

方法3(使用节点数的差异):

  • 获取第一个列表中的节点数,设 count 为 c1。
  • 获取第二个列表中的节点数,设 count 为 c2。
  • 获得计数的差异d = abs(c1 – c2)
  • 现在遍历从第一个节点到 d 个节点的更大列表,以便从这里开始两个列表的节点数相等
  • 然后我们可以并行遍历这两个列表,直到遇到一个公共节点。 (注意,获取普通节点是通过比较节点的地址来完成的)

下图是上述方法的试运行:

以下是上述方法的实现:

C++
// C++ program to get intersection point of two linked list
#include 
using namespace std;
  
// Link list node 
class Node 
{
    public:
    int data;
    Node* next;
};
  
// Function to get the counts of 
// node in a linked list 
int getCount(Node* head);
  
/*  Function to get the intersection 
    point of two linked lists head1 
    and head2 where head1 has d more 
    nodes than head2 */
int _getIntesectionNode(int d, Node* head1,
                        Node* head2);
  
/* Function to get the intersection point 
   of two linked lists head1 and head2 */
int getIntesectionNode(Node* head1, 
                       Node* head2)
{
    // Count the number of nodes in
    // both the linked list
    int c1 = getCount(head1);
    int c2 = getCount(head2);
    int d;
  
    // If first is greater
    if (c1 > c2) 
    {
        d = c1 - c2;
        return _getIntesectionNode(d, head1,
                                   head2);
    }
    else 
    {
        d = c2 - c1;
        return _getIntesectionNode(d, head2, 
                                   head1);
    }
}
  
/* Function to get the intersection point 
   of two linked lists head1 and head2 
   where head1 has d more nodes than head2 */
int _getIntesectionNode(int d, Node* head1, 
                        Node* head2)
{
    // Stand at the starting of the 
    // bigger list
    Node* current1 = head1;
    Node* current2 = head2;
  
    // Move the pointer forward
    for (int i = 0; i < d; i++) 
    {
        if (current1 == NULL) 
        {
            return -1;
        }
        current1 = current1->next;
    }
  
    // Move both pointers of both list till 
    // they intersect with each other
    while (current1 != NULL && 
           current2 != NULL) 
    {
        if (current1 == current2)
            return current1->data;
  
        // Move both the pointers forward
        current1 = current1->next;
        current2 = current2->next;
    }
  
    return -1;
}
  
/* Takes head pointer of the linked list and 
   returns the count of nodes in the list */
int getCount(Node* head)
{
    Node* current = head;
  
    // Counter to store count of nodes
    int count = 0;
  
    // Iterate till NULL
    while (current != NULL) 
    {
        // Increase the counter
        count++;
  
        // Move the Node ahead
        current = current->next;
    }
  
    return count;
}
  
// Driver Code
int main()
{
    /* Create two linked lists     
        1st 3->6->9->15->30 
        2nd 10->15->30     
        15 is the intersection point */
    Node* newNode;
  
    // Addition of new nodes
    Node* head1 = new Node();
    head1->data = 10;
  
    Node* head2 = new Node();
    head2->data = 3;
  
    newNode = new Node();
    newNode->data = 6;
    head2->next = newNode;
  
    newNode = new Node();
    newNode->data = 9;
    head2->next->next = newNode;
  
    newNode = new Node();
    newNode->data = 15;
    head1->next = newNode;
    head2->next->next->next = newNode;
  
    newNode = new Node();
    newNode->data = 30;
    head1->next->next = newNode;
  
    head1->next->next->next = NULL;
  
    cout << "The node of intersection is " << 
             getIntesectionNode(head1, head2);
}
// This code is contributed by rathbhupendra


C++
// C++ program to print intersection of lists
#include 
using namespace std;
  
// Link list node 
class Node 
{
    public:
    int data;
    Node* next;
};
  
// A utility function to return  
// intersection node
Node* intersectPoint(Node* head1, 
                     Node* head2)
{
    // Maintaining two pointers ptr1 
    // and ptr2 at the head of A and B,
    Node* ptr1 = head1;
    Node* ptr2 = head2;
  
    // If any one of head is NULL i.e
    // no Intersection Point
    if (ptr1 == NULL || ptr2 == NULL) 
    {
        return NULL;
    }
  
    // Traverse through the lists until 
    // they reach Intersection node
    while (ptr1 != ptr2) {
  
        ptr1 = ptr1->next;
        ptr2 = ptr2->next;
  
        // If at any node ptr1 meets ptr2, 
        // then it is intersection node.
        // Return intersection node.
  
        if (ptr1 == ptr2) 
        {
            return ptr1;
        }
  
        /* Once both of them go through 
           reassigning, they will be 
           equidistant from the collision
           point.*/
  
        // When ptr1 reaches the end of a list,
        // then reassign it to the head2.
        if (ptr1 == NULL) 
        {
            ptr1 = head2;
        }
        // When ptr2 reaches the end of a list, 
        // then redirect it to the head1.
        if (ptr2 == NULL) 
        {
            ptr2 = head1;
        }
    }
  
    return ptr1;
}
  
// Function to print intersection nodes
// in  a given linked list
void print(Node* node)
{
    if (node == NULL)
        cout << "NULL";
    while (node->next != NULL) 
    {
        cout << node->data << "->";
        node = node->next;
    }
    cout << node->data;
}
  
// Driver code
int main()
{
    /* Create two linked lists
    1st Linked list is 3->6->9->15->30
    2nd Linked list is 10->15->30
    15 30 are elements in the intersection
    list */
    Node* newNode;
    Node* head1 = new Node();
    head1->data = 10;
    Node* head2 = new Node();
    head2->data = 3;
    newNode = new Node();
    newNode->data = 6;
    head2->next = newNode;
    newNode = new Node();
    newNode->data = 9;
    head2->next->next = newNode;
    newNode = new Node();
    newNode->data = 15;
    head1->next = newNode;
    head2->next->next->next = newNode;
    newNode = new Node();
    newNode->data = 30;
    head1->next->next = newNode;
    head1->next->next->next = NULL;
    Node* intersect_node = NULL;
  
    // Find the intersection node of
    // two linked lists
    intersect_node = intersectPoint(head1, 
                                    head2);
  
    cout << "INTERSEPOINT LIST :";
    print(intersect_node);
    return 0;
    // This code is contributed by bolliranadheer
}


输出:

The node of intersection is 15

时间复杂度: O(m+n)
辅助空间: O(1)

方法4(在第一个列表中画圈):
感谢Saravanan Man提供以下解决方案。
1.遍历第一个链表(计数元素),制作一个循环链表。 (记住最后一个节点,以便我们以后可以打破圆圈)。
2. 现在将问题视为在第二个链表中找到循环。所以问题就解决了。
3. 由于我们已经知道循环的长度(第一个链表的大小),我们可以遍历第二个链表中的许多节点,然后从第二个链表的开头开始另一个指针。我们必须遍历直到它们相等,这就是所需的交点。
4. 从链表中删除圆圈。

时间复杂度: O(m+n)
辅助空间: O(1)

方法5(反转第一个列表并制作方程式):
感谢Saravanan Mani提供这种方法。

1) Let X be the length of the first linked list until intersection point.
   Let Y be the length of the second linked list until the intersection point.
   Let Z be the length of the linked list from the intersection point to End of
   the linked list including the intersection node.
   We Have
           X + Z = C1;
           Y + Z = C2;
2) Reverse first linked list.
3) Traverse Second linked list. Let C3 be the length of second list - 1. 
     Now we have
        X + Y = C3
     We have 3 linear equations. By solving them, we get
       X = (C1 + C3 – C2)/2;
       Y = (C2 + C3 – C1)/2;
       Z = (C1 + C2 – C3)/2;
      WE GOT THE INTERSECTION POINT.
4)  Reverse first linked list.

优点:没有指针比较。
缺点:修改链表(倒排表)。
时间复杂度: O(m+n)
辅助空间: O(1)

方法6(遍历两个列表并比较最后一个节点的地址):该方法仅用于检测是否存在交叉点。 (感谢 NeoTheSaviour 的建议)

1) Traverse the list 1, store the last node address
2) Traverse the list 2, store the last node address.
3) If nodes stored in 1 and 2 are same then they are intersecting.

该方法的时间复杂度为O(m+n),使用的辅助空间为O(1)

方法 7(2-point 技术):

使用两个指针:

  • 在 head1 和 head2 处初始化两个指针 ptr1 和 ptr2。
  • 遍历列表,一次一个节点。
  • 当 ptr1 到达列表末尾时,将其重定向到 head2。
  • 同样,当 ptr2 到达列表末尾时,将其重定向到 head1。
  • 一旦它们都经过重新分配,它们将与
    碰撞点
  • 如果在任何节点 ptr1 与 ptr2 相遇,那么它就是交集节点。
  • 在第二次迭代后,如果没有交叉节点,则返回 NULL。

C++

// C++ program to print intersection of lists
#include 
using namespace std;
  
// Link list node 
class Node 
{
    public:
    int data;
    Node* next;
};
  
// A utility function to return  
// intersection node
Node* intersectPoint(Node* head1, 
                     Node* head2)
{
    // Maintaining two pointers ptr1 
    // and ptr2 at the head of A and B,
    Node* ptr1 = head1;
    Node* ptr2 = head2;
  
    // If any one of head is NULL i.e
    // no Intersection Point
    if (ptr1 == NULL || ptr2 == NULL) 
    {
        return NULL;
    }
  
    // Traverse through the lists until 
    // they reach Intersection node
    while (ptr1 != ptr2) {
  
        ptr1 = ptr1->next;
        ptr2 = ptr2->next;
  
        // If at any node ptr1 meets ptr2, 
        // then it is intersection node.
        // Return intersection node.
  
        if (ptr1 == ptr2) 
        {
            return ptr1;
        }
  
        /* Once both of them go through 
           reassigning, they will be 
           equidistant from the collision
           point.*/
  
        // When ptr1 reaches the end of a list,
        // then reassign it to the head2.
        if (ptr1 == NULL) 
        {
            ptr1 = head2;
        }
        // When ptr2 reaches the end of a list, 
        // then redirect it to the head1.
        if (ptr2 == NULL) 
        {
            ptr2 = head1;
        }
    }
  
    return ptr1;
}
  
// Function to print intersection nodes
// in  a given linked list
void print(Node* node)
{
    if (node == NULL)
        cout << "NULL";
    while (node->next != NULL) 
    {
        cout << node->data << "->";
        node = node->next;
    }
    cout << node->data;
}
  
// Driver code
int main()
{
    /* Create two linked lists
    1st Linked list is 3->6->9->15->30
    2nd Linked list is 10->15->30
    15 30 are elements in the intersection
    list */
    Node* newNode;
    Node* head1 = new Node();
    head1->data = 10;
    Node* head2 = new Node();
    head2->data = 3;
    newNode = new Node();
    newNode->data = 6;
    head2->next = newNode;
    newNode = new Node();
    newNode->data = 9;
    head2->next->next = newNode;
    newNode = new Node();
    newNode->data = 15;
    head1->next = newNode;
    head2->next->next->next = newNode;
    newNode = new Node();
    newNode->data = 30;
    head1->next->next = newNode;
    head1->next->next->next = NULL;
    Node* intersect_node = NULL;
  
    // Find the intersection node of
    // two linked lists
    intersect_node = intersectPoint(head1, 
                                    head2);
  
    cout << "INTERSEPOINT LIST :";
    print(intersect_node);
    return 0;
    // This code is contributed by bolliranadheer
}

输出:

INTERSEPOINT LIST :15->30

时间复杂度: O( m + n )
辅助空间: O(1)

有关详细信息,请参阅关于编写函数以获取两个链表的交点的完整文章!