面试100题:13.求单向链表倒数第k个节点

转载并参考July的博客http://topic.csdn.net/u/20101126/10/b4f12a00-6280-492f-b785-cb6835a63dc9.html,万分感谢!


题目

输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第0个结点为链表的尾指针。

分析

因为是单向链表,不能从尾部向头部遍历,所以要找到一种合适的方法遍历到倒数第K个节点。

解一

假设整个链表有n个结点,那么倒数第k个结点是从头结点开始的第n-k-1个结点(从0开始计数)。如果我们能够得到链表中结点的个数n,那我们只要从头结点开始往后走n-k-1步就可以了。如何得到结点数n?这个不难,只需要从头开始遍历链表,每经过一个结点,计数器加一就行了。这种思路的时间复杂度是O(n),但需要遍历链表两次。第一次得到链表中结点个数n,第二次得到从头结点开始的第n-k-1个结点即倒数第k个结点。

/*Title:    13.求单向链表倒数第k个节点:解一
Author:     gocode
Date:       2012-10-15*/

#include <iostream>
using namespace std;

struct ListNode
{
	int m_nKey;
	ListNode* m_pNext;
};

ListNode* Head;
ListNode* pCur;

void AddToList(ListNode* &pCur, unsigned int key)
{
	if(pCur == NULL)
	{
		ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
		newNode->m_nKey = key;
		newNode->m_pNext = NULL;
		pCur = newNode;
		Head = newNode;
	}
	else
	{
		ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
		newNode->m_nKey = key;
		newNode->m_pNext = NULL;
		pCur->m_pNext = newNode;
		pCur = newNode;
	}
}

ListNode* FindKthToTail_Solution1(ListNode* pListHead, unsigned int k)
{
	if(pListHead == NULL)
		return NULL;

	// 计算链表里节点个数
	ListNode *pCur = pListHead;
	unsigned int nNum = 0;
	while(pCur != NULL)
	{
		pCur = pCur->m_pNext;
		nNum ++;
	}
	// 如果链表节点数小于k,则退出
	if(nNum < k)
		return NULL;

	// 倒数第k个节点也是整数第n-k个节点
	// 找到它
	pCur = pListHead;
	for(unsigned int i = 0; i < nNum - k; ++ i)
		pCur = pCur->m_pNext;
	return pCur;
}

void DisplayList(ListNode* pHead)
{
	ListNode* p = pHead;
	if(p == NULL)
		cout<<"The LinkedList is empty."<<endl;
	else
	{
		while(p != NULL)
		{
			cout<<p->m_nKey<<" ";
			p = p->m_pNext;
		}
	}
	cout<<endl;
}

void main()
{
	Head = pCur = NULL;

	AddToList(pCur, 1);
	AddToList(pCur, 2);
	AddToList(pCur, 3);
	AddToList(pCur, 4);
	AddToList(pCur, 5);
	AddToList(pCur, 6);
	AddToList(pCur, 7);

	DisplayList(Head);

	cout<<"13.求单向链表倒数第k个节点:解一"<<endl;
	cout<<"The Kth from tail is: "<<FindKthToTail_Solution1(Head, 3)->m_nKey<<endl;
	system("pause");
}

解二

设置p1p2两个指针,开始时均指向头指针head,然后p2向后移动k个节点,接着同时移动p1p2节点,当p2指向尾部NULL时,此时p1指向的就是倒数第k个节点。

/*Title:    13.求单向链表倒数第k个节点:解二
Author:     gocode
Date:       2012-10-15*/

#include <iostream>
using namespace std;

struct ListNode
{
	int m_nKey;
	ListNode* m_pNext;
};

ListNode* Head;
ListNode* pCur;

void AddToList(ListNode* &pCur, unsigned int key)
{
	if(pCur == NULL)
	{
		ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
		newNode->m_nKey = key;
		newNode->m_pNext = NULL;
		pCur = newNode;
		Head = newNode;
	}
	else
	{
		ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
		newNode->m_nKey = key;
		newNode->m_pNext = NULL;
		pCur->m_pNext = newNode;
		pCur = newNode;
	}
}

ListNode* FindKthToTail_Solution2(ListNode* pListHead, unsigned int k)
{
	if(pListHead == NULL)
		return NULL;

	ListNode *p1, *p2 = pListHead;
	unsigned int nNum = 1;
	while(p2 != NULL)
	{
		p2 = p2->m_pNext;
		nNum ++;
		if(nNum == k) // 结束条件
			break;
	}
	// if the number of nodes in the list is less than k
	// do nothing
	if(nNum < k)
		return NULL;
	// 现在p1和p2之间的距离保持为k个节点
	// 同时移动它们,直到p2指向NULL
	p1 = pListHead;
	while(p2->m_pNext != NULL)
	{
		p1 = p1->m_pNext;
		p2 = p2->m_pNext;
	}

	return p1;
}

void DisplayList(ListNode* pHead)
{
	ListNode* p = pHead;
	if(p == NULL)
		cout<<"The LinkedList is empty."<<endl;
	else
	{
		while(p != NULL)
		{
			cout<<p->m_nKey<<" ";
			p = p->m_pNext;
		}
	}
	cout<<endl;
}

void main()
{
	Head = pCur = NULL;

	AddToList(pCur, 1);
	AddToList(pCur, 2);
	AddToList(pCur, 3);
	AddToList(pCur, 4);
	AddToList(pCur, 5);
	AddToList(pCur, 6);
	AddToList(pCur, 7);

	DisplayList(Head);

	cout<<"13.求单向链表倒数第k个节点:解二"<<endl;
	cout<<"The Kth from tail is: "<<FindKthToTail_Solution2(Head, 3)->m_nKey<<endl;
	system("pause");
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【1】项目代码完整且功能都验证ok,确保稳定可靠运行后才上传。欢迎下载使用!在使用过程中,如有问或建议,请及时私信沟通,帮助解答。 【2】项目主要针对各个计算机相关专业,包括计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师或企业员工使用。 【3】项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 【4】如果基础还行,或热爱钻研,可基于此项目进行二次开发,DIY其他不同功能,欢迎交流学习。 【注意】 项目下载解压后,项目名字和项目路径不要用中文,否则可能会出现解析不了的错误,建议解压重命名为英文名字后再运行!有问私信沟通,祝顺利! 基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值