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

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

set方法可以先通过获取原来index位置的节点,通过Node的getElement方法获取节点上的元素,在通过Node的setElement方法设置指定的元素到指定索引的节点上。

@Override
public T set(int index, T element) {
    Node<T> node = getNodeByIndex(index);
    T oldElement = node.getElement();
    node.setElement(element);
    return oldElement;
}
复制代码
@Override
public void add(int index, T element) {
    CheckUtils.checkIndex4Add(index,size);
    // 获取指定索引的前一个元素
    Node<T> prevNode = getNodeByIndex(index - 1);
    Node<T> nextNode = getNodeByIndex(index);
    // 创建新的Node
    Node<T> newNode = new Node();
    newNode.setElement(element);
    // 新创建的Node指向下一个元素
    newNode.setNext(nextNode);
    // 指定索引前的元素指向新加入的元素
    prevNode.setNext(newNode);
    size++;
}
复制代码

remove (int index) - 删除元素

@Override
public T remove(int index) {
    CheckUtils.checkIndex(index,size);
    Node<T> node = first;
    if (index == 0){
        first.next = first.next.next;
    } else {
        Node<T> prev = getNodeByIndex(index - 1);
        node = prev.next;
        prev.next = node.next;
    }
    size --;
    return node.getElement();
}
复制代码

重写toString方法

@Override
public String toString() {
    StringBuilder string = new StringBuilder();
    string.append("LinkedList {size=").append(size).append(", [");
    Node<T> node = first;
    for (int i = 0; i < size; i++) {
        if (i != 0) {
            string.append(", ");
        }
        string.append(node.element);
        node = node.next;
    }
    string.append("]}");
    return string.toString();
}
复制代码

创建LinkedListTest,增加测试方法

public class LinkedListTest {
    List<Integer> linkedList = new LinkedList<>();
    @Before
    public void init() {
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        linkedList.add(4);
        System.out.println("初始化:" + linkedList);
    }
    @Test
    public void add() {
        linkedList.add(11);
        linkedList.add(34);
        linkedList.add(78);
        linkedList.add(1,99);
        System.out.println("执行add方法后," + linkedList);
    }
    @Test
    public void remove(){
        linkedList.remove(0);
        System.out.println("执行remove方法删除索引0位置的元素后," + linkedList);
        linkedList.remove(2);
        System.out.println("再次执行remove方法删除索引2位置的元素后," + linkedList);
    }
    @Test
    public void indexOf(){
        int i = linkedList.indexOf(3);
        System.out.println("执行indexOf,元素3位置的索引为:" + i);
    }
}
复制代码

执行LinkedListTest测试类

image.png

虚拟头节点

为了统一所有节点的处理逻辑,可以在链表最前面增加一个虚拟的头节点,不存储任何数据

image.png

有了虚拟头节点,那么链表中的first就是虚拟头节点,虚拟头节点无论链表是否为空都存在,需要增加一个构造方法。

// 增加带有虚拟头节点的构造函数,不管链表中是否存在元素,都有虚拟头节点
public LinkedListWthDummyHead(){
    first = new Node<T>(null,null);
}
复制代码
//获取指定索引对应的元素
public Node getNodeByIndex(int index){
    CheckUtils.checkIndex(index,size);
    // 从first的next节点开始寻找,虚拟头节点的下一个节点开始
    Node<T> node = first.next;
    for (int i = 0; i < index; i++) {
        node = node.getNext();
    }
    return node;
}
复制代码

有了虚拟头节点之后,链表中的每一个节点都有前一个节点,没有虚拟头节点时索引为0的节点是没有前一个节点的,所有在获取指定位置的前一个节点时都要进行判断当前节点是否是第一个节点,所以可以对这些代码作统一的修改,无需再判断是否是第一个节点。

修改add方法

@Override
public void add(int index, T element) {
    CheckUtils.checkIndex4Add(index,size);
    Node<T> prev = index == 0 ? first : getNodeByIndex(index - 1);
    prev.next = new Node<>(element,prev.next);
    size++;
}
复制代码

修改remove方法

@Override
public T remove(int index) {
    CheckUtils.checkIndex(index,size);
    Node<T> prev = index == 0 ? first : getNodeByIndex(index - 1);
    Node<T> node = prev.next;
    prev.next = node.next;
    size --;
    return node.element;
}
复制代码

修改toString()方法

@Override
public String toString() {
    StringBuilder string = new StringBuilder();
    string.append("LinkedList {size=").append(size).append(", [");
    Node<T> node = first.next;
    for (int i = 0; i < size; i++) {
        if (i != 0) {
            string.append(", ");
        }
        string.append(node.element);
        node = node.next;
    }
    string.append("]}");
    return string.toString();
}
复制代码

创建一个测试类LinkedListWthDummyHeadTest

public class LinkedListWthDummyHeadTest {
    List<Integer> linkedList = new LinkedListWthDummyHead<>();
    @Before
    public void init() {
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        linkedList.add(4);
        System.out.println("初始化:" + linkedList);
    }
    @Test
    public void add() {
        linkedList.add(11);
        linkedList.add(34);
        linkedList.add(78);
        linkedList.add(1,99);
        System.out.println("执行add方法后," + linkedList);
    }
    @Test
    public void remove(){
        linkedList.remove(0);
        System.out.println("执行remove方法删除索引0位置的元素后," + linkedList);
        linkedList.remove(2);
        System.out.println("再次执行remove方法删除索引2位置的元素后," + linkedList);
    }
    @Test
    public void indexOf(){
        int i = linkedList.indexOf(3);
        System.out.println("执行indexOf,元素3位置的索引为:" + i);
    }
}
复制代码

执行测试

image.png


相关文章
|
3月前
|
存储 Java
|
6月前
|
数据采集 Java 数据处理
Java流与链表:探索java.util.stream与LinkedList的交汇点
本文探讨了Java中流(Streams)与链表(LinkedList)的结合使用,展示了如何通过流处理LinkedList以实现高效数据操作。示例代码包括LinkedList的基本操作、使用Stream进行过滤和映射,以及结合HttpClient和代理IP实现网络爬虫。代理IP有助于绕过反爬机制,提高爬取效率。通过结合这些技术,开发者能编写出更简洁、高效的代码。
Java流与链表:探索java.util.stream与LinkedList的交汇点
|
6月前
|
算法 测试技术
【数据结构与算法 | 基础篇】模拟LinkedList实现的双向循环链表
【数据结构与算法 | 基础篇】模拟LinkedList实现的双向循环链表
|
6月前
|
存储 算法 Java
【数据结构与算法 | 基础篇】模拟LinkedList实现的双向链表
【数据结构与算法 | 基础篇】模拟LinkedList实现的双向链表
|
6月前
|
算法
【数据结构与算法 | 基础篇】模拟LinkedList实现的链表(无哨兵)
【数据结构与算法 | 基础篇】模拟LinkedList实现的链表(无哨兵)
|
6月前
|
存储 Python
链表(Linked List)详解
链表(Linked List)详解
51 0
|
6月前
|
设计模式 测试技术
在实现链表的代码中,为什么要使用`Node`类而不是直接在`LinkedList`类中定义节点?
在实现链表的代码中,为什么要使用`Node`类而不是直接在`LinkedList`类中定义节点?
48 1
|
6月前
|
存储 算法 Linux
【C/C++ 线性表】C++ 从零开始实现 双向循环链表(Exploring Doubly Circular Linked List in C++)
【C/C++ 线性表】C++ 从零开始实现 双向循环链表(Exploring Doubly Circular Linked List in C++)
123 0
|
6月前
|
算法 Java 索引
【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)
【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)
67 0
|
6月前
|
存储 算法 Java
【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)
【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)
66 0