题目:写一个函数,完成删除单向链表里倒数第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个节点