1. 概述

链表是一种数据结构,在内存中通过节点记录内存地址而相互链接形成一条链的储存方式。链表的插入和删除都比较快,缺点是查找比较慢。除非需要频繁的通过下标来随机访问数据,否则在很多使用数组的地方都可以用链表代替。相比数组而言,链表在内存中不需要连续的区域,只需要每一个节点都能够记录下一个节点的内存地址,通过引用进行查找,因此链表增删操作时间消耗很小,而查找遍历时间消耗很大。

2. 链表的分类

链表常用的有 3 类: 单链表、双向链表、循环链表。

单链表:

单链表是链表中结构最简单的,是一种线性表,实际上是由节点(Node)组成的。一个单链表的节点(Node)分为两个部分,第一个部分(data)保存或者显示关于节点的信息,另一个部分存储下一个节点的地址。最后一个节点存储地址的部分指向空值。

单向链表的实现:

package cn.zzw.singlelink;/*** @author 鹭岛猥琐男* @create 2019/8/13 5:48*/
public class SingleLink<T> {private Node first;private Node last;private int size;private class Node<T> {private Node next;private T data;Node(T data, Node next) {this.data = data;this.next = next;}}/**   向链表头部添加元素*/public void push(T t) {Node f = first;Node newNode = new Node(t, f);//因为是向链表头部添加元素,所以第一个节点变成新的节点first = newNode;//如果原来的第一个节点是空,则原链表为空,添加后,链表仅有一个节点,最后一个节点也是新添加的节点if (f == null) {last = newNode;}size++;}/**  向链表的尾部添加元素*/public void add(T t) {Node l = last;Node newNode = new Node(t, null);last = newNode;if (l == null) {first = newNode;} else {l.next = newNode;}size++;}/*** 打印结点*/public void printLink() {Node curNode = first;while (curNode != null) {System.out.print(curNode.data + " ");curNode = curNode.next;}System.out.println();}/** 返回链表的长度*/public int getSize() {return size;}/**  删除指定位置的节点*/public void remove(int index) {//先判断index是否合法if (index < 0 || index >= size) {throw new IndexOutOfBoundsException();}//当需要删除的是头节点,直接将头节点指向下一个节点if (index == 0) {Node removeNode = first;first = removeNode.next;} else {Node prev = first;for (int i = 0; i < index - 1; i++) {//prev此时指向的是被删除节点的前一个位置prev = prev.next;}//需要被删除的节点Node removeNode = prev.next;prev.next = removeNode.next;removeNode.next = null;}size--;}/**  获取指定位置的节点的值*/public T get(int index) {//先判断index是否合法if (index < 0 || index >= size) {throw new IndexOutOfBoundsException();}Node<T> x = first;for (int i = 0; i < index; i++)x = x.next;return x.data;}
}

测试类:

package cn.zzw.singlelink;/*** @author 鹭岛猥琐男* @create 2019/8/13 5:48*/
public class TestLink
{public static void main(String[] args){SingleLink<Integer> singleLink =new SingleLink();singleLink.add(8);singleLink.add(9);singleLink.push(1);singleLink.push(2);System.out.println("链表的长度:"+singleLink.getSize());//按照上面的添加顺序,链表的排序应该是:2,1,8,9singleLink.printLink();//获取指定节点的值Integer index0 = singleLink.get(0);Integer index1 = singleLink.get(1);System.out.println("获取头节点的值:"+index0);System.out.println("获取节点1的值:"+index1);//删除指定位置的节点singleLink.remove(3);System.out.println("删除节点后的列表:");singleLink.printLink();System.out.println("删除后链表的长度:"+singleLink.getSize());}
}

测试结果:

链表的长度:4
2 1 8 9
获取头节点的值:2
获取节点1的值:1
删除节点后的列表:
2 1 8
删除后链表的长度:3

双向链表:

双向链表即是这样一个有序的结点序列,每个节点分为三个部分,一个部分(data)保存或者显示关于节点的信息,另一个部分存储下一个节点的地址,还有一部分存储上一个节点的地址。第一个节点的存储的上一个节点的地址为空值,最后一个节点存储的下一个节点的地址为空值。双向链表是可以从两个方向进行遍历的。

双向链表的实现:

package cn.zzw.doublelink;public class DoubleLink<E> {private Node first;private Node last;private int size;/**   与单向链表相比,多了指向前一个节点的prev*/private class Node<E> {private E data;private Node<E> prev;private Node next;Node(E data, Node prev, Node next) {this.data = data;this.prev = prev;this.next = next;}}/**  向链表的尾部添加元素*/public boolean add(E e) {linkLast(e);return true;}void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<E>(e, l, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;}/**   向链表头部添加元素*/public void push(E e) {final Node<E> f = first;final Node<E> newNode = new Node<>(e, null, f);//因为是向链表头部添加元素,所以第一个节点变成新的节点first = newNode;//如果原来的第一个节点是空,则原链表为空,添加后,链表仅有一个节点,最后一个节点也是新添加的节点if (f == null) {last = newNode;} else {f.prev = newNode;}size++;}/*** 打印结点*/public void printLink() {Node curNode = first;while (curNode != null) {System.out.print(curNode.data + " ");curNode = curNode.next;}System.out.println();}/** 返回链表的长度*/public int getSize() {return size;}/**  删除指定位置的节点,并返回删除节点的值*/public E remove(int index) {//先判断index是否合法if (index < 0 || index >= size) {throw new IndexOutOfBoundsException();}return unlink(node(index));}/**  查找指定位置的节点*/Node<E> node(int index) {if (index < (size >> 1)) {Node<E> x = first;for (int i = 0; i < index; i++)x = x.next;return x;} else {Node<E> x = last;for (int i = size - 1; i > index; i--)x = x.prev;return x;}}E unlink(Node<E> x) {final E element = x.data;final Node<E> next = x.next;final Node<E> prev = x.prev;if (prev == null) {first = next;} else {prev.next = next;x.prev = null;}if (next == null) {last = prev;} else {next.prev = prev;x.next = null;}x.data = null;size--;return element;}/**  获取指定位置的节点的值*/public E get(int index) {//先判断index是否合法if (index < 0 || index >= size) {throw new IndexOutOfBoundsException();}return node(index).data;}
}

测试类:

package cn.zzw.doublelink;import cn.zzw.singlelink.SingleLink;/*** @author 鹭岛猥琐男* @create 2019/8/13 5:48*/
public class TestDoubleLink
{public static void main(String[] args){DoubleLink<Integer> doubleLink =new DoubleLink();doubleLink.add(8);doubleLink.add(9);doubleLink.push(1);doubleLink.push(2);System.out.println("链表的长度:"+doubleLink.getSize());//按照上面的添加顺序,链表的排序应该是:2,1,8,9doubleLink.printLink();//获取指定节点的值Integer index0 = doubleLink.get(0);Integer index1 = doubleLink.get(1);System.out.println("获取头节点的值:"+index0);System.out.println("获取节点1的值:"+index1);//删除指定位置的节点doubleLink.remove(3);System.out.println("删除节点后的列表:");doubleLink.printLink();System.out.println("删除后链表的长度:"+doubleLink.getSize());}
}

测试结果:

链表的长度:4
2 1 8 9
获取头节点的值:2
获取节点1的值:1
删除节点后的列表:
2 1 8
删除后链表的长度:3

Java自带的集合包中有实现双向链表,路径是:java.util.LinkedList,以上双向链表的实现,就是参考它的源码来实现的。

循环链表:

循环链表指的是在单向链表和双向链表的基础上,将两种链表的最后一个结点指向第一个结点从而实现循环。

循环列表分为单向循环链表和双向循环链表,循环链表和单向列表以及双向链表的区别在于,最后一个结点是否指向第一个结点,这里就不再展开了。

Java数据结构:链表相关推荐

  1. 猴子选大王 java_基于java数据结构链表写的猴子选大王

    [实例简介] 基于java数据结构链表写的猴子选大王,其实就是一个约瑟夫环问题,采用java数据结构链表写的.有点小问题.当输入一只猴子,报数为1时删除会出错.没有实现动态显示猴子的添加和删除. [实 ...

  2. Java数据结构链表面试题 作者:哇塞大嘴好帥(哇塞大嘴好帅) --持续更新

    作者:哇塞大嘴好帥(哇塞大嘴好帅) Java数据结构链表面试题 4.1.查询链表有效数据个数 //判断有效数据个数 public int validDate(){//创建临时变量NodeDate no ...

  3. java数据结构-链表详解

    文章目录 1.数据结构-链表详解 1.1单链表 1.1.1单链表节点的尾部添加 1.1.2单链表节点的自动排序添加 1.1.3单链表节点的修改 1.1.4单链表节点的删除 1.2单链表面试题 1.2. ...

  4. Java数据结构--链表

    public interface Predecessor<E> {//定义接口 用于实现多态public ListNode<E> getNext(); public void ...

  5. java数据结构 -链表 -获取有效节点个数,单链表中倒数k个节点

    // 1.获取到单链表的节点的个数(如果有头结点,不统计头结点)public static int getLength(HeroNode head){if (head.next == null){re ...

  6. 【Java数据结构[链表--单向链表]】

    单向链表 链表是以节点的方式来存储的,是链式存储 每个节点包含一个数据域用来保存当前节点的数据,一个next域用于指向下一个节点 单链表结构示意图: 单链表内存示意图: 代码实现: //链表 clas ...

  7. Java数据结构——链表

    目录 方法一 方法二 问题一:求单链表中有效节点的个数 问题二:查找单链表中的倒数第k个结点 问题三:单链表的反转 问题三:从尾到头打印单链表 [方式1:反向遍历 . 方式2:Stack栈] 问题四: ...

  8. Java数据结构 -- 链表

    生活中的链表 链表其实是一个一环扣一环的东西,最简单明了的就是我们的链子了,它就是一个一环扣一环的东西 链表介绍 链表在内存中的图解可以用下图来表示 链表是以节点的方式存储,是一个链式存储. 每个节点 ...

  9. Java数据结构和算法(七)——链表

    前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷.在无序数组中,搜索性能差,在有序数组中,插入效率又很低,而且这两种数组的删除效率都很低,并且数组在创建后,其大小是固定了,设置的过大会造 ...

  10. java双链表基本方法_Java数据结构之双端链表原理与实现方法

    本文实例讲述了Java数据结构之双端链表原理与实现方法.分享给大家供大家参考,具体如下: 一.概述: 1.什么时双端链表: 链表中保持这对最后一个连点引用的链表 2.从头部插入 要对链表进行判断,如果 ...

最新文章

  1. I00031 Look-and-say sequence
  2. ESXI开启snmp协议方法
  3. C++对C的加强之变量检测增强
  4. mysql-workbench连接数据库
  5. dokcer mysql修改编码_默认支持utf8编码的mysql docker镜像
  6. “成长”必经之路:越努力越幸运
  7. 阿里 异构数据 mysql_异构数据库迁移
  8. opensource项目_最佳Opensource.com:教程
  9. sql语句分析是否走索引_mysql sql语句执行时是否使用索引检查方法
  10. 代码,代码,多少梦想葬身于汝!
  11. QT入门(一)——QT概述
  12. 基于python的OCR中文识别教程
  13. 2020抖音最新版去水印方法
  14. 研究B站个人收藏中已失效的视频
  15. alios下载_AliOS-Things ESP8266 编译下载
  16. 爬取起点小说网免费小说
  17. 如何保证用log4J 写log 的时间和系统设置的timezone 保持一致
  18. 使用Excel制作一个动态计划表
  19. 逆向笔记 | 破解极域学生端密码并实现窗口化屏幕广播
  20. STM32移植STemwin

热门文章

  1. java字符串长度_Java中String字符串的最大长度?
  2. java华容道教程_Java初学之华容道游戏
  3. 覆盖率测试工具(coverage tool)
  4. kubernetes强制删除namespace
  5. 使用mvc模式读取服务器上的文件,ASP.NET MVC之读取服务器文件资源的两种方式
  6. Python的数据类型3-列表list
  7. Android源码剖析之Framwork层后记篇(硬件消息传递、apk管理、输入法框架、编译过程)
  8. linux 查看防火墙是否开启
  9. 【人工智能】智能家居控制器中的智能智能家居控制系统
  10. linux配置dns三种方式