数据结构和算法之单向链表二:获取倒数第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 || 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个节点的更多相关文章
- 算法总结之 在单链表和双链表中删除倒数第k个节点
分别实现两个函数,一个可以删除单链表中倒数第k个节点,另一个可以删除双链表中倒数第k个节点 思路: 如果链表为空,或者k<1 参数无效 除此之外 让链表从头开始走到尾,每移动一步,就让k的值减1 ...
- 在单链表和双链表中删除倒数第K个节点
[说明]: 本文是左程云老师所著的<程序员面试代码指南>第二章中“在单链表和双链表中删除倒数第K个节点”这一题目的C++复现. 本文只包含问题描述.C++代码的实现以及简单的思路,不包含解 ...
- 《程序员代码面试指南》第二章 链表问题 在单链表和双链表中删除倒数第K个节点
题目 在单链表和双链表中删除倒数第K个节点 java代码 /** * @Description:在单链表和双链表中删除倒数第K个节点 * @Author: lizhouwei * @CreateDat ...
- 链表问题----删除倒数第K个节点
在单链表和双链表中删除倒数第K个节点 分别实现两个函数,一个可以删除单链表中的倒数第K个节点,一个可以删除双链表中的倒数第k 个节点,要求时间复杂度是 O(N),空间复杂度是 O(1). [解析] 基 ...
- 链表中获取倒数第K个结点
/* * 链表中查找倒数第K个结点.cpp * * Created on: 2018年5月1日 * Author: soyo */ #include<iostream> using nam ...
- 面试题 02.02. [链表][双指针]返回倒数第 k 个节点
面试题 02.02. 返回倒数第 k 个节点 方法一:使用外部空间 // 执行用时: 1 ms , 在所有 Java 提交中击败了 16.75% 的用户 // 内存消耗: 36.8 MB , 在所有 ...
- 1.求链表中的倒数第K个节点
注意事项:1.要是K大于链表长度怎么办? 2.k<=0怎么办? ListNode* FindR_Kth(ListNode* p_head, unsigned int k) 2 {//找到链表的倒 ...
- 链表中删除倒数第K个节点
问题描述 分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点. 问题分析与解决 从问题当中,我们只能得到一个链表和要删除的第K个节点的信息,于是就有以下思路:如 ...
- 线性数据结构案例1 —— 单向链表中获取倒数k个节点
一.介绍 先遍历整个链表获取链表长度length,然后通过 (length-index) 方式得到我们想要节点在链表中的位置. 二.代码 public Node findLastIndexNode( ...
随机推荐
- ImportError: liblapack.so.3: cannot open shared object file问题
问题: 安装完tensorflow后,在终端输入: python import cv2 出现如下错误: ImportError: liblapack.so.3: cannot open shared ...
- CentOS常用命令汇总
将新创建的数据分配某个用户访问 grant all privileges on zhouzdb.* to 'zhouz'@'%' identified by '1234'; flush privile ...
- BDD测试框架Spock概要
前言 为了找到一个适合自己的.更具操作性的.以DDD为核心的开发方法,我最近一直在摸索如何揉合BDD与DDD.围绕这个目标,我找到了Impact Mapping → Cucumber → Spock ...
- 滑动ViewPager引起swiperefreshlayout刷新的冲突
ViewPager是Android中提供的页面切换的控件,SwipeRefreshLayout是Android提供的下拉刷新控件,通过SwipeRefreshLayout可以很简单的实现下拉刷新的功能 ...
- Android HOOK工具Cydia Substrate使用详解
目录(?)[+] Substrate几个重要API介绍 MShookClassLoad MShookMethod 使用方法 短信监控实例 Cydia Substrate是一个代码修改平台.它可以修 ...
- erl_0020 《面对软件错误构建可靠的分布式系统》读书笔记001 “面向并发COPL”
在现实世界中,顺序化的(sequential)活动非常罕见.当我们走在大街上的时候,如果只看到一件事情发生的话我们一定会感到不可思议,我们期望碰到许多同时进行的活动. 如果我们不能对同时发生的众多事件 ...
- ZOJ3640Help Me Escape(师傅逃亡系列•一)(数学期望||概率DP)
Background If thou doest well, shalt thou not be accepted? and if thou doest not well, sin lieth at ...
- hadoop入门手册3:Hadoop【2.7.1】初级入门之命令指南
问题导读1.hadoop daemonlog管理员命令的作用是什么?2.hadoop如何运行一个类,如何运行一个jar包?3.hadoop archive的作用是什么? 概述 hadoop命令被bin ...
- ORACLE PL/SQL:触发器
ORACLE PL/SQL 触发器 本篇主要内容如下: 8.1 触发器类型 8.1.1 DML触发器 8.1.2 替代触发器 8.1.3 系统触发器 8.2 创建触发器 8.2.1 触发器触发次序 8 ...
- jQuery.1.9 live 代替事件 on 新增内容无法触发事件
如果是新增 append 或者 html() 事件添加的内容,无法触发 click 事件, 在1.9 可以用live 事件来代替 1.9以后用 <div class="search-r ...