代码改变世界

面试题14:用O(1)时间删除链表结点

2016-03-31 22:17  Keiven_LY  阅读(1348)  评论(0编辑  收藏  举报

题目描述:

给定一个单向链表的头指针和一个结点指针,实现一个函数在o(1)时间删除该结点。

基本思路:

通常我们删除某个节点都是从头开始遍历到需要删除节点的前一个节点。然后使得该节点的next指向删除节点的next即可,这样看来删除一个节点的复杂度为O(n)。然而我们其实遍历的目的只是想获取想要删除节点的前一个节点。

那么我们可以这样考虑:我们把要删除节点下一个节点的值赋值到当前节点,然后将当前节点的下一个节点删除即可。

比如:

一个链表3->2->5->7->9,给定的指针指向5也就是说要删除5这个结点。我们将结点5下一个结点的值赋值给需要删除的节点即:3->2->7->7->9,然后再p->next=p->next->next即可删除。

但是,如果要删除的结点是尾结点,它没有下一个结点,怎么办?我们可仍然从链表的头结点开始,顺序遍历到该结点的前一个结点,并完成删除操作。

最后还需注意,如果链表中只有一个结点,而我们又要删除链表的头结点(也是尾结点),此时我们在删除结点后,还需要把链表的头结点设置为NULL。

功能函数:

/*     获取要删除的结点    */
Node *getNodeToBeDeleted(Node *head)
{
    int count;
    Node *p = head;
    cout << "请输入你要删除的结点: ";
    cin >> count;
    int i = 0;
    while( i <count)
    {
        p = p->next;
        i++;
    }
    return p;        
}

/*     o(1)时间删除链表结点    */
void deleteNode(Node *head, Node *pToBeDeleted)
{
    if(head == NULL || pToBeDeleted == NULL)
        return;

    //要删除的结点不是尾结点
    if(pToBeDeleted ->next != NULL)
    {
        Node *pnext = pToBeDeleted->next;
        pToBeDeleted->data = pnext->data;
        pToBeDeleted->next = pnext->next;
        free(pnext);
        pnext = NULL;
    }
    //链表只有一个结点,删除头结点(也是尾结点)
    else if(head == pToBeDeleted)
    {
        free(pToBeDeleted);
        pToBeDeleted = NULL;
        head->next = NULL;
    }
    //链表中有多个结点,要删除的结点是尾结点
    else
    {
        Node *pNode = head;
        while(pNode->next != pToBeDeleted)
        {
            pNode = pNode->next;
        }
        pNode->next = NULL;
        free(pToBeDeleted);
        pToBeDeleted = NULL;
    }
}

完整可执行程序:

#include<iostream>
#include <stack>
#include<stdlib.h> 
#include<time.h>

using namespace std;

typedef struct node
{
    int data;
    struct node *next;
}Node;

/*     创建含有n个结点的单链表    */
Node *CreateListHead(int n) 
{
    Node *head;
    head=(Node *)malloc(sizeof(Node)); /*创建头结点*/
    Node *q = head;

    /* 初始化随机数种子 */
    srand(time(0));  //srand函数在stdlib.h头文件中,time函数在time.h头文件中

    for(int i=0; i < n; i++)
    {
        Node *p = (Node *)malloc(sizeof(Node));
        p->data = rand()%100+1;  //随机生成100以内的数字 
        p->next = q->next;
        q->next = p;
        q = p;
    }
    q->next = NULL;

    return head;
}

/****打印单链表******/
void print(Node *head)
{
    Node *p;
    if(head->next==NULL)
    {
        cout << "The LinkList is Empty !" <<endl;
        return;
    }
    p=head->next;
    while(p!=NULL)
    {
        cout << p->data << " " ;
        p=p->next;
    }
}
/*     获取要删除的结点    */
Node *getNodeToBeDeleted(Node *head)
{
    int count;
    Node *p = head;
    cout << "请输入你要删除的结点: ";
    cin >> count;
    int i = 0;
    while( i <count)
    {
        p = p->next;
        i++;
    }
    return p;        
}

/*     o(1)时间删除链表结点    */
void deleteNode(Node *head, Node *pToBeDeleted)
{
    if(head == NULL || pToBeDeleted == NULL)
        return;

    //要删除的结点不是尾结点
    if(pToBeDeleted ->next != NULL)
    {
        Node *pnext = pToBeDeleted->next;
        pToBeDeleted->data = pnext->data;
        pToBeDeleted->next = pnext->next;
        free(pnext);
        pnext = NULL;
    }
    //链表只有一个结点,删除头结点(也是尾结点)
    else if(head == pToBeDeleted)
    {
        free(pToBeDeleted);
        pToBeDeleted = NULL;
        head->next = NULL;
    }
    //链表中有多个结点,要删除的结点是尾结点
    else
    {
        Node *pNode = head;
        while(pNode->next != pToBeDeleted)
        {
            pNode = pNode->next;
        }
        pNode->next = NULL;
        free(pToBeDeleted);
        pToBeDeleted = NULL;
    }
}
int main()
{
    Node *SingleLinkList = NULL;
    int length;

    cout << "Please input the length of LinkList: ";
    cin >> length;
    SingleLinkList = CreateListHead(length);
    cout << "The new created LinkList as below: " ;
    print(SingleLinkList);
    cout << endl;

    Node *toBedeletedNode;
    toBedeletedNode = getNodeToBeDeleted (SingleLinkList);
    cout << "删除了你要删除的结点后的链表为: ";    
    deleteNode(SingleLinkList,toBedeletedNode);
    print(SingleLinkList);
    cout << endl;
    system("pause");
    return 0;
}

运行结果: