• <剑指OFFER18> 18_02_DeleteDuplicationNode删除重复节点


    /*******************************************************************
    Copyright(c) 2016, Harry He
    All rights reserved.
    
    Distributed under the BSD license.
    (See accompanying file LICENSE.txt at
    https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt)
    *******************************************************************/
    
    //==================================================================
    // 《剑指Offer——名企面试官精讲典型编程题》代码
    // 作者:何海涛
    //==================================================================
    
    // 面试题18(二):删除链表中重复的结点
    // 题目:在一个排序的链表中,如何删除重复的结点?例如,在图3.4(a)中重复
    // 结点被删除之后,链表如图3.4(b)所示。
    
    #include <cstdio>
    #include "list.h"
    
    void DeleteDuplicationAnswer(ListNode** pHead)
    {
        if (pHead == nullptr || *pHead == nullptr)
            return;
    
        ListNode* pPreNode = nullptr;
        ListNode* pNode = *pHead;
        while (pNode != nullptr)
        {
            ListNode *pNext = pNode->m_pNext;
            bool needDelete = false;
            if (pNext != nullptr && pNext->m_nValue == pNode->m_nValue)
                needDelete = true;
    
            if (!needDelete)
            {
                pPreNode = pNode;
                pNode = pNode->m_pNext;
            }
            else
            {
                int value = pNode->m_nValue;
                ListNode* pToBeDel = pNode;
                while (pToBeDel != nullptr && pToBeDel->m_nValue == value)
                {
                    pNext = pToBeDel->m_pNext;
    
                    delete pToBeDel;
                    pToBeDel = nullptr;
    
                    pToBeDel = pNext;
                }
    
                if (pPreNode == nullptr)
                    *pHead = pNext;
                else
                    pPreNode->m_pNext = pNext;
                pNode = pNext;
            }
        }
    }
    /*
    1. 头节点可能与后面的节点重复,头节点可能被删除
    2. 从头遍历整个链表,如果当前节点和下一节点的值相同,删除
    3. 删除后,当前节点的前一节点和后面值比当前节点的值大的节点相连
    如果头节点为空,返回
    while(当前节点不为空)
    {
        如果找到重复节点,删除标志位为真
    
        删除标志为假
        {
            循环下一节点
        }
            
        删除标志为真:
        {
            删掉连续的重复节点,判断是不是空,防止到了尾节点
    
            如果是从头节点开始重复了,重置新的头节点指针
            如果不是的话,前一节点连接不重复的节点
    
            重置当前节点的位置为pNext
        }
    
    }
    */
    void DeleteDuplication(ListNode** pHead)
    {
        if (pHead == nullptr || *pHead == nullptr)
            return;
        /*如果头节点不是重复节点,那么链表的头节点地址是不变的,中间内容会变*/
        /*pNode的作用是遍历链表,减掉重复节点,再把断的链表连起来*/
        /*只要有了链表头节点地址就可以遍历整个链表,有了地址就可以访问和修改里面内容,这样是有效的*/
        ListNode *pNode = *pHead;
        ListNode *pPre = nullptr;
        /*终止条件是pNode==nullptr,这时*pHead并没有变!!!*/
        while (pNode != nullptr)
        {
            bool need_delete = false;
            ListNode *pNext = pNode->m_pNext;
            // need delete conditions
            if (pNode->m_pNext != nullptr &&/* 如果只有一个节点,则下一节点没有值*/
                pNode->m_nValue == pNext->m_nValue)
                need_delete = true;
    
            // do not need delete
            if (!need_delete)
            {
                pPre = pNode;
                pNode = pNode->m_pNext;
            }
            else//need delete
            {
                ListNode *pToBeDeleted = pNode;
                int value = pNode->m_nValue;
                while (pToBeDeleted != nullptr && pToBeDeleted->m_nValue == value)
                {
                    pNext = pToBeDeleted->m_pNext;
    
                    delete pToBeDeleted;
                    pToBeDeleted = nullptr; //??
                     
                    pToBeDeleted = pNext;
                }
                /*从头节点开始就重复了,还没来得及给Pre节点赋值*/
                if (pPre == nullptr)
                    *pHead = pToBeDeleted;//重置头节点指针,不能使用pNode,作为null退出
                else
                {
                    pPre->m_pNext = pToBeDeleted;
                }
                /* 1 1 1 4 5 5*/
                pNode = pToBeDeleted;
                /*
                pNode和pHead作用是不同的,pHead记录头节点地址,有它可以访问所有节点
                pNode相当于迭代器,遍历每一节点,执行删除和连接操作。
                */
            }
        }
    }
    
    // ====================测试代码====================
    void Test(char* testName, ListNode** pHead, int* expectedValues, int expectedLength)
    {
        if (testName != nullptr)
            printf("%s begins: ", testName);
    
        DeleteDuplication(pHead);
    
        int index = 0;
        ListNode* pNode = *pHead;
        while (pNode != nullptr && index < expectedLength)
        {
            if (pNode->m_nValue != expectedValues[index])
                break;
    
            pNode = pNode->m_pNext;
            index++;
        }
    
        if (pNode == nullptr && index == expectedLength)
            printf("Passed.
    ");
        else
            printf("FAILED.
    ");
    }
    
    // 某些结点是重复的
    void Test1()
    {
        ListNode* pNode1 = CreateListNode(1);
        ListNode* pNode2 = CreateListNode(2);
        ListNode* pNode3 = CreateListNode(3);
        ListNode* pNode4 = CreateListNode(3);
        ListNode* pNode5 = CreateListNode(4);
        ListNode* pNode6 = CreateListNode(4);
        ListNode* pNode7 = CreateListNode(5);
    
        ConnectListNodes(pNode1, pNode2);
        ConnectListNodes(pNode2, pNode3);
        ConnectListNodes(pNode3, pNode4);
        ConnectListNodes(pNode4, pNode5);
        ConnectListNodes(pNode5, pNode6);
        ConnectListNodes(pNode6, pNode7);
    
        ListNode* pHead = pNode1;
    
        int expectedValues[] = { 1, 2, 5 };
        Test("Test1", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));
    
        DestroyList(pHead);
    }
    
    // 没有重复的结点
    void Test2()
    {
        ListNode* pNode1 = CreateListNode(1);
        ListNode* pNode2 = CreateListNode(2);
        ListNode* pNode3 = CreateListNode(3);
        ListNode* pNode4 = CreateListNode(4);
        ListNode* pNode5 = CreateListNode(5);
        ListNode* pNode6 = CreateListNode(6);
        ListNode* pNode7 = CreateListNode(7);
    
        ConnectListNodes(pNode1, pNode2);
        ConnectListNodes(pNode2, pNode3);
        ConnectListNodes(pNode3, pNode4);
        ConnectListNodes(pNode4, pNode5);
        ConnectListNodes(pNode5, pNode6);
        ConnectListNodes(pNode6, pNode7);
    
        ListNode* pHead = pNode1;
    
        int expectedValues[] = { 1, 2, 3, 4, 5, 6, 7 };
        Test("Test2", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));
    
        DestroyList(pHead);
    }
    
    // 除了一个结点之外其他所有结点的值都相同
    void Test3()
    {
        ListNode* pNode1 = CreateListNode(1);
        ListNode* pNode2 = CreateListNode(1);
        ListNode* pNode3 = CreateListNode(1);
        ListNode* pNode4 = CreateListNode(1);
        ListNode* pNode5 = CreateListNode(1);
        ListNode* pNode6 = CreateListNode(1);
        ListNode* pNode7 = CreateListNode(2);
    
        ConnectListNodes(pNode1, pNode2);
        ConnectListNodes(pNode2, pNode3);
        ConnectListNodes(pNode3, pNode4);
        ConnectListNodes(pNode4, pNode5);
        ConnectListNodes(pNode5, pNode6);
        ConnectListNodes(pNode6, pNode7);
    
        ListNode* pHead = pNode1;
    
        int expectedValues[] = { 2 };
        Test("Test3", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));
    
        DestroyList(pHead);
    }
    
    // 所有结点的值都相同
    void Test4()
    {
        ListNode* pNode1 = CreateListNode(1);
        ListNode* pNode2 = CreateListNode(1);
        ListNode* pNode3 = CreateListNode(1);
        ListNode* pNode4 = CreateListNode(1);
        ListNode* pNode5 = CreateListNode(1);
        ListNode* pNode6 = CreateListNode(1);
        ListNode* pNode7 = CreateListNode(1);
    
        ConnectListNodes(pNode1, pNode2);
        ConnectListNodes(pNode2, pNode3);
        ConnectListNodes(pNode3, pNode4);
        ConnectListNodes(pNode4, pNode5);
        ConnectListNodes(pNode5, pNode6);
        ConnectListNodes(pNode6, pNode7);
    
        ListNode* pHead = pNode1;
    
        Test("Test4", &pHead, nullptr, 0);
    
        DestroyList(pHead);
    }
    
    // 所有结点都成对出现
    void Test5()
    {
        ListNode* pNode1 = CreateListNode(1);
        ListNode* pNode2 = CreateListNode(1);
        ListNode* pNode3 = CreateListNode(2);
        ListNode* pNode4 = CreateListNode(2);
        ListNode* pNode5 = CreateListNode(3);
        ListNode* pNode6 = CreateListNode(3);
        ListNode* pNode7 = CreateListNode(4);
        ListNode* pNode8 = CreateListNode(4);
    
        ConnectListNodes(pNode1, pNode2);
        ConnectListNodes(pNode2, pNode3);
        ConnectListNodes(pNode3, pNode4);
        ConnectListNodes(pNode4, pNode5);
        ConnectListNodes(pNode5, pNode6);
        ConnectListNodes(pNode6, pNode7);
        ConnectListNodes(pNode7, pNode8);
    
        ListNode* pHead = pNode1;
    
        Test("Test5", &pHead, nullptr, 0);
    
        DestroyList(pHead);
    }
    
    // 除了两个结点之外其他结点都成对出现
    void Test6()
    {
        ListNode* pNode1 = CreateListNode(1);
        ListNode* pNode2 = CreateListNode(1);
        ListNode* pNode3 = CreateListNode(2);
        ListNode* pNode4 = CreateListNode(3);
        ListNode* pNode5 = CreateListNode(3);
        ListNode* pNode6 = CreateListNode(4);
        ListNode* pNode7 = CreateListNode(5);
        ListNode* pNode8 = CreateListNode(5);
    
        ConnectListNodes(pNode1, pNode2);
        ConnectListNodes(pNode2, pNode3);
        ConnectListNodes(pNode3, pNode4);
        ConnectListNodes(pNode4, pNode5);
        ConnectListNodes(pNode5, pNode6);
        ConnectListNodes(pNode6, pNode7);
        ConnectListNodes(pNode7, pNode8);
    
        ListNode* pHead = pNode1;
    
        int expectedValues[] = { 2, 4 };
        Test("Test6", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));
    
        DestroyList(pHead);
    }
    
    // 链表中只有两个不重复的结点
    void Test7()
    {
        ListNode* pNode1 = CreateListNode(1);
        ListNode* pNode2 = CreateListNode(2);
    
        ConnectListNodes(pNode1, pNode2);
    
        ListNode* pHead = pNode1;
    
        int expectedValues[] = { 1, 2 };
        Test("Test7", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));
    
        DestroyList(pHead);
    }
    
    // 结点中只有一个结点
    void Test8()
    {
        ListNode* pNode1 = CreateListNode(1);
    
        ConnectListNodes(pNode1, nullptr);
    
        ListNode* pHead = pNode1;
    
        int expectedValues[] = { 1 };
        Test("Test8", &pHead, expectedValues, sizeof(expectedValues) / sizeof(int));
    
        DestroyList(pHead);
    }
    
    // 结点中只有两个重复的结点
    void Test9()
    {
        ListNode* pNode1 = CreateListNode(1);
        ListNode* pNode2 = CreateListNode(1);
    
        ConnectListNodes(pNode1, pNode2);
    
        ListNode* pHead = pNode1;
    
        Test("Test9", &pHead, nullptr, 0);
    
        DestroyList(pHead);
    }
    
    // 空链表
    void Test10()
    {
        ListNode* pHead = nullptr;
    
        Test("Test10", &pHead, nullptr, 0);
    }
    
    int main(int argc, char* argv[])
    {
        //Test1();
        Test2();
        //Test3();
        //Test4();
        //Test5();
        //Test6();
        //Test7();
        //Test8();
        //Test9();
        //Test10();
    
        return 0;
    }
    /*******************************************************************
    Copyright(c) 2016, Harry He
    All rights reserved.
    
    Distributed under the BSD license.
    (See accompanying file LICENSE.txt at
    https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt)
    *******************************************************************/
    
    //==================================================================
    // 《剑指Offer——名企面试官精讲典型编程题》代码
    // 作者:何海涛
    //==================================================================
    
    #include "list.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    ListNode* CreateListNode(int value)
    {
        ListNode* pNode = new ListNode();
        pNode->m_nValue = value;
        pNode->m_pNext = nullptr;
    
        return pNode;
    }
    
    void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)
    {
        if(pCurrent == nullptr)
        {
            printf("Error to connect two nodes.
    ");
            exit(1);
        }
    
        pCurrent->m_pNext = pNext;
    }
    
    void PrintListNode(ListNode* pNode)
    { 
        if(pNode == nullptr)
        {
            printf("The node is nullptr
    ");
        }
        else
        {
            printf("The key in node is %d.
    ", pNode->m_nValue);
        }
    }
    
    void PrintList(ListNode* pHead)
    {
        printf("PrintList starts.
    ");
        
        ListNode* pNode = pHead;
        while(pNode != nullptr)
        {
            printf("%d	", pNode->m_nValue);
            pNode = pNode->m_pNext;
        }
    
        printf("
    PrintList ends.
    ");
    }
    
    void DestroyList(ListNode* pHead)
    {
        ListNode* pNode = pHead;
        while(pNode != nullptr)
        {
            pHead = pHead->m_pNext;
            delete pNode;
            pNode = pHead;
        }
    }
    
    void AddToTail(ListNode** pHead, int value)
    {
        ListNode* pNew = new ListNode();
        pNew->m_nValue = value;
        pNew->m_pNext = nullptr;
    
        if(*pHead == nullptr)
        {
            *pHead = pNew;
        }
        else
        {
            ListNode* pNode = *pHead;
            while(pNode->m_pNext != nullptr)
                pNode = pNode->m_pNext;
    
            pNode->m_pNext = pNew;
        }
    }
    
    void RemoveNode(ListNode** pHead, int value)
    {
        if(pHead == nullptr || *pHead == nullptr)
            return;
    
        ListNode* pToBeDeleted = nullptr;
        if((*pHead)->m_nValue == value)
        {
            pToBeDeleted = *pHead;
            *pHead = (*pHead)->m_pNext;
        }
        else
        {
            ListNode* pNode = *pHead;
            while(pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue != value)
                pNode = pNode->m_pNext;
    
            if(pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue == value)
            {
                pToBeDeleted = pNode->m_pNext;
                pNode->m_pNext = pNode->m_pNext->m_pNext;
            }
        }
    
        if(pToBeDeleted != nullptr)
        {
            delete pToBeDeleted;
            pToBeDeleted = nullptr;
        }
    }
    /*******************************************************************
    Copyright(c) 2016, Harry He
    All rights reserved.
    
    Distributed under the BSD license.
    (See accompanying file LICENSE.txt at
    https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt)
    *******************************************************************/
    
    //==================================================================
    // 《剑指Offer——名企面试官精讲典型编程题》代码
    // 作者:何海涛
    //==================================================================
    
    struct ListNode
    {
        int       m_nValue;
        ListNode* m_pNext;
    };
    
    __declspec( dllexport ) ListNode* CreateListNode(int value);
    __declspec( dllexport ) void ConnectListNodes(ListNode* pCurrent, ListNode* pNext);
    __declspec( dllexport ) void PrintListNode(ListNode* pNode);
    __declspec( dllexport ) void PrintList(ListNode* pHead);
    __declspec( dllexport ) void DestroyList(ListNode* pHead);
    __declspec( dllexport ) void AddToTail(ListNode** pHead, int value);
    __declspec( dllexport ) void RemoveNode(ListNode** pHead, int value);
  • 相关阅读:
    Dijit、ExtJS、jQuery UI 异同浅析
    Sencha Touch和jQuery Mobile该如何选择(转)
    用delphi开发activex打印控件
    组织机构图
    MyBatis自学(1):MyBatis概述
    MyBatis自学(4):动态SQL
    MyBatis自学(3):MyBatis逆向工程
    MyBatis自学(2):MyBatis初识
    MyBatis自学(5):延迟加载
    FileUpload上传图片提示 “GDI+中发生一般性错误”
  • 原文地址:https://www.cnblogs.com/focus-z/p/12780968.html
Copyright © 2020-2023  润新知