数据结构和算法之单向链表二:获取倒数第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大于链表长度,链表为空的情况。我们在进行测试的时候可以通过我上一篇博客对一个链表插入数据,然后再进行功能测试,获取链表的首尾中三个节点数据,在进行特殊测试的时候可以输入上面的三种情况就是测试。

时间: 2024-08-06 20:04:36

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

找出单向链表中的倒数第k个结点

import java.util.Scanner; public class List { private Node first; private int N; class Node{ int data; Node next; } //顺便复习一下链表 public int size() { return N; } public boolean isEmpty() { return first==null; } public Node FindPrev(int pos){ Node tmp=fi

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

分别实现两个函数,一个可以删除单链表中倒数第k个节点,另一个可以删除双链表中倒数第k个节点 思路: 如果链表为空,或者k<1 参数无效 除此之外 让链表从头开始走到尾,每移动一步,就让k的值减1 当链表走到头时候 如果k值大于0   说明不用调整  因为链表根本没有倒数第k个节点 此时将原链表直接返回即可 如果k值=0,说明链表倒数第k个节点就是头节点,此时直接返回head.next 也就是原链表的第二个节点 让第二个节点作为链表的头节点,此时直接返回head.next 如果k值<0  重新从

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

在单链表和双链表中删除倒数第K个节点 分别实现两个函数,一个可以删除单链表中的倒数第K个节点,一个可以删除双链表中的倒数第k 个节点,要求时间复杂度是 O(N),空间复杂度是 O(1). [解析] 基本思路: 让链表从头开始走到尾,每移动一步,就让k值减一,当k 值走到结尾时, 如果k 值大于0,说明链表根本没有倒数第k 个节点 如果等于0,那么头节点就是倒数第k 个节点,此时应该返回 head.next 如果小于0,则重新从头节点开始,每移动一步,k 值增加一,当k 等于0时,移动停止,移动到

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

/* * 链表中查找倒数第K个结点.cpp * * Created on: 2018年5月1日 * Author: soyo */ #include<iostream> using namespace std; struct Node { int num; Node * next; }; Node * creat() { Node *head=NULL; head=new Node; head->num=9; head->next=NULL; return head; } Node

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

题目:分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点 要求:如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1) My: 删除单链表或双链表中倒数第K个节点,核心代码(单链表和双链表的方法定义参见另一篇文:https://www.cnblogs.com/latup/p/9823179.html): 1 def del_k(L, k): 2 index = L.length - k + 1 3 L.delt(index) 原文地址:htt

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

问题描述 分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点. 问题分析与解决 从问题当中,我们只能得到一个链表和要删除的第K个节点的信息,于是就有以下思路:如果链表为空或者K<0时,直接返回:如若不然,遍历链表的每个节点,每经过一个节点K减1.比如对于1 --> 2 --> 3 --> 4该链表的过程如下: K = 5,所遍历的节点以及K值的变化:1 -- > 2 --> 3 --> 4 4,3,2,1: K = 4,所遍

数据结构和算法之单向链表六:链表的反转以及链表节点的删除

在前面介绍了关于链表的一系列问题,这里我们在介绍一下关于单向链表的反转这个比较具有代表性的算法.在进行反转的时候一定要记住多画图,多去理解在链表进行反转的时候它对于地址的改变,这和数组的数据对换具有很大的不一致. public Node reverseList(Node head){ //判断链表是否为空或者只有一个节点 if(head == null || head.next == null){ return head; } //准备三个节点 Node next = null;//保存当前节点

数据结构与算法学习-单向链表的实现

链表(Chain本文所说链表均为单向链表,以下均简称单向链表)实际上是由节点(Node)组成的,一个链表拥有不定数量的节点.而向外暴露的只有一个头节点(Head),我们对链表的所有操作,都是直接或者间接地通过其头节点来进行的. 节点(Node)是由一个需要储存的对象及对下一个节点的引用组成的.也就是说,节点拥有两个成员:储存的对象.对下一个节点的引用. 这样说可能大家不是很明白,我贴一张图大家可能更容易理解. package LinkedList; /** * <p><strong>

单链表中查找倒数第K个节点

// 查找链表的倒数第K个结点 PSListNode FindLastKNode(PSListNode pHead, int K ) { PSListNode pFast = pHead ; PSListNode pSlow = pHead ; if (pHead == NULL || K <= 0) { return NULL ; } while (--K ) { if (pFast == NULL ) { return NULL ; } pFast = pFast->pNext; } wh