[链表] 查找单链表中的倒数第k个元素

1、为了找出倒数第k个元素,最容易想到的办法是首先遍历一遍单链表,求出整个单链表的长度n,然后将倒数第k个,转换为正数第n-k个,接下来遍历一次就可以得到结果。但是该方法存在一个问题,即需要对链表进行两次遍历,第一次遍历用于求解单链表的长度,第二次遍历用于查找正数第n-k个元素。
2、显然,这种方法还可以进行优化。于是想到了第二种方法,如果从头至尾的方向从链表中的某个元素开始,遍历k个元素后刚好达到链表尾,那么该元素就是要找到的倒数第k个元素,根据这一性质,可以设计如下算法:从头节点开始,依次对链表的每一个节点元素进行这样的测试,遍历k个元素,查看是否到达链表尾,只到找到哪个倒数第k个元素。此种方法将对同一批元素进行反复多次的遍历,对于链表中的大部分元素而言,都要遍历K个元素,如果链表长度为n个的话,该算法的时间复杂度为O(kn)级,效率太低。

3、存在另外一个更高效的方式,只需要一次遍历即可查找到倒数第k个元素。由于单链表只能从头到尾依次访问链表的各个节点,因此,如果要找到链表的倒数第k个元素的话,也只能从头到尾进行遍历查找,在查找过程中,设置两个指针,让其中一个指针比另一个指针先前移k-1步,然后两个指针同时往前移动。循环直到线性的指针值为NULL时,另一个指针所指向的位置就是所要找到的位置。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace repicropal
{
    class Program
    {
        static void Main(string[] args)
        {
            LinkedList<string> list = new LinkedList<string>();
            list.AddLast("1");
            list.AddLast("2");
            list.AddLast("3");
            list.AddLast("4");
            Console.WriteLine(GetReciprocalElement2(list, 4).Value);
        }

        static LinkedListNode<string> GetReciprocalElement1(LinkedList<string> list, int reciprocalIndex)
        {
            LinkedListNode<string> temp = null;
            LinkedListNode<string> head = list.First;
            int index = 1;
            if (list.Count < reciprocalIndex) return null;
            while (head != null)
            {
                //index达到倒数的位数时
                if (reciprocalIndex == index)
                {
                    //temp从head开始,也就是temp比head先跑index个步数
                    temp = head;
                    //head从头开始
                    head = list.First;
                }
                if (temp != null)
                {
                    //temp == null 说明temp已经到达链表尾部
                    if (temp.Next == null)
                    {
                        //此时head刚好到达倒数的指定位置
                        temp = head;
                        break;
                    }
                }
                //累加步数
                index++;
                //temp向前移动
                if (temp != null)
                    temp = temp.Next;
                //head 向前移动
                head = head.Next;
            }
            Console.WriteLine(index+"循环次数 "+temp.Value);
            return temp;
        }

        static LinkedListNode<string> GetReciprocalElement2(LinkedList<string> list, int reciprocalIndex)
        {
            LinkedListNode<string> temp = list.First;
            LinkedListNode<string> head = list.First;

            //让head先跑reciprocalIndex步
            while (--reciprocalIndex >= 0)
            {
                head = head.Next;
            }

            //temp从头开始跑,head继续从当前位置开始跑,一直到head跑到最后
            while (head != null)
            {
                temp = temp.Next;
                head = head.Next;
            }

            return temp;
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容