代码的鲁棒性:链表的倒数第 k 个节点

题目:输入一个链表,输出该链表中倒数第 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)判断一个单链表是否造成了一个环形结构【一样的定义两个指针,同时从链表的头结点开始出发,一个指针一次走一步,另外一个指针一次走两步。若是走的快的指针追上了走得慢的指针,则说明链表是环形的。若是走得快的指针走到了链表的末尾都没有追上走得慢的指针,则说明链表不是环形的。】

相关文章
相关标签/搜索