Data Structures | 连载 02 - 链表 LinkedList 实现(上)

简介: Data Structures | 连载 02 - 链表 LinkedList 实现

一、链表 LinkedList

由于数组申请的内存是连续的,当数组的容量非常大时会造成内存空间的浪费,而且一旦容量到达临界点需要重新申请一块更大的内存,如果此时没有连续的内存空间供使用,那么将会造成数据的丢失。而链接是一种链式存储的线性表,所有元素的内存地址不一定是连续的,可以完美解决空间浪费的缺点

49bf80ac295041f8b66f9622f4a30563_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

0 是头节点,3 是尾节点

一个链表中肯定至少包含两个成员变量,一个是链表的长度 size,另一个是链表的节点 Node,而根据图示每个 Node 节点中肯定至少包含节点中的元素以及下一个节点 Node。

二、链表LinkedList实现

创建一个新的 Module 名为LinkedList,在 entity 包中新增一个 Node 实体类

public class Node<T> {
    private T element;
    private Node<T> next;
    public Node(T element, Node<T> next) {
        this.element = element;
        this.next = next;
    }
    public T getElement() {
        return element;
    }
    public void setElement(T element) {
        this.element = element;
    }
    public Node<T> getNext() {
        return next;
    }
    public void setNext(Node<T> next) {
        this.next = next;
    }
}
复制代码

在 linked 包中定义 LinkedList 类,链表的接口和动态数组都是线性表,因此他们所包含的接口是一致的,可以定义一个上层接口 List<T>。

在 List 接口中定义线性表的接口,接口中只声明,不实现,但是链表和动态数组确实有些接口的实现是相同的,如 size()、isEmpty() 等,针对这种情况可以再定义一个 AbstractList 抽象类实现 List 接口,将一些相同的代码方法在 AbstractList 中,让 LinkedList 和 ArrayList 都继承这个抽象类。

977fa8de4c4440abb5983e7d3d9f2e22_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

List 接口

public interface List<T> {
    public static final int ELEMENT_NOT_FOUND = -1;
    void clear();
    int size();
    boolean isEmpty();
    boolean contains(T element);
    void add(T element);
    T get(int index);
    T set(int index, T element);
    void add(int index, T element);
    T remove(int index);
    int indexOf(T element);
}
复制代码

AbstractList 抽象类的定义

public abstract class AbstractList<T> implements List<T> {
    public int size;
    public int size(){
        return size;
    }
    public boolean isEmpty(){
        return size == 0;
    }
    public boolean contains(T element){
        return indexOf(element) != ELEMENT_NOT_FOUND;
    }
    public void add(T element) {
        add(size, element);
    }
}
复制代码

clear 接口的实现,首先 size=0,然后 first 指向空即可

1cbab75444ff4828bda52ff5dfaeb740_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

@Override
public void clear() {
    size = 0;
    first = null;
}
复制代码

add (int index, T element) - 指定位置添加元素

image.png

将55这个节点添加到索引为2的位置上,需要先将要增加的元素将55这个节点添加到索引为2的位置上,然后找到索引2的前一个元素,即索引为1的元素,让索引为1的元素即22指向新增加的元素(1号线),这样新增加的元素的索引就变成2,原来索引为2的元素索引变为3,整个列表长度增加1。新增元素完成。

image.png

新增一个方法,获取指定索引位置的元素,链表不是顺序排列的,无法通过list[index]方式快速获取指定索引对应的元素。

//获取指定索引对应的元素
public Node getNodeByIndex(int index){
    CheckUtils.checkIndex(index,size);
    Node<T> node = first;
    for (int i = 0; i < index; i++) {
        node = node.getNext();
    }
    return node;
}
复制代码

get方法就可以通过调用getNodeByIndex方法获取指定索引的Node,在去通过Node调用getElement方法获取该节点的元素

@Override
public T get(int index) {
    return (T) getNodeByIndex(index).getElement();
}



相关文章
|
3月前
|
Java
LinkedList与链表(有源码剖析)(一)
LinkedList与链表(有源码剖析)
37 0
|
1月前
|
设计模式 测试技术
在实现链表的代码中,为什么要使用`Node`类而不是直接在`LinkedList`类中定义节点?
在实现链表的代码中,为什么要使用`Node`类而不是直接在`LinkedList`类中定义节点?
21 1
|
1月前
|
算法 Java 索引
【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)
【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)
31 0
|
1月前
|
存储 算法 Java
【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)
【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)
43 0
|
6月前
|
存储 安全 Java
【JavaSE专栏49】Java集合类LinkedList解析,链表和顺序表有什么不同?
【JavaSE专栏49】Java集合类LinkedList解析,链表和顺序表有什么不同?
|
2月前
|
存储
数据结构 模拟实现LinkedList双向不循环链表
数据结构 模拟实现LinkedList双向不循环链表
57 1
|
2月前
|
存储
数据结构 模拟实现LinkedList单向不循环链表
数据结构 模拟实现LinkedList单向不循环链表
33 0
|
3月前
|
存储 Java 容器
LinkedList与链表(有源码剖析)(二)
LinkedList与链表(有源码剖析)(二)
31 0
|
6月前
|
机器学习/深度学习 存储
链表oj题 && 链表与LinkedList && 栈的概念 && 队列的概念 && 树和二叉树
链表oj题 && 链表与LinkedList && 栈的概念 && 队列的概念 && 树和二叉树
113 38
|
7月前
|
存储 Java
【数据结构】LinkedList与链表
【数据结构】LinkedList与链表
40 0