数据结构和算法之单向链表二:获取倒数第K个节点

Posted GoNewLife

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构和算法之单向链表二:获取倒数第K个节点相关的知识,希望对你有一定的参考价值。

  我们在做算法的时候或多或少都会遇到这样的问题,那就是我们需要获取某一个数据集的倒数或者正数第几个数据。那么今天我们来看一下这个问题,怎么去获取倒数第K个节点。我们拿到这个问题的时候自然而然会想到我们让链表从末尾开始next   K-1 次不就是第K-1个节点了么,但是必须要注意一点,这是单向链表。那么这时候的解决思路或许就会出现分歧,大多数人都会想到我们遍历一下链表,获取链表的长度,然后再减去 K 长度的节点,那么我们这个链表的最后一个节点就是原链表的倒数第K个节点:我们看一下实现代码:

/**
     * 获取倒数第K个节点的数据
     * @param index
     * @return
     */
    public int getDtae(int index){
        //对整个链表进行遍历
        int size = 0;
        Node current = head;//head是头结点
        while(current!=null){
            size++;
            current = current.next;
        }
        current = head;
        //向后遍历size-K获取倒数第K个节点
        for(int i = 0;i < size - index;i++){
            current = current.next;
        }
        return current.date;
    }

  我们可以发现,这段代码可不可以实现我们需要的功能,当然可以。那么问题来了,如果我们要是输入的index大于链表的长度或者说链表自身就是一个空链表,那么,我们这段代码会不会出现问题。或者当我们的index等于0的时候,又会不会出现问题,正常来说我们将倒数都是从倒数第一开始,倒数零是不是就没有意义,那么这一段代码还够不够强壮。这个问题或许我们稍微有一点良好的编程思想都会想到,我们留到最后解决。下面我们需要思考的是怎么在遍历一边链表的情况下就获取到上面的数据。我们可不可以定义两个节点first和second,他们同时指向head头结点。我们先把第二个节点向后移动index-1步,这时first和second是不是就相距k,我们再把两个节点同时向后移动,当second到达链表尾端的时候,是不是就可以说first的位置就是我们需要的倒数第K个节点。代码如下:

/**
     * 获取倒数第K个节点的数据
     * @param index
     * @return
     */
    public int getDtae(int index){
        //定义两个节点指向head
        Node first = head;
        Node second = head;
        //把第二个节点向后移动k-1步
        for(int i = 0;i < index - 1;i++){
            second = second.next;
        }
        //再把两个节点同时向后移动,直到second到达尾端位置
        while(second!=null){
            first = first.next;
            second = second.next;
        }
        return first.date;
    }

  我们可以看到这一段代码是不是就已经实现了。但是还是那个问题,一段代码的强壮型在于它在处理特殊事件时候的能力,别让整个程序崩溃。接下来我们进行以下操作,避免我们所说的三个问题,index等于0,index超过了链表的长度,链表是空链表的请况:

/**
     * 获取倒数第K个节点的数据
     * @param index
     * @return
     */
    public int getDtae(int index){
        //判断index是否为零或者是小于零的不合法数据
        if(index <= 0){
            //抛出空指针异常
            throw new NullPointerException();
        }
        //定义两个节点指向head
        Node first = head;
        Node second = head;
        //第二个节点向后移动K-1步
        for(int i = 0;i < index -1;i++){
            //判断second是否为空
            if(second==null){
                throw new NullPointerException();
            }
            second = second.next;
        }
        //两个节点向后移动直到链表的尾端
        while(second!=null){
            first = first.next;
            second = second.next;
        }
        return first.date;
    }

  我们可以看到在开始直接判断k等于0的情况,我们在第二个节点向后移动的时候直接判断他是否为空,如果链表为空,那么刚开始second自然为空,如果index大于链表长度,在之后next的过程中,自然second也会产生空的情况。这就完美解决了上面提到的三个情况,index等于零,index大于链表长度,链表为空的情况。我们在进行测试的时候可以通过我上一篇博客对一个链表插入数据,然后再进行功能测试,获取链表的首尾中三个节点数据,在进行特殊测试的时候可以输入上面的三种情况就是测试。

以上是关于数据结构和算法之单向链表二:获取倒数第K个节点的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法面试题单向链表倒数第k个节点

数据结构——求单向链表的倒数第K个节点

算法总结之 在单链表和双链表中删除倒数第k个节点

算法面试题 02.02. 返回倒数第 k 个节点

链表的倒数第k个节点

输入一个单向链表,输出该链表中倒数第k个结点