在O(1)时间内删除链表节点

来源:互联网 发布:mac能播p2p电影浏览器 编辑:程序博客网 时间:2024/05/29 17:28

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

【方案】
方案一:从链表头节点开始顺序遍历查找要删除的节点,并在链表中删除该节点,如图A。因为这种思路需要顺序查找,时间复杂度是O(n),不符合要求。
方案二:把要删除节点的下一个节点的数据覆盖到被删除的节点,然后把下个节点删除掉,如图B。
这里写图片描述
图1 删除链表节点图

【解题思路】
方案二有三种情况:
1、在多节点链表中,要删除的节点不是尾节点时。如B链表,要删除节点i,先把j节点的数据复制到i节点上,再让i的指针指向j节点的下一个节点,最后把j节点删除掉,就相当于删除了i节点。
2、链表只有一个节点,删除节点(既是头节点,也是尾节点)。在删除节点后,还要把头节点置空。
3、链表有多个节点,删除尾节点。从链表的头节点开始,顺序遍历得到该节点的前序节点,并完成删除操作。

【代码】

void DeleteNode(pList *plisthead, pList deletenode){    if (!*plisthead || !deletenode)    {        return;    }    //在多节点中,删除非尾节点    if (deletenode->next != NULL)    {        pNode pnext = deletenode->next;        deletenode->data = pnext->data;        deletenode->next = pnext->next;        delete pnext;        pnext = NULL;    }    //在单节点中删除节点(既是头节点,也是尾节点)    else if (*plisthead == deletenode)    {        delete deletenode;        deletenode = NULL;        *plisthead = NULL;    }    //在多节点中删除尾节点    else    {        if (deletenode->next == NULL)        {            pNode pnode = *plisthead;            while (pnode != deletenode)            {                pnode = pnode->next;            }            delete deletenode;            deletenode = NULL;        }    }}

【程序】

#define _CRT_SECURE_NO_WARNINGS 1# include <stdio.h># include <stdlib.h># include <assert.h>typedef int DataType;typedef struct Node{    DataType data;    struct Node *next;}Node, *pList, *pNode;void InitLinkList(pList *pplist){    assert(pplist);    *pplist = NULL;}void PushBack(pList *pplist, DataType x){    pNode cur = *pplist;    pNode pnode = NULL;    assert(pplist);    pnode = (pNode)malloc(sizeof(Node));    if (pnode == NULL)    {        perror("PushBack::malloc");        exit(EXIT_FAILURE);    }    pnode->data = x;    pnode->next = NULL;    if (cur == NULL)    {        *pplist = pnode;    }    else    {        while (cur->next != NULL)        {            cur = cur->next;        }        cur->next = pnode;    }}void Display(pList plist){    pNode cur = plist;    while (cur)    {        printf("%d-->", cur->data);        cur = cur->next;    }    printf("over\n");}void PrintNode(pList plist){    assert(plist);    pNode cur = plist;    if (plist == NULL)    {        return;    }    else    {        printf("%d\n", cur->data);    }}void Destroy(pList *pplist){    pNode cur = *pplist;    assert(pplist);    while (cur)    {        pNode del = cur;        cur = cur->next;        free(del);    }    *pplist = NULL;}void DeleteNode(pList *plisthead, pList deletenode){    if (!*plisthead || !deletenode)    {        return;    }    //在多节点中,删除非尾节点    if (deletenode->next != NULL)    {        pNode pnext = deletenode->next;        deletenode->data = pnext->data;        deletenode->next = pnext->next;        delete pnext;        pnext = NULL;    }    //在单节点中删除节点(既是头节点,也是尾节点)    else if (*plisthead == deletenode)    {        delete deletenode;        deletenode = NULL;        *plisthead = NULL;    }    //在多节点中删除尾节点    else    {        if (deletenode->next == NULL)        {            pNode pnode = *plisthead;            while (pnode != deletenode)            {                pnode = pnode->next;            }            delete deletenode;            deletenode = NULL;        }    }}void test1(){    pList plist1;    pNode ret = NULL;    InitLinkList(&plist1);    PushBack(&plist1, 1);    PushBack(&plist1, 2);    PushBack(&plist1, 3);    PushBack(&plist1, 4);    Display(plist1);    DeleteNode(&plist1, );    Destroy(&plist1);}int main(){    test1();    system("pause");    return 0;}

【测试】
1、功能测试
(1)从有多个节点的链表的中间删除一个节点。
(2)从有多个节点的链表中删除头节点。
(3)从有多个节点的链表中删除尾节点。
(4)从只有一个节点的链表中删除节点。
2、特殊功能测试
(1)指向链表的头指针为空。
(2)指向链表要删除节点的指针为空。

【存在问题】
1、头指针为何要定义为双指针?
2、不会调用DeleteNode函数(删除节点)。