删除单向链表里倒数第n个节点

题目:写一个函数,完成删除单向链表里倒数第n个节点的功能,并返回这个被删除的节点指针(第一个节点为表头,不考虑删除它。)

struct SNode
{
    int value;
    SNode *next;
};
SNode rdel(SNode *head, int n);

 

1.假设题目改成leetcode上原题:

给定一个链表,删除链表中倒数第n个节点,返回链表的头节点。

样例 
给出链表1->2->3->4->5->null和 n = 2.

删除倒数第二个节点之后,这个链表将变成1->2->3->5->null.

1)先不考虑n是否大于链表长度

思路:

定义两个指针,刚开始这两个指针的next指向头结点,然后先让一个指针先走n步,接着两个指针同时遍历链表,当第一个指针到达链表尾部的时候,第二个指针指向的就是要删除的倒数第n+1个结点。 

ListNode *rdel(ListNode* head, int n)
{
    ListNode l(0);
    ListNode *pre = &l;
    pre->next = head;
    ListNode *p = pre;
    ListNode *q = pre;
    
    for(int i = 0; i < n; i++)
    {
        p = p->next;
    }
    while(p->next != NULL)
    {
        p = p->next;
        q = q->next;
    }
    
    ListNode *k = q->next;//k是要删除的那个节点
    if(k == head)
    {
        head = head->next;
        return head;
    }
    q->next = k->next;    
    return head;

}

2)考虑n的各种可能情况时

思路:

定义两个指针,刚开始分别指向头结点,然后先让一个指针先走n-1步,接着两个指针同时遍历链表,当第一个指针到达链表尾部的时候,第二个指针指向的就是要删除的倒数第n个结点。 
编程需要注意的是:

输入的链表为空,或输入的n不合法;
输入的n大于链表的长度;
需要保存需要删除的那个结点的上一个结点。
删除的那个结点是头结点。

ListNode* removeNthFromEnd(ListNode* pHead, int n)
{
    ListNode* pFast = pHead;
    ListNode* pLow = pHead;
    ListNode* pPre = NULL;
    
    if (pHead == NULL || n <=0)
    {
        return NULL;//输入的链表为空或输入的n不合法
    }
    
    for (int i = 0; i < n-1; i++)
    {
        if(pFast->next != NULL)
        {
            pFast = pFast->next;
        }
        else
        {
            return NULL;//输入的n大于链表的长度
        }
    }
        
    while(pFast->next != NULL)
    {
        pFast = pFast->next;
        pPre = pLow;//需要保存需要删除的节点的上一个节点
        pLow = pLow->next;
    }
    //此时pLow就是需要删除的那个节点
    
    if (pLow == pHead)//删除的那个节点是头节点
    {
        pHead = pHead->next;
    }
    else
    {
        pPre->next = pPre->next->next;//删除节点
    }
    return pHead;
}

测试代码:

struct ListNode
{
    ListNode(int x ): val(x), next(NULL){}
    int val;
    ListNode* next;
};

void BianLi(ListNode* pHead)
{
    ListNode* pCur = pHead;
    while(pCur!=NULL)
    {
        cout<<pCur->val<<endl;
        pCur = pCur->next;
    }
}

void main()
{
    ListNode l1(1);
    ListNode l2(2);
    ListNode l3(3);
    ListNode l4(4);
    ListNode l5(5);
    ListNode l6(6);
    l1.next = &l2;
    l2.next = &l3;
    l3.next = &l4;
    l4.next = &l5;
    l5.next = &l6;
    l6.next = NULL;
    ListNode* pHead = &l1;

    BianLi(pHead);
    pHead = removeNthFromEnd(pHead, 2);
    cout<<"++++++++++++++++"<<endl;
    BianLi(pHead);
}

总结:如果先让一个指针先走n步,当第一个指针到达链表尾部的时候,第二个指针指向的就是要删除的倒数第n+1个结点。 

            而若先让一个指针先走n-1步,当第一个指针到达链表尾部的时候,第二个指针指向的就是要删除的倒数第n个结点

 

           为了程序的健壮性还需考虑:

           1)输入的链表为空,或输入的n不合法;
           2)输入的n大于链表的长度;
           3)需要保存需要删除的那个结点的上一个结点。
           4)删除的那个结点是头结点。

参考:https://blog.csdn.net/u013108511/article/details/80404476 C++链表操作1:删除倒数第n个节点

           https://blog.csdn.net/zwhlxl/article/details/47104535 【面试题】删除链表中倒数第n个节点

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值