问答题 如何找出单链表中的倒数第k个元素
【正确答案】
【答案解析】为了找出单链表中的倒数第k个元素,最容易想到的方法是首先遍历一遍单链表,求出整个单链表的长度n,然后将倒数第k个,转换为正数第n-k个,接下去遍历一次就可以得到结果。但是该方法存在一个问题,即需要对链表进行两次遍历,第一次遍历用于求解单链表的长度,第二次遍历用于查找正数第n-k个元素。
显然,以上这种方法还可以进行优化。于是想到了第二种方法,如果沿从头至尾的方向从链表中的某个元素开始,遍历k个元素后刚好达到链表尾,那么该元素就是要找的倒数第k个元素,根据这一性质,可以设计如下算法:从头结点开始,依次对链表的每一个结点元素进行这样的测试,遍历k个元素,查看是否到达链表尾,直到找到那个倒数第k个元素。此种方法将对同一批元素进行反复多次的遍历,对于链表中的大部分元素而言,都要遍历k个元素,如果链表长度为n,该算法时间复杂度为O(kn)级,效率太低。
存在另外一种更高效的方式,只需要一次遍历即可查找到倒数第k个元素。由于单链表只能从头到尾依次访问链表的各个结点,因此,如果要找出链表的倒数第k个元素的话,也只能从头到尾进行遍历查找,在查找过程中,设置两个指针,让其中一个指针比另一个指针(虽然Java语言没有指针的概念,但是引用与指针有着非常相似的性质。为了便于理解,在后续的介绍中都采用指针的概念来介绍)先前移k-1步,然后两个指针同时往前移动。循环直到先行的指针值为NULL时,另一个指针所指的位置就是所要找的位置。程序代码如下:
public Node findElem(Node head, int k){
if(k<1 || k>this.length())
return null;
Node p1=head;
Node p2=head;
for(int i=0; i<k-1; i++)//前移k-1步
p1=p1.next;
while(p1!=null){
p1=p1.next;
p2=p2.next;
}
return p2;
}