Java数据结构之链表的原理及LinkedList的部分源码剖析

一、为什么要学习数据结构?

  • 做为一名程序员,不管你是用什么编程语言,数据结构是取底层的东西。就相当于盖楼的地基一样,地基做不好,上边再好也没有用。
  • 在高级语言中,一般会对这些基础的数据结构进行封装,我们学要学习这些基础的东西吗?
    当然是的,只有知道这些基础的东西,我们才能更好地使用语言封装好的api。举个最简单的例子,在Java中,List的实现类有ArrayList,LinkedList,Vector,你知道在什么情况下用哪个效率最高吗?只有知道其底层源才能更好地利用。
  • 如何学习数据结构?
    可以看书,看视频,看博客...但是最重要的一点,一定要自己用手去敲,比如自己去写一个链表,自己去模拟一个栈,一个队列等。可能你写的没有在语言中封装的那么用好,但是你一定会收获颇丰的。
  • 视频书籍哪里找?
    微信关注公众号“小鱼与Java”,后台回复数据结构,有我已经整理好的资料。

    二、什么是数据和数据结构?

    数据就是一些或某部分有关系的内容的组合。
    数据结构是数据的存储方式。从不同的角度来讨论,分类如下:
    |按逻辑结构分|按物理结构分|
    |-|-|
    |线性结构|顺序存储结构|
    |集合结构|链式存储结构|
    |树形结构||
    |图形结构||

  • 逻辑结构,即按照人们的思维逻辑对其分类。
  • 物理结构就是数据在磁盘上的存储方式,可以是一整块存储区域,也可以是不同的存储块(但是它们之前有关系,所以就划分为一组数据)。

二、物理结构分法的分类

顺序存储

就是在磁盘上连续存储的,在Java中就是数组,它从第一个索引开始,所有的数据都是紧跟其后的。

链式存储

这些数据(称为数据元素,是不可再分隔的)在磁盘上是分开存储的,只是因为它们之间有一些关系,所以我们就将其联系到了一起,组成了一种数据结构————链表。

代码实现

对于顺序存储的来说,在Java中就是数组,所以不做代码实现。

对于链式存储,就是在其中任何一个元素,除了存储它本身的数据外,还存储另一个或多个数据元素的存储位置。主要分类有下:

单向链表:

就是在这个元素中,除了存储它自身的数据还存储了它的下一个数据

 class LinkedNode<T> {
        private T data;
        private LinkedNode<T> next;

        public LinkedNode(T data) {
            this.data = data;
            //在构建这个时,我们就让它的下一个指针为null
            next = null;
        }
    }

接下来写一个管理它的类,我们写一个add(T t)方法,就是插入到最后

public class MyLinked<T> {
    /**
     * 用一个头指针来表示这个链表的头
     */
    private LinkedNode<T> first;

    public MyLinked() {
    }

    /**
     * 提供一个有参构造方法
     *
     * @param t
     */
    public MyLinked(T t) {
        this.first = new LinkedNode<>(t);
        first.next=null;
    }

    /**
     * 往链表中添加元素,默认是添加到最后的
     *
     * @param t
     */
    public void add(T t) {
        if (first == null) {
            first = new LinkedNode<>(t);
        } else {
            LinkedNode herd = first;
            while (herd.next != null) {
                herd = herd.next;
            }
            //当从这个循环中出来的时候,这个herd.next就是null,也就是说这个herd就是这个链表的最后一个元素
            herd.next = new LinkedNode(t);
        }
    }
}

我们写的这个add方法,是要遍历整个链表来做此操作。
以上就是最简单的一个链表类了,我们使用了泛型为了让其更加通用。

双向链表


双向链表就是在这个链表中存储了自身的数据,还存储了它的前一个和后一个数据的地址。

class LinkedNode<T> {
        private T data;
        private LinkedNode<T> prev;
        private LinkedNode<T> next;

        public LinkedNode(T data) {
            this.data = data;
            this.prev = null;
            this.next = null;
        }
    }

循环链表表

  • 它也分为单向循环链表和双向循环链表
  • 在单向链表中,最后一个元素的next不是null,而是指向第一个元素
  • 在双向链表中它的第一个元素的prev是最后一个元素,最后一个元素的next是第一个元素。
  • 因为它是双向循环的,所以在效率上要比单向的下快一些。
    比如,这个链表的长度是50,我们要找第48个元素。如果是单身的话,它只能从0->1->2.....->48,这样要遍历前48个元素;如果是双向的话,我们只需要50->49->48,三次就够了。
  • Java中的LinkedList就是底层就是双向循环链表。我们来瞅一下它的源码:
private static class Node<E> {
       E item;
       Node<E> next;
       Node<E> prev;

       Node(Node<E> prev, E element, Node<E> next) {
           this.item = element;
           this.next = next;
           this.prev = prev;
       }
   }

我们主要看一下,它的最基本的add方法,来体验一个它的魅力

  • 它有add(E e)和add(int index, E e)两个方法

add(E e)就是添加到链表的最后,最终调用的方法如下:

void linkLast(E e) {
    //将当前的最后一个节点保存下来
        final Node<E> l = last;
    //构造一个新的节点对象
        final Node<E> newNode = new Node<>(l, e, null);
    //将这个链表的last指向这个新元素
        last = newNode;
        if (l == null){
    //这个条件就是说,此时链表为空。因为l是在添加之前的last,如果这个链表为空,last肯定是空的
            first = newNode;
        }else{
            l.next = newNode;
    }
        size++;//当前的链表大小++
        modCount++;//这个是用来记录这个链表的操作次数,对这个链表进行的任何操作,这个都会++
    }

上边的构造方法

    Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }

这个插入到时最后的链表并没有去遍历一个整个链表,而是将last.next指向了这个新的节点

add(int index, E e)插入到指定位置
这个最重要的就是利用循环列表来找到这个index是在前半边还是后半边,主要寻找的代码如下:

Node<E> node(int index) {
        if (index < (size >> 1)) {
    //上边的>>就是取半,除以2
            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;
        }
    }

可以看到,它判断了所在的部分进行了不同的遍历方式,就是对二分法的一次简利用

  • 当然,它内部还写了迭代等其他的方法,感兴趣的可以自己看一下。

原文地址:https://www.cnblogs.com/Lyn4ever/p/12105106.html

时间: 2024-08-28 15:35:34

Java数据结构之链表的原理及LinkedList的部分源码剖析的相关文章

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 概要  和学习ArrayList一样,接下来呢,我们先对LinkedList有个整体认识,然后再学习它的源码:最后再通过实例来学会使用LinkedList.内容包括:第1部分 LinkedList介绍第2部分 LinkedList数

Java HashMap实现原理 源码剖析

HashMap是基于哈希表的Map接口实现,提供了所有可选的映射操作,并允许使用null值和null建,不同步且不保证映射顺序.下面记录一下研究HashMap实现原理. HashMap内部存储 在HashMap内部,通过维护一个 瞬时变量数组table (又称:桶) 来存储所有的键值对关系,桶 是个Entry对象数组,桶 的大小可以按需调整大小,长度必须是2的次幂.如下代码: /** * 一个空的entry数组,桶 的默认值 */ static final Entry<?,?>[] EMPTY

转:【Java集合源码剖析】LinkedList源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/35787253   您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票,谢谢! 投票地址:http://vote.blog.csdn.net/Article/Details?articleid=35568011 LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使

【Java集合源码剖析】LinkedList源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/35787253 LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全的,只在单线程下适合使用. LinkedList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了Cloneable接口,能被克隆. Linked

【Java集合源码剖析】LinkedHashmap源码剖析

LinkedHashMap简介 LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加入了一个双向链表的头结点,将所有put到LinkedHashmap的节点一一串成了一个双向循环链表,因此它保留了节点插入的顺序,可以使节点的输出顺序与输入顺序相同. LinkedHashMap可以用来实现LRU算法(这会在下面的源码中进行分析). LinkedHashMap同样是非线程安全的,只在单线程环境下使用. LinkedHashMap源码剖析 LinkedHashM

【源码】LinkedList源码剖析

//----------------------------------------------------------- 转载请注明出处:http://blog.csdn.net/chdjj by Rowandjj 2014/8/8 //---------------------------------------------------------- 注:以下源码基于jdk1.7.0_11 上一篇我们分析了ArrayList,今天我们再来看下LinkedList. 首先上一幅框架图: Lin

转:【Java集合源码剖析】LinkedHashmap源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/37867985   前言:有网友建议分析下LinkedHashMap的源码,于是花了一晚上时间研究了下,分享出此文(这个系列的最后一篇博文了),希望大家相互学习.LinkedHashMap的源码理解起来也不难(当然,要建立在对HashMap源码有较好理解的基础上). LinkedHashMap简介 LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加

LinkedList源码剖析

LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全的,只在单线程下适合使用. LinkedList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了Cloneable接口,能被克隆. LinkedList源码剖析 LinkedList的源码如下(加入了比较详细的注释): 1 package java.util; 2 3

【Java集合源码剖析】HashMap源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955 HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap. HashMap 实现了Serializable接口,因此它支持序列化,