我们在做算法的时候或多或少都会遇到这样的问题,那就是我们需要获取某一个数据集的倒数或者正数第几个数据。那么今天我们来看一下这个问题,怎么去获取倒数第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 || head == null){
//抛出空指针异常
throw new NullPointerException();
}
//定义两个节点指向head
Node first = head;
Node second = head;
//第二个节点向后移动K-1步
for(int i = 0;i < index -1;i++){
//判断second是否为空
second = second.next;
 if(second==null){

throw new NullPointerException();
}
} //两个节点向后移动直到链表的尾端 while(second!=null){ first = first.next; second = second.next; } return first.date; }

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

  通过以上问题我们还可以思考一个事情,如果我们需要得到中间节点,但是只允许遍历一次的情况下我们应该怎么去实现:

public int getMiddle(){
//判断链表是否为空
if(head == null){
throw new NullpointerExpection();
}
//定义两个节点同时指向首节点
Node first = head;
Node second = head;
//将第二个节点向后移动两步,第一个节点向后移动一步,直到second到达尾端
while( second.next != null){
first = first.next;
second = second.next.next;
}
return first.date;
}

  我们需要注意的是这段代码有一点缺陷,那就是我们的链表长度如果是偶数的话,那么我们获取到的中间值就是 N/2 + 1的节点,与我们的计算会相差一位,不过这不是重点,重要的是我们需要体会里面的思想。

 if(second==null){
throw new NullPointerException();
}

数据结构和算法之单向链表二:获取倒数第K个节点的更多相关文章

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

    分别实现两个函数,一个可以删除单链表中倒数第k个节点,另一个可以删除双链表中倒数第k个节点 思路: 如果链表为空,或者k<1 参数无效 除此之外 让链表从头开始走到尾,每移动一步,就让k的值减1 ...

  2. 在单链表和双链表中删除倒数第K个节点

    [说明]: 本文是左程云老师所著的<程序员面试代码指南>第二章中“在单链表和双链表中删除倒数第K个节点”这一题目的C++复现. 本文只包含问题描述.C++代码的实现以及简单的思路,不包含解 ...

  3. 《程序员代码面试指南》第二章 链表问题 在单链表和双链表中删除倒数第K个节点

    题目 在单链表和双链表中删除倒数第K个节点 java代码 /** * @Description:在单链表和双链表中删除倒数第K个节点 * @Author: lizhouwei * @CreateDat ...

  4. 链表问题----删除倒数第K个节点

    在单链表和双链表中删除倒数第K个节点 分别实现两个函数,一个可以删除单链表中的倒数第K个节点,一个可以删除双链表中的倒数第k 个节点,要求时间复杂度是 O(N),空间复杂度是 O(1). [解析] 基 ...

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

    /* * 链表中查找倒数第K个结点.cpp * * Created on: 2018年5月1日 * Author: soyo */ #include<iostream> using nam ...

  6. 面试题 02.02. [链表][双指针]返回倒数第 k 个节点

    面试题 02.02. 返回倒数第 k 个节点 方法一:使用外部空间 // 执行用时: 1 ms , 在所有 Java 提交中击败了 16.75% 的用户 // 内存消耗: 36.8 MB , 在所有 ...

  7. 1.求链表中的倒数第K个节点

    注意事项:1.要是K大于链表长度怎么办? 2.k<=0怎么办? ListNode* FindR_Kth(ListNode* p_head, unsigned int k) 2 {//找到链表的倒 ...

  8. 链表中删除倒数第K个节点

    问题描述 分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点. 问题分析与解决 从问题当中,我们只能得到一个链表和要删除的第K个节点的信息,于是就有以下思路:如 ...

  9. 线性数据结构案例1 —— 单向链表中获取倒数k个节点

    一.介绍  先遍历整个链表获取链表长度length,然后通过 (length-index) 方式得到我们想要节点在链表中的位置. 二.代码 public Node findLastIndexNode( ...

随机推荐

  1. SpringMVC札集(04)——SpringMVC传递参数

    自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onL ...

  2. 《Tomcat内核设计剖析》勘误表

    <Tomcat内核设计剖析>勘误表 书中第95页图request部分印成了reqiest. 书中第311页两个tomcat3,其中一个应为tomcat4. 书中第5页URL应为URI. 书 ...

  3. awk命令结合管道命令对json文件进行统计分析

    json文件内容: $ head file.json {"B": 0.337, "C": 0.663, "name": "xxx& ...

  4. linux远程win7教程

    http://jingyan.baidu.com/article/c275f6bacd2227e33c756754.html 1 在ubuntu下搜索Remmina(超级方便,应该也可以控制linux ...

  5. threejs三角形Geometry的顶点时针顺序会导致三角形看不见

    var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75,winSize.width/winSize.hei ...

  6. CA数字加密解密Demo

    package aisin.text;    import com.google.common.collect.Maps;  import sun.misc.BASE64Decoder;  impor ...

  7. 《DSP using MATLAB》示例 Example 6.11

    上代码: % x = -7:7 y = OnesComplement(x, 4) 函数OnesComplement代码: function [y] = OnesComplement(x, B); % ...

  8. python 数组反序的方法

    arr = np.array(some_sequence) reversed_arr = arr[::-1] do_something(arr) look_at(reversed_arr) do_so ...

  9. 部署coredns

      1 前提:     1.1不依赖kubeadm的方式,适用于不是使用kubeadm创建的k8s集群,或者kubeadm初始化集群之后,删除了dns相关部署.      1.2 DNS IP :10 ...

  10. Python 函数 -getattr()

    getattr(object, name[, default]) getatt() 函数用于返回一个对象属性值.object 对象.name 字符串,对象属性.object 默认返回值,如果不提供该参 ...