码迷,mamicode.com
首页 > 其他好文 > 详细

链表中倒数第k个结点

时间:2016-05-12 23:49:13      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:

题目:输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人都习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1, 2, 3, 4, 5, 6。这个链表的倒数第3个结点是值为4的结点。链表结点定义如下:

typedef struct ListNode
{
	int val;
	struct ListNode *p_next;
}NODE, *PNODE;

为了找到倒数第k个结点,很自然的就可以想到先找到链表的尾结点,然后从后往前找1第k个结点。然而从链表结点的结构情况来看,它是一个单链表,所以这种方法直接就out了。

所以我们马上就又想到了,假设链表结点总数为n,那么倒数第k个结点不就是第 n-k+1 个结点喽!既然如此,我们只需先把整个链表遍历一遍,统计出总的结点个数,然后在从头开始遍历,找出第 n-k+1 个结点就ok了。

上边这个方法效率只能说是还行,但因为它需要把链表遍历两次,这样不是做了很多无用功嘛。所以我们要想着优化一下。怎么才能在只遍历一次的情况下,就找到倒数第k个结点呢?

like this:

定义两个指针,第一个指针从链表的头结点开始向后走k-1步,第二个指针不动;从第k步开始,第二个指针也开始从链表的头指针处向后遍历。由于这两个指针的距离始终保持着k-1的距离,所以当第一个指针走到了链表的尾结点时,第二个指针自然的就指向了倒数第k个结点。如图所示,这是一个链表,有两个指针指向它的头结点: 

                                   技术分享

这里再假设我们要查找倒数第3个结点,也就是3这个结点。那么接下来就是让right指针向后移动 3-1 步,变成这样:

                                    技术分享

right现在指向了结点3,接下来,left指针和right指针同时开始右移,直到right指向尾结点,如下:

                                  技术分享

这时Right指向了尾结点,同时的,left也已经指向了倒数第k个结点。

另外,还有几点要注意的是,如果传进来的链表是一个空指针怎么办?传进来的k小于0怎么办?k大于总结点数怎么办?这些情况都需要进行处理。理清了总体思路,接下来就可以开始写代码了:

PNODE find_Kth_to_tail(PNODE head, int k)
{
	PNODE left = NULL;
	PNODE right = NULL;
	int i = 0;

	assert(head);
	
	if (k <= 0)
		return NULL;

	left = right = head;

	for (i = 0; (i < k-1) && (NULL != right->p_next); i++)
	{
		right = right->p_next;;
	}
	if (i != k-1)
		return NULL;
	while (NULL != right->p_next)
	{
		left = left->p_next;
		right = right->p_next;
	}
	
	return left;
}
void distroy(PNODE head)
{
	PNODE tmp = NULL;

	while (NULL != head)
	{
		tmp = head;
		head = head->p_next;
		free(tmp);
	}
}

写完代码一定不要忘记测试哟!

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct ListNode
{
	int val;
	struct ListNode *p_next;
}NODE, *PNODE;


int main()
{
	PNODE p1 = (PNODE)malloc(sizeof(NODE));	
	PNODE p2 = (PNODE)malloc(sizeof(NODE));	
	PNODE p3 = (PNODE)malloc(sizeof(NODE));	
	PNODE p4 = (PNODE)malloc(sizeof(NODE));	
	PNODE ret = NULL;

	p1->val = 1;
	p1->p_next = p2;
	p2->val = 2;
	p2->p_next = p3;
	p3->val = 3;
	p3->p_next = p4;
	p4->val = 4;
	p4->p_next = NULL;

	ret = find_Kth_to_tail(p1, 5);
	if (ret)
		printf("%d\n", ret->val);
	else
		printf("没找到\n");

	distroy(p1);
	return 0;
}

还有一些同类型的题目,比如返回链表的中间结点,判断链表是不是形成了环形结构等,都可以用这种两个指针的思路来实现。

当我们用一个指针遍历链表不能解决问题的时候,可以尝试用两个指针来遍历链表。可以让其中一个指针遍历的速度快些,比如一次让这个指针走两步,或者干脆让它先走若干步。(《剑指offer》)

链表中倒数第k个结点

标签:

原文地址:http://blog.csdn.net/qq_33724710/article/details/51344286

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!