线性时间查找两个单链表的交叉结点

线性时间查找两个单链表的交叉结点

思路

为了解决本道题有多种解法。
方法 1)先将两个单链表LA和LB分别遍历一遍,获得各自的长度为m和n,假设m比n大,那么先对LA表从头遍历m-n个元素。接下来两个表同时遍历,若两个指针指向同一个结点,则停止。返回指向该结点的任一指针。
方法 2)先将两个单链表LA和LB分别遍历一遍,分别将各自的指针保存在两个栈中。然后同时对两个栈进行top操作,直到两个栈顶元素相等,也就是两个栈顶指针所指向的结点相同,则停止。返回指向该结点的任一指针。
本文实现的是方法1)。见以下代码中的getInterNode函数。merge函数是一个辅助函数,为了构造两个尾部结点相同的单链表。

代码

#include <iostream>
#include <vector>
#include <cassert>
#include <stack>
#include <string>
using namespace std;
typedef int Type;
struct Node
{
    Type data;
    Node * next;
};
void createList(Node * & phead, const vector<Type> & inp)
{
    phead = new Node;
    phead->data = inp.at(0);
    phead->next = NULL;
    Node * p = phead;
    int i = 1;
    while( i<inp.size() )
    {
        Node * pnew = new Node;
        pnew->data = inp.at(i);
        pnew->next = NULL;
        p->next = pnew;
        p = pnew;
        i++;
    }
}
void destroyList(Node * & phead)
{
    assert(phead != NULL);
    Node * pnext = phead->next;
    while(pnext)
    {
        delete phead;
        phead = pnext;
        pnext = phead->next;
    }
    delete phead;
}
void mergeNode(Node *hA, Node *hB)
{
    Node * headA = hA;
    Node * headB = hB;
    stack<Node *> chain1, chain2;
    while( headA !=  NULL )
    {
        chain1.push( headA );
        headA =  headA -> next;
    }
    while( headB !=  NULL )
    {
        chain2.push( headB );
        headB =  headB -> next;
    }
    int lena=chain1.size(), lenb=chain2.size();
    int len = 0;
    Node * record = NULL;
    assert ( chain1.top()->data == chain2.top()->data );
    while( !chain1.empty() && !chain2.empty() && chain1.top()->data == chain2.top()->data )
    {
        chain1.pop();
        chain2.pop();
        lena--;
        lenb--;
    }
    headA = hA;
    headB = hB;
    int rcA = 0, rcB = 0;
    while( headA && rcA < lena )
    {
        rcA++;
        headA = headA->next;
    }
    while( headB && rcB < lenb-1 )
    {
        rcB++;
        headB = headB->next;
    }
    destroyList( headB->next );
    headB->next = headA;
}

Node * getInterNode(Node *headA, Node *headB)
{
    int rcA = 0, rcB = 0;
    Node * ha = headA;
    Node * hb = headB;
    while( ha )
    {
        rcA++;
        ha = ha->next;
    }
    while( hb )
    {
        rcB++;
        hb = hb->next;
    }
    int sub = rcA>rcB ? (rcA-rcB) : (rcB-rcA);
    ha = headA;
    hb = headB;
    int rc = 0;
    while( rcA>rcB && ha && rc<sub )
    {
        rc++;
        ha = ha->next;
    }
    while( rcA<rcB && hb && rc<sub )
    {
        rc++;
        hb = hb->next;
    }
    while( ha && hb && ha != hb )
    {
        ha = ha->next;
        hb = hb->next;
    }
    if (ha)
    {
        return ha;
    }
    else
    {
        return NULL;
    }
}

int main()
{
    int arr1[] = {0, 1, 2, 3, 4, 5};
    int arr2[] = {7, 2, 3, 4, 5};
    vector<Type> inp1(arr1, arr1+6);
    vector<Type> inp2(arr2, arr2+5);
    Node * l1 = NULL;
    Node * l2 = NULL;
    createList(l1, inp1);
    createList(l2, inp2);
    mergeNode(l1, l2);
    Node * ret = getInterNode(l1, l2);
    cout<<"cross node: "<<ret->data<<endl;
    destroyList(l1);
    destroyList(l2);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值