zoukankan      html  css  js  c++  java
  • Java学习笔记--链表

    心在山东身在吴,飘蓬江海漫嗟吁。

    他时若遂凌云志, 敢笑黄巢不丈夫。

                   ——水浒传

    先上源代码,LinkedList类:

     1 private static class Node<E> {
     2         E item;
     3         Node<E> next;
     4         Node<E> prev;
     5 
     6         Node(Node<E> prev, E element, Node<E> next) {
     7             this.item = element;
     8             this.next = next;
     9             this.prev = prev;
    10         }
    11     }

    Java链表中定义了一个内部类Node类,"node"是节点的意思.链表的基本元素是节点,(双向链表)每个节点包含三个成员,分别是item:数据,next:指向链表下一个元素的指针,prev:指向上一个元素的指针

    先看一下C中的链表:

    头指针变量保存了一个地址,它指向一个变量No.1,No.1中又保存了一个指针,它指向No.2,以此类推,直到No.X中保存的地址指向No.last,图中最后一项为No.3,它指向NULL。

    双向链表每个元素中又加入了prev指针。

    双向链表图:

    但是java中没有指向内存地址的指针,那么如何实现链表呢?

    再看Java源代码:

     1  transient int size = 0;
     2 
     3     /**
     4      * Pointer to first node.
     5      * Invariant: (first == null && last == null) ||
     6      *            (first.prev == null && first.item != null)
     7      */
     8     transient Node<E> first;
     9 
    10     /**
    11      * Pointer to last node.
    12      * Invariant: (first == null && last == null) ||
    13      *            (last.next == null && last.item != null)
    14      */
    15     transient Node<E> last;
    16 
    17     /**
    18      * Constructs an empty list.
    19      */
    20     public LinkedList() {
    21     }
    22 
    23     /**
    24      * Constructs a list containing the elements of the specified
    25      * collection, in the order they are returned by the collection's
    26      * iterator.
    27      *
    28      * @param  c the collection whose elements are to be placed into this list
    29      * @throws NullPointerException if the specified collection is null
    30      */
    31     public LinkedList(Collection<? extends E> c) {
    32         this();
    33         addAll(c);
    34     }
    View Code

    LinkedList类定义了两个临时节点first和last,两个构造器.一个无参构造和一个带参构造,无参构造创建链表实例,带参构造可以把一个集合整体加入链表

    下面看一下add()方法:

    1 public boolean add(E e) {
    2         linkLast(e);
    3         return true;
    4     }
     1 void linkLast(E e) {
     2         final Node<E> l = last;
     3         final Node<E> newNode = new Node<>(l, e, null);
     4         last = newNode;
     5         if (l == null)
     6             first = newNode;
     7         else
     8             l.next = newNode;
     9         size++;
    10         modCount++;
    11     }

    画图:

    初始链表为空的情况:prev和next都是null,item是e,这里假设传入的数据是No.1,No.2...;

    此时再加入元素:

    加入第三个元素:

    加入第四个元素:

    以此类推。。。

    可见java中链表是用引用变量指向节点来代替C中的指针变量指向内存地址。

    每次加入新的元素,只需要将原last元素的next指向新加入元素的实例,把新加入元素的prev指向原last元素的实例。

    再看下add(int index, E element)方法:

    1 public void add(int index, E element) {
    2         checkPositionIndex(index);
    3 
    4         if (index == size)
    5             linkLast(element);
    6         else
    7             linkBefore(element, node(index));
    8     }
     1 Node<E> node(int index) {
     2         // assert isElementIndex(index);
     3 
     4         if (index < (size >> 1)) {
     5             Node<E> x = first;
     6             for (int i = 0; i < index; i++)
     7                 x = x.next;
     8             return x;
     9         } else {
    10             Node<E> x = last;
    11             for (int i = size - 1; i > index; i--)
    12                 x = x.prev;
    13             return x;
    14         }
    15     }

    这里假定传入的index比size小,

    node(int index)用很简单的方式返回了位置为index的Node实例,然后执行linkBefore(E e, Node<E> succ)方法

     1 void linkBefore(E e, Node<E> succ) {
     2         // assert succ != null;
     3         final Node<E> pred = succ.prev;
     4         final Node<E> newNode = new Node<>(pred, e, succ);
     5         succ.prev = newNode;
     6         if (pred == null)
     7             first = newNode;
     8         else
     9             pred.next = newNode;
    10         size++;
    11         modCount++;
    12     }

    把newNode 的prev 指向原位置节点的prev节点,next 指向原位置节点;

    把原位置节点的prev指向newNode;

    最后把原位置节点的prev节点(如果有)的next指向newNode;如果没有,则newNode为第一个节点,原位置节点变为第二个节点;

    此处省略其他链表方法...原理是一样的.

     

  • 相关阅读:
    在Unix上使用管道压缩exp导出文件
    自制CPU的黑暗历程一
    Error C1189: #error: Please use the /MD switch for _AFXDLL builds
    Redis乐观锁解决高并发抢红包的问题
    PHP分页类
    汇编基础——使用nasm和bochs学习汇编
    数据同步工具DBsync
    完成端口的一些教程
    sdf
    (转)C#(WIN FORM)两个窗体间LISTVIEW值的修改
  • 原文地址:https://www.cnblogs.com/tomasman/p/6815173.html
Copyright © 2011-2022 走看看