删除单链表中的重复元素

很老的一道面试题,经典解法是用哈希表求解。如果不允许申请额外的存储空间,我能想到的就是用归并排序来搞,在归并的比较过程中删除重复元素,但成立的前提是允许改变原始链表元素的顺序。

用链表做归并排序有个方便的地方,就是不用像处理普通数组那样额外申请空间, 正好满足问题的附加条件。不方便的地方在于把规模n的问题分解为n/2子问题的时候,没法直接求得中点。简单粗暴的做法是分解问题时先遍历到中点,这样会增加n/2*logn的复杂度,凑合。


struct Node{
     double v;
    Node* next;
};  // 链表元素
// 合并2个有序的链表,顺带删除重复元素
static Node* mergeList(Node* pHead1,Node* pHead2)
{
    Node* pHead = NULL;
    Node* pTail =NULL;
     while(pHead1 != NULL && pHead2 != NULL)
    {
        Node* pMin;  // 需要一个临时变量保存当前的最小值
         if(pHead1->v < pHead2->v)
        {
            pMin = pHead1;
            pHead1 = pHead1->next;
        }
         else  if(pHead1->v > pHead2->v)
        {
            pMin = pHead2;
            pHead2 = pHead2->next;
        }
         else// 删除重复元素
            Node* t = pHead2;
            pHead2 = pHead2->next;
            delete t;
             continue// 注意
        }

         if(pHead == NULL){
            pHead = pMin;
            pTail = pMin;
        }
         else{
            pTail->next = pMin;  // 注意要更新->next
            pTail = pMin;  // 更新合并后的链表尾
        }
    }

     if(pHead==NULL){
        pHead = (pHead1==NULL) ? pHead2 : pHead1;
    }
     else{
        pTail->next = (pHead1==NULL) ? pHead2 : pHead1;  // 注意是->next
    }
     return pHead;
}
// 第二个入参为链表的长度
static Node* mergeSort(Node* pHead, int size)
{
     if(size ==  1){ return pHead;}
     int half =  size/ 2;
    Node* last = pHead;  // 遍历到左边list的最后一个元素
     for( int i = 0; i < half- 1;++i)
    {
        last = last->next;
    }

    Node* right = last->next;
    last->next = NULL;  // 分割链表前记得保存为right
    mergeSort(pHead,half);
    mergeSort(right,size-half);
     return mergeList(pHead,right);
}
// 最外层的主函数
Node* deleteDups(Node* pHead)
{
     if(pHead == NULL){ return NULL;}
     int size= 0;
    Node* t = pHead;
     while(t != NULL)
    {
        ++size;
        t = t->next;
    }
     return  mergeSort(pHead,size);
}

转载于:https://www.cnblogs.com/pop-lar/p/4181430.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值