由于链表中不能随机得到一个结点的值,也不知道具体的第K个结点在什么位置,不像数组那样随机存取效率高,所以有时候我们需要知道第K个元素的值,这里我们讨论一下如何获得倒数第K个元素的值。
正向第K个元素很简单,用一趟遍历便可以得到。时间复杂度为O(N)。
那么倒数第K个元素,还需要遍历一次,其时间复杂度为:O(N)+O(N)=O(N)。遍历一遍,我们就知道了链表的长度N,用一个计数器就搞定。
那么和倒数第K个元素有什么关系呢?
倒数第K个元素,也就是正向的第N-K+1个。
例如:12345,倒数第二个元素4,也就是正向的5-2+1=4。
方案一的代码是实现比较简单,省略。这里主要是实现方案二:
正向第K个元素很简单,用一趟遍历便可以得到。时间复杂度为O(N)。
那么倒数第K个元素,还需要遍历一次,其时间复杂度为:O(N)+O(N)=O(N)。遍历一遍,我们就知道了链表的长度N,用一个计数器就搞定。
那么和倒数第K个元素有什么关系呢?
倒数第K个元素,也就是正向的第N-K+1个。
例如:12345,倒数第二个元素4,也就是正向的5-2+1=4。
所以基于这个原理我们可以很快的得到解决方案一:遍历两次,第二次得到第N-K+1的位置。但是第一种方案遍历了两次链表,有时候我们要求只遍历一次。
那么又有了第二种方案。
方案二:这也是受第一种方案的启发。因为链表的总长度N不变,借助两个指针,一个向前走K-1步后,第二个指针开始从头走,当第一个走到尾结点的时候,第二个指针走了N-K+1步,和第一种方案原理类似。但是我们只遍历了一次,提高了效率。方案一的代码是实现比较简单,省略。这里主要是实现方案二:
具体代码如下:
#include <iostream>
using namespace std;
struct List
{
int number;
List *pNext;
};
List *pHead=NULL;
List *pEnd=NULL;
List *pNode=NULL;
void CreateList()
{
int number;
cout<<"please input the number:"<<endl;
cin>>number;
while(0!=number)
{
pNode=new List;
pNode->number=number;
pNode->pNext=NULL;
if(NULL==pHead)
{
pHead=pNode;
pEnd=pNode;
}
else
{
pEnd->pNext=pNode;
pEnd=pNode;
}
cin>>number;
}
}
void show()
{
List *temp=pHead;
cout<<"List:";
while(temp)
{
cout<<temp->number<<" ";
temp=temp->pNext;
}
cout<<endl;
}
List* Backword_K(int num)
{
List *First=pHead;
List *second=pHead;
//输入的K不符合要求,小于等于0;链表为NULL;
if(!pHead || 0==num)
return NULL;
//K大于链表的长度的情况;
for(int i=0;i<num-1;i++)
{
if(First->pNext!=NULL)
{
First=First->pNext;
}
else
{
return NULL;
}
}
while(First->pNext)
{
First=First->pNext;
second=second->pNext;
}
return second;
}
int main()
{
int position=3;
int result=0;
CreateList();
show();
List *temp=Backword_K(position);
result=temp->number;
cout<<"倒数第"<<position<<"个数是:"<<result<<endl;
system("pause");
return 0;
}
运行结果: