有一个单项的链表,在没有头结点的情况下,只知道有一个指向结点B的指针p,假设这个结点B不是尾结点,删除该节点B。

**

问题:有一个单项的链表,在没有头结点的情况下,只知道有一个指向结点B的指针p,假设这个结点B不是尾结点,删除该节点B。

**

    p->data = p->next->data;
    p->next = p->next->next;
    free(p->next)

解析:要删除p指向的结点B,必须要将结点B前后的两个节点A和C连接起来,但是该单链表没有头结点,因此无法追溯到A,也就无法将A和C相连了。无法删除结点B,但我们可以删除B的后继结点C,并通过p->next = p->next->next重新将链表连接起来,而唯一丢失的是结点C的数据项data。因此,我们只需要将结点C的数据项取代结点B的数据项,然后将真正指向结点C的指针删除即可是实现将结点B删除。

**

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

**

解析:在链表中删除一个结点,最常规的做法是从链表的头结点开始,顺序查找要删除的结点,找到之后再删除。由于需要顺序查找,时间复杂度自然是O(n)。我们之所以需要从头结点开始查找要删除的结点,是因为我们需要得到要删除的结点的前面一个结点。我们试着换一种思路。我们可以从给定的结点得到它的下一个结点。这个时候我们实际删除的是它的下一个结点,由于我们已经得到实际删除的结点的前面一个结点,因此完全是可以实现的。当然,在删除之前,我们需要把给定结点的下一个结点的数据拷贝到给定的结点中。此时,时间复杂度为O(1)。上面的思路还有一个问题:如果删除的结点位于链表的尾部,没有下一个结点,怎么办?我们仍从链表的头结点开始,顺便遍历得到给定结点的前序结点,并完成删除操作。这个时间复杂度是O(n)。题目要求在O(1)时间完成删除操作,这个算法是不是不符合要求。实际上,假设链表总共有n个结点,我们的算法在n-1总情况下时间复杂度是O(1),只有当给定的结点处于链表尾部的时候,时间复杂度为O(n)。那么平均时间复杂度[(n-1)*O(1)+O(n)]/n,仍然是O(1)。

void DeleteRandomNode(Node *pListHead, Node *pCurrent)
{
    assert(pCurrent!=NULL || pListHead!=NULL);
    if(pCurrent->next!=NULL)        //要删除的结点不是最后一个结点
    {
        Node *pNext = pCurrent->next;
        pCurrent->data = pNext->data;
        pCurrent->next = pNext->next;
        delete pNext;
        pNext = NULL;
    }
    else
    {
        Node *pNode = pListHead;
        while(pNode->next!=pCurrent)       //得到要删除结点的前继结点
        {
            pNode = pNode->next;
        }
        pNode->next = NULL;
        delete pCurrent;
        pCurrent = NULL;
    }
}

**
同类问题:假设有一个没有头指针的单链表,一个指针p指向单链表中的一个结点(不是第一个,也不是最后一个),请在该结点之前插入一个新的结点q。
**

//在p结点后添加q,然后交换p和q的数据域即可。
q->next = p->next;
p->next = q;
swap(&p->data, &q->value);

代码实例:

#include <QtCore/QCoreApplication>
#include <iostream>
#include <assert.h>
#include <malloc.h>

struct ListNode
{
    int data;
    ListNode *next;
};

typedef ListNode Node;

//参数必须是指向指针的指针,因为要修改指针,所以要考虑“参数本地拷贝”问题
void initList(Node **pList)
{
    *pList = (Node*)malloc(sizeof(Node));
    (*pList)->next = NULL;
}

//第一个参数不必是指向指针的指针,因为函数内只修改指针指向的数据,所以不用担心“参数本地拷贝”问题
void insertList(Node *pList, int data)
{
    Node* pNewNode = (Node*)malloc(sizeof(Node));
    pNewNode->data = data;
    pNewNode->next = pList->next;
    pList->next = pNewNode;
}

void DeleteRandomNode(Node *pCurrent)
{
    assert(pCurrent!=NULL);
    Node *pNext = pCurrent->next;
    if(pNext!=NULL)
    {
        pCurrent->next = pNext->next;
        pCurrent->data = pNext->data;
        delete pNext;
        pNext = NULL;
    }
}

void DeleteRandomNode(Node *pListHead, Node *pCurrent)
{
    assert(pCurrent!=NULL || pListHead!=NULL);
    if(pCurrent->next!=NULL)        //要删除的结点不是最后一个结点
    {
        Node *pNext = pCurrent->next;
        pCurrent->data = pNext->data;
        pCurrent->next = pNext->next;
        delete pNext;
        pNext = NULL;
    }
    else
    {
        Node *pNode = pListHead;
        while(pNode->next!=pCurrent)       //得到要删除结点的前继结点
        {
            pNode = pNode->next;
        }
        pNode->next = NULL;
        delete pCurrent;
        pCurrent = NULL;
    }
}

//打印链表元素
void PrintListNormally(Node *pListHead)
{
    Node *pTempNode = pListHead->next;
    while(pTempNode!=NULL)
    {
        std::cout<<pTempNode->data<<std::endl;
        pTempNode = pTempNode->next;
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Node *pHead = NULL;

    initList(&pHead);

    //int i;
    for(int i=9; i>=0; i--)
    {
        insertList(pHead,i);
    }

    PrintListNormally(pHead);

    std::cout<<"\n";

    Node *pNext = pHead->next->next;
    DeleteRandomNode(pNext);

    PrintListNormally(pHead);

    return a.exec();
}

参考自:
http://blog.csdn.net/zhaozhanyong/article/details/6184203
http://www.cnblogs.com/fickleness/archive/2013/06/25/3154950.html

猜你喜欢

转载自blog.csdn.net/u011125673/article/details/50933070
今日推荐