-
题目描述:
-
输入一个链表,输出该链表中倒数第k个结点。
(hint: 请务必使用链表。)
-
输入:
-
输入可能包含多个测试样例,输入以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
代码:
1.设置快慢指针即可,快指针先走k-1步,接着两个指针同时向后走,到快指针到达末尾时,满指针指向的元素即倒数第k个元素。
2.需要注意代码的鲁棒性。三种情况,k<=0,链表为空,k>链表长度.
/************************************
链表倒数第k个结点
by Rowandjj
2014/7/31
************************************/
#include<stdio.h>
#include<stdlib.h>
typedef struct _NODE_
{
int data;
struct _NODE_ *next;
}Node,*pNode;
pNode findNode(pNode list,int k)
{
if(list == NULL || k <= 0)
{
return NULL;
}
pNode p = list,q = list;
for(int i = 0; i < k-1; i++)
{
if(p->next == NULL)
{
return NULL;
}else
{
p = p->next;
}
}
while(p->next != NULL)
{
p = p->next;
q = q->next;
}
return q;
}
int main()
{
int n,k,i,data;
while(scanf("%d",&n) != EOF)
{
scanf("%d",&k);
if(n <= 0)
{
printf("NULL\n");
continue;
}
scanf("%d",&data);
pNode list = (pNode)malloc(sizeof(Node));
if(!list)
{
exit(-1);
}
list->data = data;
list->next = NULL;
pNode pTemp = list;
for(i = 0; i < n-1; i++)
{
scanf("%d",&data);
pNode pNew = (pNode)malloc(sizeof(Node));
if(!pNew)
{
exit(-1);
}
pNew->data = data;
pNew->next = NULL;
pTemp->next = pNew;
pTemp = pNew;
}
pNode pR = findNode(list,k);
if(pR != NULL)
{
printf("%d\n",pR->data);
}else
{
printf("NULL\n");
}
}
return 0;
}
类似题目:
1.求链表中间节点,如果链表结点数为奇数,返回中间节点,否则返回中间两个结点的任意一个。
思路:定义两个指针,同时从链表头部出发,一个指针一次走一步,一个指针一次走两步,当快指针走到末尾时,慢指针正好在链表中间。
代码:
/*
求链表中间结点
by Rowandjj
2014/7/31
*/
#include<stdio.h>
#include<stdlib.h>
typedef struct _NODE_
{
int data;
struct _NODE_ *next;
}Node,*list;
Node* findMiddleNode(list l)
{
if(l == NULL)
{
return NULL;
}
Node *p = l;
Node *q = l;
while(p->next != NULL)
{
p = p->next;
if(p->next != NULL)
{
p = p->next;
}else
{
break;
}
q = q->next;
}
return q;
}
int main()
{
int m,data;
while(scanf("%d",&m) != EOF)
{
if(m <= 0)
{
printf("NULL\n");
continue;
}
scanf("%d",&data);
list l = (Node*)malloc(sizeof(Node));
if(!l)
{
exit(-1);
}
l->data = data;
l->next = NULL;
Node *pTemp = l;
for(int i = 0; i < m-1; i++)
{
scanf("%d",&data);
Node *pNew = (Node*)malloc(sizeof(Node));
if(!pNew)
{
exit(-1);
}
pNew->data = data;
pNew->next = NULL;
pTemp->next = pNew;
pTemp = pNew;
}
Node * p = findMiddleNode(l);
if(p != NULL)
{
printf("%d\n",p->data);
}
else
{
printf("NULL\n");
}
}
return 0;
}
2.判断链表是否有环
思路:同样是设置快慢指针,快指针一次走两步,慢指针一次走一步,如果快指针追上慢指针,说明有环,如果当快指针指向null时,仍然没有追上那么无环。
代码:
typedef struct _NODE_
{
int data;
struct _NODE_ *next;
}Node,*List,*pNode;
//设置快慢指针,快指针一次走两步,满指针一次走一步,
//若链表有环,则返回两个指针相遇的结点,否则返回NULL
pNode func(List list)
{
if(list == NULL)
{
return NULL;
}
pNode p = list,q = list;
while(p->next != NULL)
{
//快指针走两步
p = p->next;
if(p->next != NULL)
{
p = p->next;
}else
{
return NULL;
}
//慢指针走一步
q = q->next;
//若相遇
if(p == q)
{
return p;
}
}
return NULL;
}
//判断单链表是否有环,如果有,则返回true,否则返回false
bool isCircleList(List list)
{
return func(list)!=NULL;
}
问题1:如何求带环链表中环长?
通过上面代码可求出第一次相遇的结点,从该点出发,再次相遇时经过的结点数即为环长.
问题2:如何求得带环链表的环入口?
上述两个指针相遇点到环入口的距离恰好等于链表起始点到环入口的距离。可以使用两个指针分别从这两个位置出发,一次走一步,相遇时即为环的入口位置。