俩链表的差集

题目描述

已知集合A和B的元素分别用不含头结点的单链表存储,函数difference()用于求解集合A与B的差集,并将结果保存在集合A的单链表中。例如,若集合A={5,10,20,15,25,30},集合B={5,15,35,25},完成计算后A={10,20,30}

思路

首先,我借助了俩段空间,第一个动态数组中存放的是第一个链表中的节点信息和每个节点对应的值信息,第二个动态数组存放的是第二个链表中的节点信息和每个节点对应的值信息。
首先我后面删除节点时用的是替换法,所以要判断下待删链表内是否只有一个节点,如果只有一个节点就没法用替换法删除了,所以我先做了一下判断。

第一步 我分别遍历了俩个链表把每个链表中的节点按值的大小对它们进行了排序。

第二步 用V1容器(第一个vector容器)中的数据不停的在第二个容器里面查找是否有相同值的节点(因为第二个链表的内容不动所以可以放心的使用二分法来查找),如果查找到了,就把V1相应节点删除,因为我保存的是键值对,所以可以用替换法删除相应节点,对于尾节点,我在最开始第一次遍历第一个链表时,就保存了尾节点的前一个节点,所以只要在最后对其处理即可。

第三步 把有交集的非尾节点在第一个链表中删除了,下来处理最后一个节点是否为有交集的节点即可。

时间复杂度

该思路主要的时间花费在遍历待删节点上,假设俩个链表都有N个节点。因为我每次查找都是用的二分查找所以单次为log2n,那么总的时间复杂度是O(nlog2n)。而且使用替换法删除时不用考虑头节点如果被删除如何返回的问题。

代码
void difference(Node** LA, Node* LB)
{
    if (LA == NULL || LB == NULL) return;
    Node*pCur_LA = *LA;
    Node*pCur_LB = LB;
    vector<pair<Node*,int>> v1;
    vector<pair<Node*,int>> v2;
    bool tail = false;
    Node*ptail_pre = NULL;
    if (pCur_LA->_PNext == NULL)
    {
        ptail_pre = pCur_LA;
    }
    while (pCur_LA)
    {
        v1.push_back(pair<Node*, int>(pCur_LA, pCur_LA->_data));
        pCur_LA = pCur_LA->_PNext;
        if (pCur_LA&&pCur_LA->_PNext&&pCur_LA->_PNext->_PNext == NULL)
        {
            ptail_pre = pCur_LA;
        }
    }
    while (pCur_LB)
    {
        v2.push_back(pair<Node*, int>(pCur_LB, pCur_LB->_data));
        pCur_LB = pCur_LB->_PNext;
    }
    int size = v1.size();
    compare com;
    std::sort(v1.begin(), v1.end(), com);
    std::sort(v2.begin(), v2.end(), com);
    int key = 0;
    Node*Del = NULL;
    for (size_t idx = 0; idx < v1.size(); ++idx)
    {
        key = v1[idx].first->_data;
        int left = 0;
        int right = v2.size();
        while (left < right)
        {
            int mid = (left&right) + ((left^right) >> 1);
            if (key < v2[mid].second)
            {
                right = mid;
            }
            else if (key>v2[mid].second)
            {
                left = mid + 1;
            }
            else{
                if (v1[idx].first->_PNext == NULL)
                {
                    tail = true;              //是否待删节点是尾节点的情况
                }
                else{
                    Del = v1[idx].first->_PNext;
                    v1[idx].first->_data=Del->_data;  //替换法删除 不用考虑ret的问题因为第一个节点不可能删除 ,并且到这块的代码是多个节点的
                    v1[idx].first->_PNext = Del->_PNext;
                    delete Del;
                    v1.erase(v1.begin() + idx+1);//虽然用替换法删除了,但是还得再容器中把相应节点删除掉,因为该节点的值还保存在容器中,防止下次遍历时出现野指针。
                    --idx;//因为替换法删除所以,即使删除了该节点指针下次也不应该前进了,应该留在新替换的节点上
                }
                break;
            }
        }
    }
    if (tail){
        if (v1.size() == 1) {
            delete ptail_pre;
            *LA = NULL;
        }
        else{
            delete ptail_pre->_PNext;
            ptail_pre->_PNext = NULL;
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值