题目:输入一个链表,输出该链表中倒数第 k 个节点。为了符合大多数人的习惯,本题从 1 开始计数,即链表的尾节点是倒数第一个节点。ios
为了获得倒数第 k 个节点,很天然的想法就是:首先走到链表的尾端回溯 k 步。然而,单向链表的节点只有从前向后的指针,没有从后往前的指针,这种思路是行不通的。spa
既然不能从尾节点遍历单链表,咱们仍是把思路回到单链表的头结点。假设整个链表有 n 个节点,那么倒数第 k 个节点就是,从头开始的第 n - k + 1 个节点。如何得知整个链表的节点数目? 只要从头遍历链表,每通过一个节点,计数器加 1 便可。也就是说,这种方法须要遍历两次单链表。第一次,统计链表中的节点数目; 第二次,就可以找到倒数第 k 个节点。指针
3)若是要求只能遍历一次单链表。咱们能够定义两个指针。第一个指针从链表的头指针开始遍历向前走 k - 1 步,第二个指针保持不动;从第 k 步开始,第二个指针也从单链表的头指针开始遍历,两个指针始终保持 k - 1,当第一个指针走到(走在前面的指针)链表的尾节点时,第二个指针(走在后面的)正好指向的是链表的倒数第 k 个节点。【使用的是快慢指针】内存
写代码时存在的三个潜在的风险:ci
1)输入的头指针为 NULL的时候,因为代码会试图访问空指针指向的内存,程序会崩溃io
2)当输入的头指针所指向的单链表的结点个数不足 k 个的时候。因为在for 循环中,程序会向前中 k - 1 步,程序就会崩溃。stream
3)输入的参数为 k 为 0,因为k 是一个无符号整数,那么在 for 循环中 k - 1 将获得的不是 -1,所以 for 循环的次数远远超乎咱们的想象,一样会形成程序的崩溃。List
//输入一个链表,输出链表的倒数第 k 个节点[使用两个指针:快慢指针]
#include<iostream>
using namespace std;循环
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}ListNode, *LinkList;遍历
LinkList CreateLinkList(LinkList L)
{
if(L == NULL)
{
L = new LNode();
L->next = NULL;
}
return L;
}
void InsertLinkList(LinkList L, ElemType value)
{
if(L == NULL)
return;
LNode *p, *s;
s = L;
p = new LNode();
p->data = value;
p->next = s->next;
s->next = p;
}
LNode* FindKthToTail(LinkList L, int k)
{
if(L == NULL || k == 0) //链表为空或者输入的 k 不合法时,返回NULL
return NULL;
LNode *pNode = L;
LNode *pBegin = NULL;
for(int i = 0; i < k - 1; i++)
{
if(pNode->next != NULL) //若是第一个指针指向的下一个元素不为空时,则向后移动第一个指针
pNode = pNode->next;
else
return NULL; //不然,返回NULL,此时说明,单链表的节点数目不足 k 个
}
pBegin = L;
while(pNode->next != NULL) //移动第一个指针,直至第一个指针指向最后一个节点
{
pNode = pNode->next;
pBegin = pBegin->next; //移动第二个指针
}
return pBegin; //返回第二个指针,其指向的正是倒数第 k 个节点
}
int main()
{
LNode *L, *result;
L = NULL;
result = NULL;
L = CreateLinkList(L);
int value;
while(cin >> value)
{
InsertLinkList(L, value);
}
result = FindKthToTail( L, 1);
cout << result->data << endl;
system("pause");
return 0;
}
相关题目:
1)求链表的中间节点:若是链表的节点总数为奇数,返回中间节点;若是节点的总数为偶数,则返回中间两个节点中的任意一个。【解决该问题,也能够定义两个指针,同时从链表的头结点开始出发,第一个指针一次走一步,第二个指针一次走两步。当第二个指针走到链表的末尾的时候,走得慢的指针正好走到链表的中间。】
2)判断一个单链表是否造成了一个环形结构【一样的定义两个指针,同时从链表的头结点开始出发,一个指针一次走一步,另外一个指针一次走两步。若是走的快的指针追上了走得慢的指针,则说明链表是环形的。若是走得快的指针走到了链表的末尾都没有追上走得慢的指针,则说明链表不是环形的。】