查找单链表中的倒数第m个结点

例4,设计一个算法求出单链表的倒数第m个结点,要求不得求出链表长度,不得对链表进行逆转,如果找到该结点就返回它的地址,否则就返回NULL。

【分析】该题目要求求出单链表的倒数第m个结点,但又不能逆转单链表。

我们知道,获取单链表顺数第i个结点的方式是:设置指针p=head,从头指针开始循环执行p=p->next,一步一步往后移,直到第i个结点为止。

这里我们变动一下,再增加一个指针q,使指针q也沿着链表移动,并且比指针p落后m-1步,当p到达链表尾部时,q刚好指向倒数第m个结点。

具体实现如下:

//实现文件,find_M.cpp

#include <iostream>
#include "LinkList.h"
using namespace std;

ListNode<int>* searchNodeM(LinkList<int> *link,int m)
{
	ListNode<int> *p = link->getNode(1); //p初始化为链表的第一个结点
	if (p != NULL && m > 0)
	{
		for (int i=1;i<m;i++)
		{
			p = p->getNext();
			if (p == NULL)
			{
				cout<<"该链表没有倒数第m个结点"<<endl;
				return NULL;
			}
		}
	}

	ListNode<int> *q = link->getNode(1); //设置指针q,让它位于p之后
	while(p->getNext() != NULL) //同时移动两个指针,直到p到达表尾
	{
		p=p->getNext();
		q=q->getNext();
	}
	return q;

}

void main()
{
	LinkList<int> *head = new LinkList<int>();
	int m,i;
	for (i=1;i<=10;i++)
	{
		head->insertNode(i*3); //数列为3,6,9,12,15,18,21,24,27,30
	}
	cout<<"输入m的值为: "<<endl;
	cin>>m;
	ListNode<int> *p = searchNodeM(head,m);
	for (i=1;i<=10;i++)
	{
		cout<<head->getNodeData(i)<<" ";
	}
	cout<<endl;
	cout<<"倒数第"<<m<<"个结点: "<<p->getData()<<endl;

}

//头文件,LinkList.h

#include <iostream>

//链表结构
template<typename DataType> class ListNode;
template<typename DataType> class LinkList
{
	public:
		LinkList()
		{
			head = new ListNode<DataType>();
		}

		LinkList(ListNode<DataType> *firstNode)
		{
			head = firstNode;
		}

		//析构函数
		~LinkList(){
			delete head;
		}

		//在第i个节点后插入节点
		bool insertNode(int index,DataType newData);
		//在表尾插入新节点
		bool insertNode(DataType newData);
		//删除节点
		bool removeNode(ListNode<DataType> *q);
		//查找指定值的节点,并返回地址
		ListNode<DataType>* findNode(DataType value);
		//清空链表
		void cleanLink();
		//获取第i个结点中的数据
		DataType getNodeData(const int index);
		//获取链表长度
		int getLength();
		//查找链表的第i个元素
		ListNode<DataType>* getNode(int i);
	private:
		ListNode<DataType> *head; //头结点

};

//定义链表结点
template <typename DataType> class ListNode
{
	public:
		ListNode(){
			next = NULL;
		}
		ListNode(const DataType item,ListNode<DataType> *nodeNext = NULL)
		{
			data = item;
			next = nodeNext;
		}
		~ListNode()
		{
			next = NULL;
		}
		//获取结点内的数据
		DataType getData()
		{
			return data;
		}
		//获取指针域
		ListNode* getNext()
		{
			return next;
		}

	private:
		friend class LinkList<DataType>; //将LinkList设为友元类,
		                                 // 以方便访问node的数据成员和方法
		ListNode<DataType> *next; //指向下一个结点的指针
		DataType data;  //节点中的数据

};

//在链表的第i个结点后插入新结点
template<typename DataType> bool LinkList<DataType>::insertNode(int i,DataType newData)
{
	ListNode<DataType> *p = head;  //设置游标指针,初始化为头结点的地址
	int j;
	for (j=1;j<=i-1;j++)  //查找第i个结点,指针需要移动i-1次
	{
		p = p->next;
		if (p == NULL) //如果该指针为空,表示不存在该结点,或者已到表尾
		{
			break;
		}
	}

	if (p==NULL && j<(i-1)) //指针为空且没有到第i个位置,说明不存在第i个结点
	{
		std::cout<<"插入位置无效!"<<endl;
		return false;
	}
	ListNode<DataType> *node = new ListNode<DataType>(newData); //创建新结点node
	node->next = p->next;  //将node的next指针赋值为p的后继结点地址
	p->next = node;    //p的后继指针指向node
	return true;

}

//在单链表的表尾添加新结点
template<typename DataType> bool LinkList<DataType>::insertNode(DataType newData)
{
	ListNode<DataType> *p = head;                          //设置游标指针
	ListNode<DataType> *node = new ListNode<DataType>(newData); //创建新结点
	if (node==NULL)            //如果新结点内存分配失败,返回false
	{
		return false;
	}

	while(p->next != NULL) //遍历单链表,找到尾结点
	{
		p = p->next;
	}
	p->next = node;
	return true;

}

//删除指定结点
template<typename DataType> bool LinkList<DataType>::removeNode(ListNode<DataType> *q)
{
	if (q == NULL)
	{
		std::cout<<"待删除结点不存在!"<<std::endl;
		return false;
	}
	ListNode<DataType> *tempPointer = head; //设置游标指针,初始化为头结点
	while(tempPointer->next != q) //遍历单链表,找到结点q的前驱结点
	{
		tempPointer = tempPointer->next;
	}
	tempPointer->next = q->next; //将结点q的后继结点地址值赋给其前驱结点的next的指针
	delete q;
	return true;

}

//查找指定结点值
template<typename DataType> ListNode<DataType>* LinkList<DataType>::findNode(DataType value)
{
	ListNode<DataType> *currentPointer = head; //设置游标指针
	//判断游标指针所指结点的值是否与value相等
	while(currentPointer != NULL && currentPointer->data != value)
	{
		currentPointer = currentPointer->next;
	}
	if (currentPointer == NULL)
	{
		std::cout<<"没有找到该结点,程序退出!"<<endl;
		exit(1);
	}
	else{
		return currentPointer
	}
}

//清空链表
template<typename DataType> void LinkList<DataType>::cleanLink()
{
	ListNode<DataType> *current = head; //设置游标指针
	while(head->next != NULL)
	{
		current = head->next;   //将current指向head的后继结点
		head->next = current->next; //将current的后继地址赋值给head的next域
		delete current;      //回收current结点所占的空间
	}
}

//获取结点数据
template<typename DataType> DataType LinkList<DataType>::getNodeData(int index)
{
	int linkLength = getLength();
	if (index < 1 || index > linkLength)
	{
		std::cout<<"结点不存在!"<<std::endl;
		return false;
	}
	else
	{
		ListNode<DataType> *pmove = head->next;
		for (int i=1; i<index && pmove; i++)
		{
			pmove = pmove->next;
		}
		return pmove->getData();
	}
}

//获取链表长度
template<typename DataType> int LinkList<DataType>::getLength()
{
	int count = 0;
	ListNode<DataType> *p = head->next;
	while(p!=NULL)
	{
		p = p->next;
		count++;
	}
	return count;
}

//查找链表的第i个元素
template<typename DataType> ListNode<DataType>* LinkList<DataType>::getNode(int i)
{
	ListNode<DataType> *p = head->next;
	int j;
	if (i<1 || i>getLength()-1) //带"头结点",所以实际结点数需要减1
	{
		return false;
	}
	for (j=1;j<i;j++)
	{
		p = p->next;
		if (p == NULL)
		{
			break;
		}
	}
	if (p == NULL && j<i-1)
	{
		return false;
	}

	return p;
}

效果如下:

图(1)在数组{3,6,9,12,15,18,21,24,27,30}中查找倒数第3个元素,得到的元素为24

参考文献: 胡浩.妙趣横生的算法(C++语言实现).北京.清华大学出版社.2014

时间: 2024-10-14 23:38:28

查找单链表中的倒数第m个结点的相关文章

实现一个算法从一个单链表中返回倒数第n个元素(keep it up)

我们维护两个指针, 它们之间的距离为n.然后,我将这两个指针同步地在这个单链表上移动,保持它们的距离 为n不变.那么, 当第二个指针指到空时,第一个指针即为所求. #include <iostream> struct Node { int data; Node* next; }; void initList(Node* vNode) { for (int i=0; i < 20; ++i) { Node* TempNode = new Node; TempNode->data =

找出单向链表中的倒数第k个结点

import java.util.Scanner; public class List { private Node first; private int N; class Node{ int data; Node next; } //顺便复习一下链表 public int size() { return N; } public boolean isEmpty() { return first==null; } public Node FindPrev(int pos){ Node tmp=fi

链表习题(8)-寻找单链表中数据域大小为k的结点,并与前一结点交换,如果前一结点存在的情况下

1 /*寻找单链表中数据域大小为k的结点,并与前一结点交换,如果前一结点存在的情况下*/ 2 /* 3 算法思想:定义两个指针,pre指向前驱结点,p指向当前结点,当p->data == k的时候,交换 4 pre->data和p->data 5 */ 6 void SwapData(LinkList& L, int k) 7 { 8 LNode *pre = L, *p = L->next; 9 int temp; 10 while (p) 11 { 12 if (p-&

[算法]在单链表和双链表中删除倒数第k个结点

题目: 分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点. 要求: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1). 解答: 让链表从头走到尾,每移动一步,就让K值减一,当链表走到结尾时,如果K值大于0,说明不用调整链表,因为链表根本没有倒数第K个节点,此时将原链表直接返回即可:如果K值等于0,说明链表倒数第K个节点就是头结点,此时直接返回head.next,相当于删除了头结点.当K的值小于零时,再次从头结点开始走,每移动一步,就让

008实现一个算法从一个单链表中返回倒数第n个元素(keep it up)

我们维护两个指针, 它们之间的距离为n. 然后.我将这两个指针同步地在这个单链表上移动,保持它们的距离 为n不变. 那么, 当第二个指针指到空时.第一个指针即为所求. #include <iostream> struct Node { int data; Node* next; }; void initList(Node* vNode) { for (int i=0; i < 20; ++i) { Node* TempNode = new Node; TempNode->data

链表中获取倒数第K个结点

/* * 链表中查找倒数第K个结点.cpp * * Created on: 2018年5月1日 * Author: soyo */ #include<iostream> using namespace std; struct Node { int num; Node * next; }; Node * creat() { Node *head=NULL; head=new Node; head->num=9; head->next=NULL; return head; } Node

链表中的倒数第k个结点

题目描述 输入一个链表,输出该链表中倒数第k个结点. 基本思想:定义两个指针a,b分别指向头节点, a指针先向前走k-1步(注意:因为倒数节点是从倒数第一个结点开始的,而不是零),然后a指针和b指针一起向前移动, 直到a->next == NULL.此时,b指针所指向的结点.即为倒数第K个结点. 边界条件:1.输入的pListHead为空指针的情况:    2.输入的以pListHead为头结点的链表的节点总数少于K的情况: 3.输入K为0的情况. #include <iostream>

leetcode链表--18、remove-nth-node-from-end-of-list(从链表中删除倒数第k个结点)

题目描述 Given a linked list, remove the nth node from the end of list and return its head. For example, Given linked list: 1->2->3->4->5, and n = 2.   After removing the second node from the end, the linked list becomes 1->2->3->5. Note:

【LeetCode-面试算法经典-Java实现】【203-Remove Linked List Elements(删除单链表中的元素)】

[203-Remove Linked List Elements(删除单链表中的元素)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 代码下载[https://github.com/Wang-Jun-Chao] 原题 Remove all elements from a linked list of integers that have value val. Example Given: 1 --> 2 --> 6 --> 3 --> 4 --> 5