首页 > 其他分享 >LinkedList

LinkedList

时间:2024-07-13 23:19:31浏览次数:8  
标签:Node index return LinkedList next null 节点

  • 静态内部类Node
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;
    }
}

添加元素

public boolean add(E e) {
    linkLast(e);
    return true;
}
public void addLast(E e) {
    linkLast(e);
}
// 加到末尾
void linkLast(E e) {
    // 获取链表最后的一个节点
    final Node<E> l = last;
    // 创建一个新节点,并把前驱指针指向尾节点,后继指针置空
    final Node<E> newNode = new Node<>(l, e, null);
    // 新节点作为新的尾节点
    last = newNode;
    if (l == null)
        // 如果链表是空的,就把新节点设置为头节点
        first = newNode;
    else
        // 把原来的尾节点的后继指针指向新的尾节点
        l.next = newNode;
    // 链表长加一
    size++;
    modCount++;
}
public void addFirst(E e) {
    linkFirst(e);
}
// 加到开头
private void linkFirst(E e) {
    final Node<E> f = first;
    final Node<E> newNode = new Node<>(null, e, f);
    first = newNode;
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}

删除元素

  • remove():删除第一个节点
  • removeFirst():删除第一个节点
  • removeLast():删除最后一个节点
public E remove() {
    return removeFirst();
}
public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}
// 删除链表的第一个节点,并返回该节点的值
private E unlinkFirst(Node<E> f) {
    // assert f == first && f != null;
    // 获取被删除元素的节点值
    final E element = f.item;
    // 获取被删除元素的后继
    final Node<E> next = f.next;
    // 清空要删除的节点
    f.item = null;
    f.next = null; // help GC
    // 后继节点作为新的头节点
    first = next;
    if (next == null)
        // 没有后继节点,表示链表只有一个元素,把last也置空
        last = null;
    else
        // 后继节点的前驱指针原来是指向被删除的节点,现在置空
        next.prev = null;
    // 表长减一
    size--;
    modCount++;
    // 返回删除节点的值
    return element;
}
  • remove(int):删除指定位置的节点
public E remove(int index) {
    // 检查越界
    checkElementIndex(index);
    return unlink(node(index));
}

private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private boolean isElementIndex(int index) {
    return index >= 0 && index < size;
}
E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;
    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.item = null;
    size--;
    modCount++;
    return element;
}
  • remove(Object):删除指定元素的节点
// 先找到节点再调用unlink()
public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            // 元素为 null 的时候,必须使用 == 来判断
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            // 元素为非 null 的时候,要使用 equals 来判断
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

修改元素

public E set(int index, E element) {
    checkElementIndex(index);
    Node<E> x = node(index);
    E oldVal = x.item;
    // 替换值
    x.item = element;
    // 返回替换前的元素
    return oldVal;
}
// 获取链表中指定位置的节点
Node<E> node(int index) {
    // assert isElementIndex(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;
    }
}

查找元素

  • indexOf(Object):查找某个元素所在的位置
// 返回链表中首次出现指定元素的位置,如果不存在该元素则返回 -1
public int indexOf(Object o) {
    int index = 0;
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null)
                return index;
            index++;
        }
    } else {     
        
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            index++;
        }
    }
    return -1;
}
  • get(int):查找某个位置上的元素
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

序列化

private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException {
    // Write out any hidden serialization magic
    // 写入默认的序列化标记
    s.defaultWriteObject();

    // Write out size
    // 写入链表的节点个数
    s.writeInt(size);

    // Write out all elements in the proper order.
    // 按正确的顺序写入所有元素
    for (Node<E> x = first; x != null; x = x.next)
        s.writeObject(x.item);
}
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    // Read in any hidden serialization magic
    // 读取默认的序列化标记
    s.defaultReadObject();

    // Read in size
    // 读取链表的节点个数
    int size = s.readInt();

    // Read in all elements in the proper order.
    for (int i = 0; i < size; i++)
        // 读取元素并将其添加到链表末尾
        linkLast((E)s.readObject());
}
  • 遍历 LinkedList 的时候,千万不要使用 for 循环,要使用迭代器。

对比ArrayList

  • 当需要频繁随机访问元素的时候,例如读取大量数据并进行处理或者需要对数据进行排序或查找的场景,可以使用 ArrayList。

  • 当需要频繁插入和删除元素的时候,例如实现队列或栈,或者需要在中间插入或删除元素的场景,可以使用 LinkedList。

标签:Node,index,return,LinkedList,next,null,节点
From: https://www.cnblogs.com/sprinining/p/18300964

相关文章

  • 4-LinkedList底层结构和源码分析
    4-LinkedList底层结构和源码分析介绍汇总:LinkedList的全面说明LinkedList的底层操作机制LinkedList的运行重要步骤ArrayList和LinkedList比较1-LinkedList的全面说明LinkedList底层实现了双向链表和双端队列特点可以添加任意元素(元素可以重复),包括null线程不安全,......
  • 数据结构(Java):集合类LinkedList&集合类Stack
    1、集合类LinkedList1.1什么是LinkedListLinkedList的底层是一个双向链表的结构(故不支持随机访问):在LinkedList中,定义了first和last,分别指向链表的首节点和尾结点。每个节点中有一个成员用来存储数据,还有两个指针域next和prev分别存储下一个节点和上一个节点的地址。Link......
  • ArrayList和LinkedList的比较
    基本比较 底层结构增删效率改查效率ArrayList可变数组较低;数组扩容较高LinkedList双向链表较高,通过链表追加较低选择使用若改查操作多选择ArrayList增删操作多选择LinkedList通常程序中大部分操作为查询,因此通常使用ArrayList根据需求,效率优先的原则......
  • ArrayList、LinkedList
    区别ArrayList是实现了基于数组的数据结构,内存连续;LinkedList是基于链表结构。对于随机访问的get和set方法查询元素,ArrayList要优于LinkedList,因为LinkedList循环链表寻找元素。对于新增和删除操作add和remove,LinkedList比较高效,因为ArrayList要移动数据。优缺点ArrayLis......
  • 【初探Java之路 六 】集合1-ArrayList和LinkedList的使用与源码分析
    ......
  • 揭秘Java LinkedList:深度剖析、实战应用与设计灵感
    1.概述Java的LinkedList是java.util包下的一个类,它实现了List接口,并且提供了基于双向链表的数据结构。这意味着LinkedList中的元素可以按照它们的插入顺序进行有序的集合。由于其双向链表的特性,LinkedList在插入、删除元素时具有优秀的性能表现,而在访问元素时则相对较慢(尤......
  • ArrayList和LinkedList区别
    底层数据结构ArrayList是动态数组的数据结构实现。LinkedList是双向链表的数据结构实现。效率下标査询ArrayList按照下标査询的时间复杂度O(1)。LinkedList不支持下标查询。查找(未知索引)ArrayList需要遍历,链表也需要链表,时间复杂度都是O(n)。新增和删除ArrayL......
  • 【java】ArrayList和LinkedList的区别
    一、ArrayList和LinkedList的相同点ArrayList和LinkedList都是实现了List接口的容器类,用于存储一系列的对象引用,他们都可以对元素的增删改查进行操作。ArrayList、LinkedList、Vector和Stack是List的四个实现类,List是一个接口,它继承与Collection接口,代表有序的队列。其中Vector......
  • JDK源码分析-LinkedList
    概述相较于ArrayList,LinkedList在平时使用少一些。LinkedList内部是一个双向链表,并且实现了List接口和Deque接口,因此它也具有List的操作以及双端队列和栈的性质。双向链表的结构如下:它除了作为List使用,还可以作为队列或者栈来使用。publicclassLinkedList<E>......
  • linkedlist
    单链表1.单链表的管理结构/********************************************************************* DataType_t data 存放数据* structLinkedList *next 存放下一个元素的地址********************************************************************/typedefstruc......