zoukankan      html  css  js  c++  java
  • 面试题13:在O(1)时间删除链表结点

    题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。

     链表结点与函数的定义如下:

    struct ListNode
    {
        int m_nValue;
        ListNode* m_pNext;
    };
    
    void DeleteNode(ListNode** pListHead,ListNode* pToBeDeleted);

    删除结点的操作我们经常碰到,比如一个链表A->B->C->D->E->F->G。如果我们要删除结点E,那么我们只需要让结点D的指针指向结点F即可,但是我们现在只给出链表头结点的指针以及结点E的指针,而又是单项链表,不能在O(1)时间内得到被删除结点前面的那一个结点的指针,所以我们原先的方法是不能在O(1)时间内删除结点E的。

    那么既然我们不能获得被删除结点的前一个结点的指针,我们就需要转变思路来考虑是否能够用过被删除结点后一个结点的指针来解决方法。因此被删除结点E的后一个结点指针是很容易得到的,也就是E->m_pNext。

    那么我们可能会想到如下方法:获得F的指针,将F的数据赋值给E,然后让E指向F的下一个结点。这里虽然删除的是结点F,但是相当于删除的是结点E。并且是O(1)时间复杂度。下面给出代码实例:

    View Code
    #include<iostream>
    #include<stdlib.h>
    #include<stack>
    using namespace std;
    
    //链表结构
    struct ListNode
    {
        int m_nValue;
        ListNode* m_pNext;
    };
    
    //创建一个链表结点
    ListNode* CreateListNode(int value)
    {
        ListNode *pNode=new ListNode();
        pNode->m_nValue=value;
        pNode->m_pNext=NULL;
        return pNode;
    
    }
    
    
    //遍历链表中的所有结点
    void PrintList(ListNode* pHead)
    {
        ListNode *pNode=pHead;
        while(pNode!=NULL)
        {
            cout<<pNode->m_nValue<<" ";
            pNode=pNode->m_pNext;
        }
        cout<<endl;
    }
    
    void ConnectListNode(ListNode* pCurrent,ListNode* pNext)//连接两个结点
    {
        if(pCurrent==NULL)
        {
            cout<<"前一个结点不能为空"<<endl;
            exit(1);
        }
        else
        {
            pCurrent->m_pNext=pNext;
        }
    }
    
    void DeleteNode(ListNode** pListHead,ListNode* pToBeDeleted)
    {
        if(pToBeDeleted->m_pNext!=NULL)//如果要删除结点后面还有结点
        {
            ListNode* pNext=pToBeDeleted->m_pNext;
            pToBeDeleted->m_nValue=pNext->m_nValue;
            pToBeDeleted->m_pNext=pNext->m_pNext;
            delete pNext;
            pNext=NULL;
        }
        else if(*pListHead==pToBeDeleted)//如果链表只有一个结点
        {
            delete pToBeDeleted;
            pToBeDeleted=NULL;
            *pListHead=NULL;
        }
        else//如果链表有多个结点,且删除最后一个结点,那么只能遍历链表
        {
            ListNode *pNode=*pListHead;
            while(pNode->m_pNext!=pToBeDeleted)
                pNode=pNode->m_pNext;
            pNode->m_pNext=NULL;
            delete pToBeDeleted;
            pToBeDeleted=NULL;
        }
    }
    
    void main()
    {
        //创建结点
        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);//创建一个结点
        //连接结点
        ConnectListNode(pNode1,pNode2);//连接两个结点
        ConnectListNode(pNode2,pNode3);//连接两个结点
        ConnectListNode(pNode3,pNode4);//连接两个结点
        ConnectListNode(pNode4,pNode5);//连接两个结点
        ConnectListNode(pNode5,pNode6);//连接两个结点
        ConnectListNode(pNode6,pNode7);//连接两个结点
        //打印链表
        PrintList(pNode1);//打印
        //删除结点
        DeleteNode(&pNode1,pNode3);
        //打印链表
        PrintList(pNode1);//打印
    
        system("pause");
    
    }

    输出结果:

    1 2 3 4 5 6 7
    1 2 4 5 6 7

  • 相关阅读:
    gearman简介及安装使用
    Linux下进程的建立
    Linux中无缓冲文件I/O API
    XMLRPC for PHP简介及使用
    数据库水平切分方法
    LVS简介及使用
    进程通信之消息队列
    install docker/dockercompose
    centOS7 下安装 JDK
    iTerm2/firewall/pulsar
  • 原文地址:https://www.cnblogs.com/xwdreamer/p/2472102.html
Copyright © 2011-2022 走看看