Java链表数据结构及其简单使用方法解析

目录
  • 认识链表结构
    • 单向链表
    • 双向链表
  • 加深对链表结构的理解
    • 实现单向和双向链表的反转
    • 实现把链表中给定的值都删除
  • 小结

认识链表结构

单向链表

单链表在内存中的表示:

可以看到,一个链表的节点包含数据域和指向下一个节点的引用,链表最后一个节点指向null(空区域)。

我们可以根据这一定义,用Java语言表示一下单向链表的结构:

public class Node {
    public int value;
    public Node next;

    public Node(int value) {
        this.value = value;
    }
}

在链表的结构中,有数据域value,以及一个指向下一个节点的引用next。

TIP:这里的value还可以定义成泛型的。

双向链表

我们再来看一下双向链表的结构:

双向链表中的节点有数值域,和指向它前一个节点的引用以及指向它后一个节点的引用,据此我们可以定义出

双向链表的结构:

public class DoubleNode {
    public int value;
    public DoubleNode pre;
    public DoubleNode next;

    public DoubleNode(int value) {
        this.value = value;
    }
}

加深对链表结构的理解

实现单向和双向链表的反转

说明:

对于一个链表如图所示:

反转的意思是,将原来链表上的节点指针指向反转,原来的指向是:a -> b -> c -> d -> null,变成现在的指向:d -> c -> b -> a -> null,

即反转后的结构如图所示:

这个题目不难,我们转换一下指针的指向就行了。

设计这样一个函数,函数的过程是调整链表各节点的指针指向,那么这个函数的要素有:

  • 返回值是链表的新的头结点,这样能保证函数执行完,原链表变成一个有新的头结点的链表
  • 需要传入一个链表,用头结点表示

解题技巧:定义两个Node引用辅助我们反转指针指向。

代码实现:

public static Node reverseNode(Node head) {
    Node pre = null;
    Node next = null;
    //最终让head指向null
    while (head != null) {
        next = head.next;
        head.next = pre;
        pre = head;
        head = next;
    }
    return pre;
}

我们来模拟一下这个函数的执行过程。

链表原始状态:

方法开始执行,此时 head.next 不为空,所以,执行如下步骤:

next = head.next:让next指向head(当前节点)的下一个节点,即b

head.next = pre:让当前节点的下一个节点指向pre,即null

此时当前节点从原来指向b,改为指向null。

  • pre = head:让pre指向当前节点
  • head = next:让当前节点指向next,相当于移动head节点,直到将head节点移动到原来tail节点的位置

第一次循环执行结束,此时 head 为b,不是null,所以继续循环,执行流程:

此时 head 为c,不是null,所以继续循环,执行流程如下:

同理,此时 head 为d,不是null,继续循环:

这是就完成了单链表的反转步骤。

有了单链表反转的经验,我们很容易就能实现双向链表的反转,代码如下:

public DoubleNode reverseDoubleNode(DoubleNode head) {
    DoubleNode pre = null;
    DoubleNode next = null;
    while (head != null) {
        next = head.next;
        //操作(移动)当前节点
        head.next = pre;
        head.pre = next;

        pre = head;
        head = next;
    }
    return pre;
}

实现把链表中给定的值都删除

题如:给定一个单链表头节点head,以及一个整数,要求把链表中值为给定整数的节点都删除。

实现思路:

  • 要实现的函数需要给我传一个头节点以及给定的数值,头节点确定链表。func(Node head, int num)。
  • 函数给不给返回值,返回值是什么?试想,针对链表 3 -> 5 -> 4 -> 3 -> 4 -> 5 ,假如要删除4,那么新链表就是 3 -> 5-> 3 -> 5,头节点仍然是原来的节点3;而如果要删除值为3的节点呢,删除后就是 5 -> 4 -> 4 -> 5 ,头节点变了。因此,我们要设计的这个函数需要返回新链表的头节点。
  • 上述分析得知,需要返回新链表的头节点,因此也就是要返回第一个不是给定值的节点(因为给定值的节点都要被删除掉)。
//head移动到第一个不需要删除的位置:边界条件
while (head != null) {
    if (head.value != num) {
        break;
    }
    //head右移
    head = head.next;
}
//跳出循环之后,head的情况:
//1. head = null,这种情况是链表中的值全部是给定值,全删了
//2. head != null
// 中间操作
//最终返回head:第一个不是给定值的节点
return head;

head移动到第一个不需要删除的位置后,head若为null,表示所有节点都删除了,直接返回就可以了;若head不为null,借助两个辅助变量Node pre和cur,从head处开始往next走,遇到给定值就跳过。

Node pre = head;
Node cur = head;
while (cur != null) {
    if (cur.value == num) {
        pre.next = cur.next;
    } else {
        pre = cur;
    }
    cur = cur.next;
}

这一执行过程图解如下:

通过上述分析,写出完整实现代码:

public static Node remove (Node head, int num) {
    while (head != null) {
        if (head.value != num) {
            break;
        }
        head = head.next;
    }

    Node pre = head;
    Node cur = head;

    while (cur != null) {
        if (cur.value == num) {
            pre.next = cur.next;
        } else {
            pre = cur;
        }
        cur = cur.next;
    }
    return head;
}

小结

针对链表这种数据结构进行了一些简单的分析,通过两个例子熟悉了链表的结构。

针对链表的操作,需要注意的就是指针指向以及边界问题,后续关于链表的算法还会遇到。

到此这篇关于Java链表数据结构及其简单使用方法解析的文章就介绍到这了,更多相关Java链表数据结构内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java数据结构基础:单链表与双向链表

    目录 单链表: 实现思路: 代码实现: 双向链表: 实现思路: 代码实现: 总结 单链表: 每个数据是以节点的形式存在的 每个节点分为数据域和指针域 数据域中保存该节点的数据 指针域中保存指向下一个节点的指针 实现思路: 节点类SingleNode中保存数据和指向下一个节点的指针 单链表类SingleLinkedList中保存链表的头节点,实现相关链表方法 对于链表方法,涉及到位置查找,如在指定位置增加.删除节点,需要使用一个临时变量temp从头节点开始遍历,直至找到对应的位置. 对于节点的增加

  • Java数据结构之顺序表和链表精解

    目录 前言 1. 顺序表 代码实现 2. 链表 链表图解 代码实现 前言 两个数据结构:顺序表和链表 数据结构是一门学科,和语言无关. 数据 + 结构:一种描述和组织数据的方式. 1. 顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储.在数组上完成数据的增删查改.其逻辑上和物理上都是连续的. 问题引入:一个数组放在这,我们如何才能自己不去数,让程序自己进行计数? 答:在引入变量,每次放一个元素就更新一次.(如下图,为问题的示意) 也就是说顺序表的底层

  • Java 数据结构与算法系列精讲之环形链表

    目录 概述 链表 环形链表 环形链表实现 Node类 insert方法 remove方法 main 完整代码 概述 从今天开始, 小白我将带大家开启 Java 数据结构 & 算法的新篇章. 链表 链表 (Linked List) 是一种递归的动态数据结构. 链表以线性表的形式, 在每一个节点存放下一个节点的指针. 链表解决了数组需要先知道数据大小的缺点, 增加了节点的指针域, 空间开销较大. 链表包括三类: 单向链表 双向链表 循环链表 环形链表 环形链表 (Circular Linked Li

  • Java实现链表数据结构的方法

    什么是链表? 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的.每一个链表都包含多个节点,节点又包含两个部分,一个是数据域(储存节点含有的信息),一个是引用域(储存下一个节点或者上一个节点的地址). 链表的理解示意图: 链表的特点是什么? 获取数据麻烦,需要遍历查找,比数组慢方便插入.删除 简单的链表的实现原理 创建一个节点类,其中节点类包含两个部分,第一个是数据域(你到时候要往节点里面储存的信息),第二个是引用域(相当于指针,单向链表有一个指

  • Java 数据结构与算法系列精讲之单向链表

    目录 概述 链表 单向链表 单向链表实现 Node类 add方法 remove方法 get方法 set方法 contain方法 main 完整代码 概述 从今天开始, 小白我将带大家开启 Jave 数据结构 & 算法的新篇章. 链表 链表 (Linked List) 是一种递归的动态数据结构. 链表以线性表的形式, 在每一个节点存放下一个节点的指针. 链表解决了数组需要先知道数据大小的缺点, 增加了节点的指针域, 空间开销较大. 链表包括三类: 单向链表 双向链表 循环链表 单向链表 单向链表

  • Java 数据结构之删除链表中重复的结点

    目录 解析一:(不提倡) 解析二:(正解) 核心考点:链表操作,临界条件检查,特殊情况处理 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 解析一:(不提倡) 解决该问题较简单,且在写代码时不易出错的做法如下: 遍历一遍链表,记录重复结点的结点值. 再遍历一遍链表,逐个删除重复结点. 动图演示: 该方法需要遍历两遍链表,且需要开辟额外的内存空间存储重复结点的结点值,所以一般不提倡. /* struct ListNode { int val; st

  • 带你了解Java数据结构和算法之链表

    目录 1.链表(Linked List) 2.单向链表(Single-Linked List) ①.单向链表的具体实现 ②.用单向链表实现栈 4.双端链表 ①.双端链表的具体实现 ②.用双端链表实现队列 5.抽象数据类型(ADT) 6.有序链表 7.有序链表和无序数组组合排序 8.双向链表 9.总结 前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷.在无序数组中,搜索性能差,在有序数组中,插入效率又很低,而且这两种数组的删除效率都很低,并且数组在创建后,其大小是固定了,设置的过大会

  • Java 精炼解读数据结构的链表的概念与实现

    目录 前言: 一.什么是链表 链表的概念 链表的结构 链表如何存储数据 链表的实现   穷举法创建链表 打印链表 查找是否包含关键字key是否在单链表当中  得到单链表的长度: 头插法 尾插法 任意位置插入,第一个数据节点为0号下标 删除第一次出现关键字为key的节点 删除所有值为key的节点 总结: 前言: 顺序表的问题及思考 1. 顺序表中间/头部的插入删除,时间复杂度为O(N) 2. 增容需要申请新空间,拷贝数据,释放旧空间.会有不小的消耗. 3. 增容一般是呈2倍的增长,势必会有一定的空

  • Java数据结构之双向链表图解

    双向链表(Doubly linked list) 什么是双向链表? 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱.所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点. 双向链表与单向链表的主要区别:  查找方向 : 单向链表的查找方向只能是一个方向,而双向链表可以向前或者向后查找.删除: 单向链表的删除需要借助辅助指针,先找到要删除节点的前驱,然后进行删除.           temp.next = temp.next

  • Java链表数据结构及其简单使用方法解析

    目录 认识链表结构 单向链表 双向链表 加深对链表结构的理解 实现单向和双向链表的反转 实现把链表中给定的值都删除 小结 认识链表结构 单向链表 单链表在内存中的表示: 可以看到,一个链表的节点包含数据域和指向下一个节点的引用,链表最后一个节点指向null(空区域). 我们可以根据这一定义,用Java语言表示一下单向链表的结构: public class Node { public int value; public Node next; public Node(int value) { thi

  • Java读取文件的简单实现方法

    本文实例讲述了Java读取文件的简单实现方法,非常实用.分享给大家供大家参考之用.具体方法如下: 这是一个简单的读取文件的代码,并试着读取一个log文件,再输出. 主要代码如下: import java.io.*; public class FileToString { public static String readFile(String fileName) { String output = ""; File file = new File(fileName); if(file.

  • Python文本处理简单易懂方法解析

    这篇文章主要介绍了Python文本处理简单易懂方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 自从认识了python这门语言,所有的事情好像变得容易了,作为小白,逗汁儿今天就为大家总结一下python的文本处理的一些小方法. 话不多说,代码撸起来. python大小写字符互换 在进行大小写互换时,常用到的方法有4种,upper().lower().capitalize() 和title(). str = "www.dataCASTLE.

  • Java HashMap两种简便排序方法解析

    这篇文章主要介绍了Java HashMap两种简便排序方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 HashMap的储存是没有顺序的,而是按照key的HashCode实现. key=手机品牌,value=价格,这里以这个例子实现按名称排序和按价格排序. Map phone=new HashMap(); phone.put("Apple",8899); phone.put("SAMSUNG",7000);

  • java常见log日志的使用方法解析

    目录 前言 1. Java.util.Logger 2. org.apache.logging.log4j 3. org.slf4j.Logger 前言 log日志可以debug错误或者在关键位置输出想要的结果 java日志使用一般有原生logger.log4j.Slf4j等 一般的日志级别都有如下(不同日志不一样的方法参数,注意甄别) 参数 描述 OFF.ON 不输出或者输出所有级别信息,通常使用在setLevel方法中 FATAL 致命错误 ERROR 错误error WARN 告警信息 I

  • Java线程池的简单使用方法实例教程

    目录 线程池使用场景? Java线程池使用 总结 线程池使用场景? java中经常需要用到多线程来处理一些业务,我们非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源.线程上下文切换问题.同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池比较合理,方便线程任务的管理.java中涉及到线程池的相关类均在jdk1.5开始的java.util.concurrent包中,涉及到的几个核心类及接口包括:Executor.Execut

  • Java链表元素查找实现原理实例解析

    链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的. 每一个链表都包含多个节点,节点又包含两个部分,一个是数据域(储存节点含有的信息),一个是引用域(储存下一个节点或者上一个节点的地址). 以下实例演示了使用 linkedlistname.indexof(element) 和 linkedlistname.Lastindexof(elementname) 方法在链表中获取元素第一次和最后一次出现的位置: Main.java 文件 import j

  • Java构建对象常用3种方法解析

    前言 当我们面对具有大量可选成员变量的 Java 类时,创建这些对象的最佳方法是什么?通常有三种方法: 伸缩构造函数,JavaBean模式和构建器模式. 构造函数 UserInfo userInfo1 = new UserInfo("felord.cn", 28); UserInfo xxxxxx = new UserInfo("felord.cn", "xxxxxx", 28); UserInfo xxxxxx1 = new UserInfo(

  • JAVA多线程间通讯常用实现方法解析

    如何实现线程间通讯,有如下三种方法: 1.使用Semaphore (信号量)类来控制线程的等待和释放 功能:三个线程 a .b .c 并发运行,b,c 需要 a 线程的数据怎么实现 分析:考虑到多线程的不确定性, 因此我们不能确保 ThreadA 就一定先于 ThreadB 和 ThreadC 前执行,就算 ThreadA先执行了, 我们也无法保证 ThreadA 什么时候才能将变量 num 给初始化完成. 因此我们必须让 ThreadB 和 Thread去等待 ThreadA 完成任何后发出的

  • java统计字符串单词个数的方法解析

    在一些项目中可能需要对一段字符串中的单词进行统计,我在这里写了一个简单的demo,有需要的同学可以拿去看一下. 不说废话了直接贴代码: 实现代码: /** * 统计各个单词出现的次数 * @param text */ public static void findEnglishNum(String text){ //找出所有的单词 String[] array = {".", " ", "?", "!"}; for (int

随机推荐