判断两条链表是否交叉,若有交叉,返回交叉节点的指针。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了判断两条链表是否交叉,若有交叉,返回交叉节点的指针。相关的知识,希望对你有一定的参考价值。

上周面试挂了,反思原因,莫非是因为一道算法题没做好吗?这题目是“判断两条链表是否交叉,若有交叉,返回交叉节点的指针。” 为了防止反复在同一个阴沟里翻船,决定把最优解写出来。

#include "pch.h"
#include <iostream>

template<typename T>
class List {
public:
    struct Node {
        T data;
        Node* next;
        Node(T& d, Node* ntx = nullptr) : data(d), next(ntx) {}
    };
    Node* mHead = nullptr;
public:
    //List(){}
    ~List() {
        Node* pcur = mHead, *pnext = nullptr;
        while (pcur) {
            pnext = pcur->next;
            delete pcur;
            pcur = pnext;
        }
    }
    bool AddNode(T dt, bool attail = true) {
        Node*ptr = new Node(dt);
        return AddNode(ptr, attail);
    }
    bool AddNode(Node* nd, bool attail = true) {
        if (nd) {
            if (attail) {
                Node* ptail = Tail();
                if (ptail) {
                    ptail->next = nd;
                }
                else {
                    mHead = nd;
                }
            }
            else {
                nd->next = mHead;
                mHead = nd;
            }
            return true;
        }
        return false;
    }
    Node* Intersect(List& oth) {
        Node* lptr = nullptr, *sptr = nullptr;
        {
            const int sz1 = Size();
            const int sz2 = oth.Size();
            int num = 0;
            if (sz1 >= sz2) {
                lptr = mHead;
                sptr = oth.mHead;
                num = sz1 - sz2;
            }
            else {
                lptr = oth.mHead;
                sptr = mHead;
                num = sz1 - sz2;
            }
            for (int i = 0; i < num; ++i) {
                if (lptr) {
                    lptr = lptr->next;
                }
            }
        }
        while (lptr && sptr) {
            if (lptr == sptr) {
                return lptr;
            }
            lptr = lptr->next;
            sptr = sptr->next;
        }
        return nullptr;
    }

private:
    Node* Tail() {
        Node* ptr = mHead;
        while (ptr && ptr->next) {
            ptr = ptr->next;
        }
        return ptr;
    }
    int Size() {
        int sz = 0;
        Node* ptr = mHead;
        while (ptr) {
            ++sz;
            ptr = ptr->next;
        }
        return sz;
    }
};

int main()
{
    std::cout << "Hello World!
"; 
    List<int> list1, list2;
    for (int i = 1; i < 3; ++i) {
        list1.AddNode(i);
    }
    for (int i = 25; i < 28; ++i) {
        list2.AddNode(i);
    }

#if 1
    for (int i = 100; i < 101; ++i) {
        List<int>::Node* node = new List<int>::Node(i);
        list1.AddNode(node);
        list2.AddNode(node);
    }
#endif
    auto ptr = list1.Intersect(list2);
    if (ptr) {
        std::cout << "intersect point at " << ptr << std::endl;
    }
    else {
        std::cout << "no intersection
";
    }

    return 0;
}

代码创建了两条有交叉节点的链表。如图所示:
技术图片

程序运行结束时,析构这两条链表,发生错误,是因为交叉节点被两次释放:
技术图片

以上是关于判断两条链表是否交叉,若有交叉,返回交叉节点的指针。的主要内容,如果未能解决你的问题,请参考以下文章

判断两条链表是否相交(公共部分)并找出相交处

10.两个链表的交叉

算法面试

小程序 - 链表检测环/链表是否交叉 等

交叉染色法判断二分图

用VISIO画两条交叉的线,怎样让它们相交处有个小弯