IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Java单链表增删查改操作 -> 正文阅读

[数据结构与算法]Java单链表增删查改操作

声明

此文章为个人笔记文,写的都是个人理解,如有哪里有误,还望大佬们指正

链表描述 - 百度百科

链表是一种物理 存储单元上非连续、非顺序的存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)O(1)

使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表双向链表以及循环链表。链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的存取和操作。程序语言或面向对象语言,如C,C++和Java依靠易变工具来生成链表。

描述总结

  1. 结构

    链表是一种物理 存储单元上非连续、非顺序的存储结构

  2. 组成

    链表由一系列结点(链表中每一个元素称为结点)组成。

  3. 链表类型

    单向链表、双向链表、循环链表

单向链表实现

单向链表结构

单向链表结构

单向链表的增删查改操作

具体功能实现方法如下图:
功能实现方法

Linked 类准备

/**
 * 单向链表
 *  head                                                                 last
 * --------------       --------------      --------------          --------------
 * | data | next | --> | data | next | --> | data | next | ... --> | data | null |
 * --------------       --------------     --------------           --------------
 */
public class Linked<T> {

    /**
     * 头结点
     */
    private Node head;

    /**
     * 覆写 Object.toString 方法, 方便输出
     * @return 链表数据组成的字符串, 格式如: [data1, data2, data3,...,dataN]
     */
    @Override
    public String toString() {
        StringBuffer text = new StringBuffer();
        Node pNode = this.head;
        while (pNode != null) {
            text.append(",").append(pNode.data);
            pNode = pNode.next;
        }
        if (text.length() > 0) {
            text.deleteCharAt(0);
        }
        return "Linked[" + text.toString() +']';
    }

    /**
     * 节点
     */
    class Node{
        /**
         * 节点存放的元素(数据)
         */
        T data;

        /**
         * 节点指向的下一个节点
         */
        Node next;

        /**
         * 根据元素进行构造节点
         * @param data 元素
         */
        public Node(T data) {
            this(data, null);
        }

        /**
         * 根据元素和下一个节点进行构造节点
         * @param data 元素
         * @param next 下一个节点
         */
        public Node(T data, Node next) {
            this.data = data;
            this.next = next;
        }
    }
}

新增操作

addHead(T data) 新增为头节点

/**
 * 增加头结点
 *  1. 当前元素节点下一个节点 指向 之前头节点
 *  2. 头结点 指向 当前元素节点
 * @param data 元素
 * @return true: 成功; false: 失败
 */
public boolean addHead (T data) {
    Node newNode = new Node(data);
    newNode.next = head;
    head = newNode;
    return true;
}

add(int index, T data) 在指定的位置新增节点

/**
 * 向 链表 某个位置添加节点
 * @param index 位置
 * @param data 元素
 * @return true: 成功; false: 失败(在找不到节点时会失败)
 */
public boolean add (int index, T data) {
    // 索引为 0, 则增加为头节点
    if (index == 0) {
        return this.addHead(data);
    }
    // 根据 索引位置 寻找到该节点的前一个节点
    Node frontNode = this.head;
    for (int i = 1; i < index; i++) {
        frontNode = frontNode.next;
        // 找不到,则返回false --> 失败
        if (frontNode == null) {
            return false;
        }
    }
    // 1. 根据 前一个节点的下个节点 得到 索引位置对应的节点
    // 2. 前一个节点的下个节点 指向 当前添加的元素节点
    // 3. 当前添加的元素节点下个节点 指向 索引位置对应的节点
    Node nextNode = frontNode.next;
    Node newNode = new Node(data);
    frontNode.next = newNode;
    newNode.next = nextNode;
    return true;
}

addLast(T data) 新增为最后一个节点(尾节点)

/**
 * 向链表最后添加元素节点
 * @param data 元素
 * @return true: 成功; false: 失败
 */
public boolean addLast (T data) {
    // 头节点为空, 则增加为头节点
    if (this.head == null) {
        return this.addHead(data);
    }
    // 寻找最后一个节点
    Node lastNode = this.head;
    while (lastNode != null) {
        // 下一个节点为空, 则表示尾节点
        if (lastNode.next == null) {
            break;
        }
        lastNode = lastNode.next;
    }
    // 最后节点 下一个节点 指向 添加的元素节点
    lastNode.next = new Node(data);
    return true;
}

查询操作

getHead(T data) 获取头节点的元素数据

/**
 * 获取头结点的元素
 * @return null(在链表为空时会失败) 或 头结点的元素
 */
public T getHead() {
    return this.isEmpty() ? null : this.head.data;
}

get(int index, T data) 获取指定位置节点的元素数据

/**
 * 根据 索引位置获取元素
 * @param index 索引位置
 * @return null 或 索引位置对应的结点的元素
 */
public T get(int index) {
    // 索引为0, 直接获取头结点元素
    if (index == 0) {
        return this.getHead();
    }
    // 获取索引位置对应的节点,当索引位置超出,则返回为null
    // 循环从
    Node pNode = this.head;
    for (int i = 1; i <= index; i++) {
        pNode = pNode.next;
        // 索引位置超出, 直接返回 null
        if (pNode == null) {
            return null;
        }
    }
    return pNode.data;
}

getLast(T data) 获取最后一个节点的元素数据

/**
 * 获取链表尾节点元素
 * @return null(在找不到节点时会失败) 或 尾节点的元素
 */
public T getLast() {
    if (this.isEmpty()) {
        return null;
    }
    // 循环寻找尾节点, 如果有节点的下一个节点为空, 则代表该节点为尾结点
    Node lastNode = this.head;
    while (lastNode != null) {
        if (lastNode.next == null) {
            break;
        }
        lastNode = lastNode.next;
    }
    return lastNode.data;
}

删除操作

removeHead() 删除头节点

/**
 * 删除头结点
 * @return true: 成功; false: 失败(在头节点为空时会失败)
 */
public boolean removeHead() {
    if (this.isEmpty()) {
        return false;
    }
    this.head = this.head.next;
    return true;
}

remove(int index) 删除指定位置的节点

/**
 * 根据索引位置删除节点
 * @param index 索引位置
 * @return true: 成功; false: 失败(在找不到节点时会失败)
 */
public boolean remove(int index) {
    // 当索引位置为0, 删除头结点
    if (index == 0) {
        return this.removeHead();
    }
    // 根据索引位置找到 需要删除的节点 的前一个节点
    Node frontNode = this.head;
    for (int i = 1; i < index; i++) {
        frontNode = frontNode.next;
        // 索引位置还没遍历完,节点下一个节点 为空, 直接返回false
        if (frontNode == null) {
            return false;
        }
    }
    // 将 需要删除的节点 的前一个节点 指向 需要删除的节点 的下一个节点
    Node next = frontNode.next;
    frontNode.next = next.next;
    return true;
}

remove(T data) 根据元素删除节点

/**
 * 根据元素删除节点
 * @param data 元素
 * @return true: 成功; false: 失败(在找不到节点时会失败)
 */
public boolean remove (T data) {
    // 链表为空, 返回删除失败
    if (this.isEmpty()) {
        return false;
    }
    // 如果头节点恰巧和元素一样, 则删除头元素
    if (this.head.data.equals(data)) {
        return this.removeHead();
    }
    // 根据元素找到 需要删除的节点 的前一个节点
    Node frontNode = this.head;
    Node pNode = frontNode.next;
    while (pNode != null) {
        // 找到了元素对应的节点, 然后将 需要删除的节点 的前一个节点 指向 需要删除的节点 的下一个节点
        if (pNode.data.equals(data)) {
            frontNode.next = pNode.next;
            return true;
        }
        // 记录前一个节点 和 循环查找 需要删除的节点
        frontNode = pNode;
        pNode = pNode.next;
    }
    // 找不到 需要删除的节点, 返回false, 代表失败
    return false;
}

removeLast() 删除最后一个节点(尾节点)

/**
 * 删除尾结点
 * @return true: 成功; false: 失败(在找不到尾节点时会失败)
 */
public boolean removeLast() {
    // 链表为空 或 没有尾结点, 返回false, 代表失败
    if (this.isEmpty()) {
        return false;
    }
    // 寻找 尾节点 的 前一个节点,然后将该节点一下个节点指向为空
    Node frontNode = this.head;
    Node pNode = frontNode.next;
    while (pNode != null) {
        pNode = pNode.next;
        if (pNode != null) {
            frontNode = frontNode.next;
        }
    }
    frontNode.next = null;
    return true;
}

修改操作

setHead(T data) 修改头节点元素数据

/**
 * 重新 设置头节点的元素
 * @param data 新的元素
 * @return true: 成功; false: 失败(在找不到头节点时会失败)
 */
public boolean setHead (T data) {
    if (this.isEmpty()) {
        return false;
    }
    head.data = data;
    return true;
}

set(int index, T data) 修改指定节点元素数据

/**
 * 根据索引位置 设置 节点的元素
 * @param index 索引位置
 * @param data 元素
 * @return true: 成功; false: 失败(在找不到节点时会失败)
 */
public boolean set (int index, T data) {
    // 如果索引为0, 则进行设置头结点元素
    if (index == 0) {
        return this.setHead(data);
    }
    // 寻找到需要修改元素的节点;
    // 如果在寻找时, 节点为空, 则代表没有该索引位置节点, 直接返回false
    Node pNode = this.head;
    for (int i = 1; i <= index; i++) {
        pNode = pNode.next;
        if (pNode == null) {
            return false;
        }
    }
    // 修改节点元素
    pNode.data = data;
    return true;
}

setLast(T data)修改最后一个节点(尾节点)元素数据

/**
 * 设置尾结点元素
 * @param data 新的元素
 * @return true: 成功; false: 失败(在找不到尾节点时会失败)
 */
public boolean setLast (T data) {
    // 如果链表为空, 直接返回false
    if (this.isEmpty()) {
        return false;
    }
    // 寻找尾节点, 然后进行设置节点元素值为新的元素
    Node lastNode = this.head;
    while (lastNode.next != null) {
        lastNode = lastNode.next;
    }
    lastNode.data = data;
    return true;
}

其他操作

contains(T data) 判断链表是否包含对应的元素数据

/**
 * 判断链表是否包含对应的元素数据
 * @param data 元素
 * @return true : 不包含; false : 包含
 */
public boolean contains(T data) {
    // 如果链表为空, 直接返回false
    if (this.isEmpty()) {
        return false;
    }
    // 从头节点开始遍历,如果匹配上则返回true, 匹配不上, 返回false
    Node pNode = this.head;
    while (pNode != null) {
        if (pNode.data.equals(data)) {
            return true;
        }
        pNode = pNode.next;
    }
    return false;
}

isEmpty() 判断链表是否为空

/**
 * 判断链表是否为空
 * @return true: 为空; false: 不为空
 */
public boolean isEmpty() {
    return this.head == null;
}

测试

代码

public class LinkedTest {

    public static void main(String[] args) {
        Linked<Integer> intLinked = new Linked<>();

        System.out.println("----------------- 测试 链表新增操作start -----------------");
        // 测试空链表时 新增头节点
        intLinked.addHead(-1);
        System.out.println("空链表时 新增头节点 intLinked.addHead(-1) -> " + intLinked);

        // 测试新增节点位置为0 -> 新增头节点
        intLinked.add(0, 1);
        System.out.println("新增节点位置为0 -> 新增头节点 intLinked.add(0, 1) -> " + intLinked);

        // 测试链表不为时 新增头节点
        intLinked.addHead(0);
        System.out.println("试链表不为时 新增头节点 intLinked.addHead(0) -> " + intLinked);

        // 测试 新增尾节点
        intLinked.addLast(2);
        System.out.println("新增尾节点 intLinked.addLast(2) -> " + intLinked);
        System.out.println("----------------- 测试 链表新增操作end -----------------\n");

        System.out.println("----------------- 测试 链表查询操作start -----------------");
        // 测试 新增指定位置节点
        intLinked.add(3, 3);
        intLinked.add(4, 4);
        System.out.println("新增指定位置节点 intLinked.add(3, 3);intLinked.add(4, 4); -> " + intLinked);

        // 测试 获取头结点元素数据
        System.out.println("获取头结点元素数据 intLinked.getHead() -> " + intLinked.getHead());

        // 测试 获取指定位置结点元素数据
        System.out.println("获取指定位置结点元素数据 intLinked.get(1) -> " + intLinked.get(1));
        // 测试 获取指定位置结点元素数据(不存在的节点)
        System.out.println("获取指定位置结点元素数据(不存在的节点) intLinked.get(9) -> " + intLinked.get(9));
        // 测试 获取尾结点元素数据
        System.out.println("获取尾结点元素数据 intLinked.getLast() -> " + intLinked.getLast());
        System.out.println("----------------- 测试 链表查询操作end -----------------\n");

        System.out.println("----------------- 测试 链表删除操作start -----------------");
        // 测试 删除头节点
        System.out.println("删除头节点 intLinked.removeHead() -> " + intLinked.removeHead() + "; 链表: " + intLinked);
        // 测试 删除指定位置节点
        System.out.println("删除指定位置节点 intLinked.remove(1) -> " + intLinked.remove(1) + "; 链表: " + intLinked);
        // 测试 删除指定位置节点(不存在的节点)
        System.out.println("删除指定位置节点(不存在的节点) intLinked.remove(9) -> " + intLinked.remove(9) + "; 链表: " + intLinked);
        // 测试 删除指定元素节点
        System.out.println("删除指定元素节点 intLinked.remove(new Integer(3)) -> " + intLinked.remove(new Integer(3)) + "; 链表: " + intLinked);
        // 测试 删除尾节点
        System.out.println("删除尾节点 intLinked.removeLast() -> " + intLinked.removeLast() + "; 链表: " + intLinked);
        System.out.println("----------------- 测试 链表删除操作end -----------------\n");

        System.out.println("----------------- 测试 链表修改操作start -----------------");
        // 测试 修改头节点
        System.out.println("修改头节点 intLinked.setHead(-2) -> " + intLinked.setHead(-2)+ "; 链表: " + intLinked);
        // 测试 修改指定位置节点
        System.out.println("修改指定位置节点 intLinked.set(1, 0) -> " + intLinked.set(1, 0) + "; 链表: " + intLinked);
        // 测试 修改指定位置节点(不存在的节点)
        System.out.println("修改指定位置节点(不存在的节点) intLinked.set(9, 8) -> " + intLinked.set(9, 8) + "; 链表: " + intLinked);
        // 测试 修改尾节点
        System.out.println("修改尾节点 intLinked.setLast(666) -> " + intLinked.setLast(666) + "; 链表: " + intLinked);
        System.out.println("----------------- 测试 链表修改操作end -----------------\n");

        System.out.println("----------------- 测试 链表其他操作start -----------------");
        // 测试 链表是否包含该元素
        System.out.println("链表是否包含该元素 intLinked.contains(666) -> " + intLinked.contains(666) + "; 链表: " + intLinked);
        // 测试 链表是否包含该元素(不存在的元素)
        System.out.println("链表是否包含该元素(不存在的元素) intLinked.contains(777) -> " + intLinked.contains(7777) + "; 链表: " + intLinked);

        // 测试 链表是否为空
        Linked<String> strLinked = new Linked<>();
        System.out.println("链表是否为空 strLinked.isEmpty() -> " + strLinked.isEmpty() + "; 链表: " + strLinked);
        // 测试 链表是否为空(不为空)
        strLinked.add(0, "Hello");
        System.out.println("链表是否为空(不为空) strLinked.isEmpty() -> " + strLinked.isEmpty() + "; 链表: " + strLinked);
        System.out.println("----------------- 测试 链表其他操作end -----------------");
    }

}

测试结果

----------------- 测试 链表新增操作start -----------------
空链表时 新增头节点 intLinked.addHead(-1) -> Linked[-1]
新增节点位置为0 -> 新增头节点 intLinked.add(0, 1) -> Linked[1,-1]
试链表不为时 新增头节点 intLinked.addHead(0) -> Linked[0,1,-1]
新增尾节点 intLinked.addLast(2) -> Linked[0,1,-1,2]
----------------- 测试 链表新增操作end -----------------

----------------- 测试 链表查询操作start -----------------
新增指定位置节点 intLinked.add(3, 3);intLinked.add(4, 4); -> Linked[0,1,-1,3,4,2]
获取头结点元素数据 intLinked.getHead() -> 0
获取指定位置结点元素数据 intLinked.get(1) -> 1
获取指定位置结点元素数据(不存在的节点) intLinked.get(9) -> null
获取尾结点元素数据 intLinked.getLast() -> 2
----------------- 测试 链表查询操作end -----------------

----------------- 测试 链表删除操作start -----------------
删除头节点 intLinked.removeHead() -> true; 链表: Linked[1,-1,3,4,2]
删除指定位置节点 intLinked.remove(1) -> true; 链表: Linked[1,3,4,2]
删除指定位置节点(不存在的节点) intLinked.remove(9) -> false; 链表: Linked[1,3,4,2]
删除指定元素节点 intLinked.remove(new Integer(3)) -> true; 链表: Linked[1,4,2]
删除尾节点 intLinked.removeLast() -> true; 链表: Linked[1,4]
----------------- 测试 链表删除操作end -----------------

----------------- 测试 链表修改操作start -----------------
修改头节点 intLinked.setHead(-2) -> true; 链表: Linked[-2,4]
修改指定位置节点 intLinked.set(1, 0) -> true; 链表: Linked[-2,0]
修改指定位置节点(不存在的节点) intLinked.set(9, 8) -> false; 链表: Linked[-2,0]
修改尾节点 intLinked.setLast(666) -> true; 链表: Linked[-2,666]
----------------- 测试 链表修改操作end -----------------

----------------- 测试 链表其他操作start -----------------
链表是否包含该元素 intLinked.contains(666) -> true; 链表: Linked[-2,666]
链表是否包含该元素(不存在的元素) intLinked.contains(777) -> false; 链表: Linked[-2,666]
链表是否为空 strLinked.isEmpty() -> true; 链表: Linked[]
链表是否为空(不为空) strLinked.isEmpty() -> false; 链表: Linked[Hello]
----------------- 测试 链表其他操作end -----------------

单向链表实现全部代码

/**
 * 单向链表
 *  head                                                                 last
 * --------------       --------------      --------------          --------------
 * | data | next | --> | data | next | --> | data | next | ... --> | data | null |
 * --------------       --------------     --------------           --------------
 */
public class Linked<T> {

    /**
     * 头结点
     */
    private Node head;

    /**
     * 增加头结点
     *  1. 当前元素节点下一个节点 指向 之前头节点
     *  2. 头结点 指向 当前元素节点
     * @param data 元素
     * @return true: 成功; false: 失败
     */
    public boolean addHead (T data) {
        Node newNode = new Node(data);
        newNode.next = head;
        head = newNode;
        return true;
    }

    /**
     * 向 链表 某个位置添加节点
     * @param index 位置
     * @param data 元素
     * @return true: 成功; false: 失败(在找不到节点时会失败)
     */
    public boolean add (int index, T data) {
        // 索引为 0, 则增加为头节点
        if (index == 0) {
            return this.addHead(data);
        }

        // 根据 索引位置 寻找到该节点的前一个节点
        Node frontNode = this.head;
        for (int i = 1; i < index; i++) {
            frontNode = frontNode.next;
            // 找不到,则返回false --> 失败
            if (frontNode == null) {
                return false;
            }
        }
        // 1. 根据 前一个节点的下个节点 得到 索引位置对应的节点
        // 2. 前一个节点的下个节点 指向 当前添加的元素节点
        // 3. 当前添加的元素节点下个节点 指向 索引位置对应的节点
        Node nextNode = frontNode.next;
        Node newNode = new Node(data);
        frontNode.next = newNode;
        newNode.next = nextNode;
        return true;
    }

    /**
     * 向链表最后添加元素节点
     * @param data 元素
     * @return true: 成功; false: 失败
     */
    public boolean addLast (T data) {
        // 头节点为空, 则增加为头节点
        if (this.head == null) {
            return this.addHead(data);
        }
        // 寻找最后一个节点
        Node lastNode = this.head;
        while (lastNode != null) {
            // 下一个节点为空, 则表示尾节点
            if (lastNode.next == null) {
                break;
            }
            lastNode = lastNode.next;
        }
        // 最后节点 下一个节点 指向 添加的元素节点
        lastNode.next = new Node(data);
        return true;
    }

    /**
     * 获取头结点的元素
     * @return null(在链表为空时会失败) 或 头结点的元素
     */
    public T getHead() {
        return this.isEmpty() ? null : this.head.data;
    }

    /**
     * 根据 索引位置获取元素
     * @param index 索引位置
     * @return null 或 索引位置对应的结点的元素
     */
    public T get(int index) {
        // 索引为0, 直接获取头结点元素
        if (index == 0) {
            return this.getHead();
        }
        // 获取索引位置对应的节点,当索引位置超出,则返回为null
        // 循环从
        Node pNode = this.head;
        for (int i = 1; i <= index; i++) {
            pNode = pNode.next;
            // 索引位置超出, 直接返回 null
            if (pNode == null) {
                return null;
            }
        }
        return pNode.data;
    }

    /**
     * 获取链表尾节点元素
     * @return null(在找不到节点时会失败) 或 尾节点的元素
     */
    public T getLast() {
        if (this.isEmpty()) {
            return null;
        }

        // 循环寻找尾节点, 如果有节点的下一个节点为空, 则代表该节点为尾结点
        Node lastNode = this.head;
        while (lastNode != null) {
            if (lastNode.next == null) {
                break;
            }
            lastNode = lastNode.next;
        }
        return lastNode.data;
    }

    /**
     * 删除头结点
     * @return true: 成功; false: 失败(在头节点为空时会失败)
     */
    public boolean removeHead() {
        if (this.isEmpty()) {
            return false;
        }
        this.head = this.head.next;
        return true;
    }

    /**
     * 根据索引位置删除节点
     * @param index 索引位置
     * @return true: 成功; false: 失败(在找不到节点时会失败)
     */
    public boolean remove(int index) {
        // 当索引位置为0, 删除头结点
        if (index == 0) {
            return this.removeHead();
        }
        // 根据索引位置找到 需要删除的节点 的前一个节点
        Node frontNode = this.head;
        for (int i = 1; i < index; i++) {
            frontNode = frontNode.next;
            // 索引位置还没遍历完,节点下一个节点 为空, 直接返回false
            if (frontNode == null) {
                return false;
            }
        }
        // 将 需要删除的节点 的前一个节点 指向 需要删除的节点 的下一个节点
        Node next = frontNode.next;
        frontNode.next = next.next;
        return true;
    }

    /**
     * 根据元素删除节点
     * @param data 元素
     * @return true: 成功; false: 失败(在找不到节点时会失败)
     */
    public boolean remove (T data) {
        // 链表为空, 返回删除失败
        if (this.isEmpty()) {
            return false;
        }
        // 如果头节点恰巧和元素一样, 则删除头元素
        if (this.head.data.equals(data)) {
            return this.removeHead();
        }
        // 根据元素找到 需要删除的节点 的前一个节点
        Node frontNode = this.head;
        Node pNode = frontNode.next;
        while (pNode != null) {
            // 找到了元素对应的节点, 然后将 需要删除的节点 的前一个节点 指向 需要删除的节点 的下一个节点
            if (pNode.data.equals(data)) {
                frontNode.next = pNode.next;
                return true;
            }
            // 记录前一个节点 和 循环查找 需要删除的节点
            frontNode = pNode;
            pNode = pNode.next;
        }
        // 找不到 需要删除的节点, 返回false, 代表失败
        return false;
    }

    /**
     * 删除尾结点
     * @return true: 成功; false: 失败(在找不到尾节点时会失败)
     */
    public boolean removeLast() {
        // 链表为空 或 没有尾结点, 返回false, 代表失败
        if (this.isEmpty()) {
            return false;
        }
        // 寻找 尾节点 的 前一个节点,然后将该节点一下个节点指向为空
        Node frontNode = this.head;
        Node pNode = frontNode.next;
        while (pNode != null) {
            pNode = pNode.next;
            if (pNode != null) {
                frontNode = frontNode.next;
            }
        }
        frontNode.next = null;
        return true;
    }

    /**
     * 重新 设置头节点的元素
     * @param data 新的元素
     * @return true: 成功; false: 失败(在找不到头节点时会失败)
     */
    public boolean setHead (T data) {
        if (this.isEmpty()) {
            return false;
        }
        head.data = data;
        return true;
    }

    /**
     * 根据索引位置 设置 节点的元素
     * @param index 索引位置
     * @param data 元素
     * @return true: 成功; false: 失败(在找不到节点时会失败)
     */
    public boolean set (int index, T data) {
        // 如果索引为0, 则进行设置头结点元素
        if (index == 0) {
            return this.setHead(data);
        }
        // 寻找到需要修改元素的节点;
        // 如果在寻找时, 节点为空, 则代表没有该索引位置节点, 直接返回false
        Node pNode = this.head;
        for (int i = 1; i <= index; i++) {
            pNode = pNode.next;
            if (pNode == null) {
                return false;
            }
        }
        // 修改节点元素
        pNode.data = data;
        return true;
    }

    /**
     * 设置尾结点元素
     * @param data 新的元素
     * @return true: 成功; false: 失败(在找不到尾节点时会失败)
     */
    public boolean setLast (T data) {
        // 如果链表为空, 直接返回false
        if (this.isEmpty()) {
            return false;
        }
        // 寻找尾节点, 然后进行设置节点元素值为新的元素
        Node lastNode = this.head;
        while (lastNode.next != null) {
            lastNode = lastNode.next;
        }
        lastNode.data = data;
        return true;
    }

    /**
     * 判断链表是否包含对应的元素数据
     * @param data 元素
     * @return true : 不包含; false : 包含
     */
    public boolean contains(T data) {
        // 如果链表为空, 直接返回false
        if (this.isEmpty()) {
            return false;
        }
        // 从头节点开始遍历,如果匹配上则返回true, 匹配不上, 返回false
        Node pNode = this.head;
        while (pNode != null) {
            if (pNode.data.equals(data)) {
                return true;
            }
            pNode = pNode.next;
        }
        return false;
    }

    /**
     * 判断链表是否为空
     * @return true: 为空; false: 不为空
     */
    public boolean isEmpty() {
        return this.head == null;
    }

    /**
     * 覆写 Object.toString 方法, 方便输出
     * @return 链表数据组成的字符串, 格式如: [data1, data2, data3,...,dataN]
     */
    @Override
    public String toString() {
        StringBuffer text = new StringBuffer();
        Node pNode = this.head;
        while (pNode != null) {
            text.append(",").append(pNode.data);
            pNode = pNode.next;
        }
        if (text.length() > 0) {
            text.deleteCharAt(0);
        }
        return "Linked[" + text.toString() +']';
    }

    /**
     * 节点
     */
    class Node{
        /**
         * 节点存放的元素(数据)
         */
        T data;

        /**
         * 节点指向的下一个节点
         */
        Node next;

        /**
         * 根据元素进行构造节点
         * @param data 元素
         */
        public Node(T data) {
            this(data, null);
        }

        /**
         * 根据元素和下一个节点进行构造节点
         * @param data 元素
         * @param next 下一个节点
         */
        public Node(T data, Node next) {
            this.data = data;
            this.next = next;
        }
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-16 11:33:17  更:2021-07-16 11:33:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 10:20:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码