链表倒数第k个结点、链表中间节点、链表是否有环

题目描述:

输入一个链表,输出该链表中倒数第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:如何求得带环链表的环入口?

上述两个指针相遇点到环入口的距离恰好等于链表起始点到环入口的距离。可以使用两个指针分别从这两个位置出发,一次走一步,相遇时即为环的入口位置。


链表倒数第k个结点、链表中间节点、链表是否有环

时间: 2024-11-05 13:39:56

链表倒数第k个结点、链表中间节点、链表是否有环的相关文章

剑指offer (15) 链表倒数第K个结点

题目: 输入一个链表,输出该链表中倒数第k个结点 (注意:我们将链表最末一个结点记为 倒数第1个结点,也就是k从1开始计数) 解题分析: 方法一:遍历链表两次,第一次统计链表结点个数,第二次遍历就可以找到倒数第K个结点 方法二:遍历链表一次 我们使用两个指针,第一个指针从链表的头指针开始遍历向前走k-1步,第二个指针一直指向链表开头并保持不动 从第k步开始,两个指针同时向前走,这时 两个指针之间的距离一直是k-1 当第一个指针到达链表尾结点时,第二个指针指向链表倒数第k个结点 1 ListNod

算法题:求链表倒数第K个结点

说明:本文仅供学习交流,转载请标明出处,欢迎转载!  题目:给出一个单链表,返回倒数第K个结点,最后一个结点为倒数第1个. <剑指offer>上面给的解法是设置两个指针,这里记为p1.p2,先让p2走(k-1)步,然后p1.p2同时走,当p2走到最后一个结点时,p1所指向的结点就是倒数第k个结点. 我觉得按照这样的逻辑写代码反而更容易出错,因为我们需要把我两件重要的问题:(1).p2先走(k-1)步:(2)循环结束的条件是p2到达最后一个结点,即p2->next==NULL.显然这样不太

剑指offer-打印链表倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点. 看到这个题目,我们很容易想到一种做法,遍历两次链表,一次得到链表长度,另外一次得到倒数第k个结点. 不过要注意的是边界值的测试 链表为空 k大于链表长度 于是我的做法如下: public static ListNode FindKthToTail(ListNode head,int k) { if(head==null) { return null; } ListNode prehead=new ListNode(0); prehead.next=he

求单链表倒数第k个结点

题目: 输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第0个结点为链表的尾指针. 分析: 设置两个指针p1,p2.首先p1和p2都指向head.然后p2向前走k步,这样p1和p2之间就间隔k个节点,然后p1和p2同.... #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; struct ListNode{ char data; ListNode* next;

《剑指offer》---输出链表倒数第k个结点

本文算法使用python3实现 1. 问题1 1.1 题目描述: ??输入一个链表,输出该链表中倒数第k个结点. ??时间限制:1s:空间限制:32768K 1.2 思路描述: ??方法一:当链表长度为 $ n $ 时,输出链表倒数第 $ k $ 个节点,即输出链表正数第 $ n-k $ 个节点.需先遍历链表计算链表长度,再从头至尾查找第 $ n-k $ 个节点,并输出. ??方法二:可以用两个指针同时指向链表头结点,第一个指针先遍历到第k个结点,此时第二个指针指向头结点,两个指针的距离为k-1

二种方法查找链表倒数第K个结点

1 #include <stdio.h> 2 #include <stdlib.h> 3 /* 4 题目:查找链表中倒数第K个结点,K>0 5 思路1:考虑 链表为空,K<链表长度,k>大于链表长度 这三种情况 6 1.链表为空,即:不存在倒数第K个结点 7 2.k>len.即:不存在倒数第K个结点. 8 3.k<len.倒数第二个结点为正数第len-1(len-2+1)个结点,倒数第三个结点为正数第len-2(len-3+1)个结点,那么倒数第K个结

剑指Offer13 链表倒数第K个结点

1 /************************************************************************* 2 > File Name: 13_KthNodeToTail.cpp 3 > Author: Juntaran 4 > Mail: [email protected] 5 > Created Time: 2016年08月30日 星期二 15时32分25秒 6 ***********************************

链表中倒数第K个结点

题目:输入一个链表,输出改链表倒数第K个结点. 分析:常规方法可能就是,先遍历一遍链表,找到链表长度length,那么我们只需要第二次遍历length-k+1个结点就可以找到倒数第k个结点. 比较好的方法是采用两个指针,让一个指针先走K-1步,后面的指针再跟上.这样只需要遍历一遍. 注意:1.提高容错性,在链表为空 或者k为空.还有k大于链表长度. 2.链表下一个结点,我们采用p=p->next.指针指向的数组我们采用p++; typedef int Type; struct listNode{

输出单链表中倒数第k个结点(Java版)

题目:输入带头结点的单链表L,输出该单链表中倒数第k个结点.单链表的倒数第0个结点为该单链表的尾指针.要求只能遍历一次单链表. 解题思路: 如果不要求只能遍历一次单链表,我们可以先遍历一次单链表,求出它的结点的总个数n(包括头结点),所以单链表的结点是从倒数第n-1个到倒数第0个,然后再遍历一次单链表,遍历时访问的第n-k-1个结点就是该单链表中倒数第k个结点.现在要求只能遍历一次单链表,可以设两个指针p和q,最开始时它们都指向头结点,然后p向后移动k位,最后p,q同时向后移动直到p为最后一个结