剑指offer:链表中倒数第k个节点

题目: 输入一个链表,输出该链表中倒数第k个结点。

思路1:为了得到倒数第k个结点,很自然的想法是先走到链表的尾端,再从尾端回溯k步。可是我们从链表结点的定义可以看出本题中的链表是单向链表,单向链表的结点只有从前往后的指针而没有从后往前的指针,因此这种思路行不通。

思路2:定义两个指针。快指针从链表的第一个节点开始遍历向前走k-1。慢指针保持不动;从第k步开始,慢指针也开始从链表的第一个节点开始遍历。由于两个指针的距离保持在k-1,当快指针到达链表的尾指结点时,慢指针正好是倒数第k个结点。

图解

                

小问题

1、输入pHead指针为NULL。由于代码会试图访问空指针指向的内存,程序会崩溃。

2、输入以pHead为头结点的链表的结点总数少于k。由于在for循环中会在链表向前走k-1步,仍然会由于空指针造成崩溃。

3、输入的参数k为0或负数,同样会造成程序的崩溃。

这里牵扯到代码的鲁棒性,即健壮性。指程序能够判断输入是否合乎规范要求,并对不符合要求的输入予以合理的处理。

代码

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

typedef int ELEM_TYPE;

typedef  struct Node
{
	ELEM_TYPE mdata;
	struct Node* pnext;
}Node, *Link;

void Init(Link phead)//初始化单链表
{
	assert(phead != NULL);
	if (phead == NULL)
	{
		return;
	}
	phead->pnext = NULL;//将头结点的指针域置为空
}

static Link CreatNode()//创建节点
{
	struct Node *pnewnode = (struct Node*)malloc(sizeof(struct Node));
	assert(pnewnode != NULL);
	pnewnode->pnext = NULL;
	return pnewnode;
}

bool InsertHead(Link phead, ELEM_TYPE val)//头插法
{
	if (phead == NULL)
	{
		return false;
	}
	struct Node* pnewnode = CreatNode();
	pnewnode->mdata = val;
	pnewnode->pnext = phead->pnext;
	phead->pnext = pnewnode;
	return true;
}

void Print(Link phead)//打印链表
{
	if (phead == NULL)
	{
		return;
	}
	struct Node* pCur = phead->pnext;
	while (pCur != NULL)
	{
		printf("%d ", pCur->mdata);
		pCur = pCur->pnext;
	}
	printf("\n");
}

Node * Find_k(Link pHead, int k) //寻找倒数第k个节点
{
	if (k <= 0)
	{
		return NULL;
	}

	Node* pfast = pHead->pnext;
	Node* pslow = pfast;

	for (int i = 0; i < k - 1; i++)
	{
		if (pfast->pnext!= NULL)
		{
			pfast = pfast->pnext;
		}
		else
		{
			return NULL;
		}
	}

	while (pfast->pnext != NULL)
	{
		pfast = pfast->pnext;
		pslow = pslow->pnext;
	}

	return pslow;
}


int main()
{
	Node head;//定义一个头结点
	Init(&head);//初始化单链表

	for (int i = 0; i < 6; i++)
	{
		InsertHead(&head, 100 + i);//头插法
	}

	Print(&head);
	Node *t= Find_k(&head, 3);
	printf("%d\n", t->mdata);

	return 0;
}

运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值