您的位置:首页 > 职场人生

剑指Offer:面试题15 链表中倒数第k个结点

2014-09-08 19:39 405 查看
/*
链表中倒数第k个节点:
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是
倒数第一个节点。例如一个链表有6个节点,从头节点开始它们的值依次是1,2,3,4,5,6。这个链表的倒数第三个
节点是值为4的结点。

输入:
输入可能包含多个测试样例,输入以EOF结束。
对于每个测试案例,输入的第一行为两个整数n和k(0<=n<=1000, 0<=k<=1000):n代表将要输入的链表元素的个数,k代表要查询倒数第几个的元素。
输入的第二行包括n个数t(1<=t<=1000000):代表链表中的元素。
输出:
对应每个测试案例,
若有结果,输出相应的查找结果。否则,输出NULL。
样例输入:
5 2
1 2 3 4 5
1 0
5
样例输出:
4
NULL

要考虑k的取值:
k = 0,返回NULL
加入k > n,此时应该也返回NULL
0< k <= n,返回倒数第k个节点
*/

/*
关键:
1 若开始p1 = p2 = 头节点指针(头节点算第一个节点),那么p1走k-1(因为第一步已经走了)步之后,大家一起走就可以(推荐这种)
  若p1 = p2 = NULL,那么p1走k步后,两者一起走
*/

#include <stdio.h>
const int INF = 1000000000;
const int MAXSIZE = 1001;

typedef struct Node
{
int _iVal;
struct Node* _next;
}Node;

void buildList_headInsert(Node** pHead,int n,int* pArr)
{
if(pHead == NULL || n < 0 || pArr == NULL)
{
return;
}
//头插法的玄机:每次使新插入的节点指向刚刚的头结点,然后使自己成为头节点
//Node* pRearNode = *pHead;
//pRearNode->_next = 
Node* pNode,*pFrontNode,*pRearNode;//因为刚开始的头结点最终会在头插法下变成最后的结点
for(int i = 0 ; i < n ;i++)
{
pNode = new Node();
pNode->_iVal = pArr[i];
if(i)
{
pNode->_next = pFrontNode;//指向刚才的上一个节点
pFrontNode = pNode;
}
else
{
pNode->_next = NULL;//设置指向为空
pFrontNode = pRearNode = pNode;
}
}
pRearNode->_next = NULL;//设置尾节点的指向为空
*pHead = pFrontNode;
}

void buildList(Node** pHead,int n,int* pArr)//采用尾插法
{
if(pHead == NULL || n < 0 || pArr == NULL)
{
return;
}
Node* pCurNode;
for(int i = 0 ; i < n ; i++)
{
if(i)
{
Node* pNode = new Node();
pNode->_iVal = pArr[i];
pNode->_next = NULL;
pCurNode->_next = pNode;
pCurNode = pNode;
}
else//建立头结点
{
(*pHead)->_iVal = pArr[i];
(*pHead)->_next = NULL;
pCurNode = (*pHead);
}

}
}

void freeList(Node** pHead)//删除链表
{
Node* pNode;
while((*pHead) != NULL)
{
pNode = *pHead;
*pHead = (*pHead)->_next;
delete pNode;
pNode = NULL;
}
}

//倒数第k个节点,1,2,3,4,5,6,k = 3,可以另p1 = 1,p2 = 1,p1走到3处(走了k-1次),然后p2 与 p1 一起走剩下的n-k+1次,则p2一共走:
int reciprocalKNode(int n,int k,int* pArr)//
{
if(k <= 0 || k > n)//鲁棒性
{
return INF;
}
Node* head  = new Node();
Node** pHead = &head;//这样做的原因是:好让头指针能够修改,若直接传递Node*作为头节点,则修改后会作为局部变量最后消失
buildList_headInsert(pHead,n,pArr);//建立链表
Node* p1,*p2;
p1 = p2 = *pHead;
//p1先走k-1步之后,p1与p2再一起走
int iCnt = 0;
while(p1->_next != NULL)
{
if(iCnt < k - 1)//k-1 - 1 + 1 = 等于走了k-1步
{
iCnt++;
}
else//如果iCnt 已经大于k-1,表名p1已经走完
{
p2 = p2->_next;
}
p1 = p1 ->_next;
}
int iRes = p2->_iVal;
freeList(pHead);
return iRes;
}

void process()
{
int n,k;
while(EOF != scanf("%d %d",&n,&k))
{
int iArr[MAXSIZE];
for(int i = 0 ; i < n ; i++)
{
scanf("%d",&iArr[i]);
}
int iRes = reciprocalKNode(n,k,iArr);
if(iRes != INF)
{
printf("%d\n",iRes);
}
else
{
printf("NULL\n");
}
}
}

int main(int argc,char* argv[])
{
process();
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: