Java数据结构之链表详解

Java数据结构之链表详解

什么是链表?

链表是一种基本的动态数据结构,它的基本思想是利用指针将一些零散的内存块串联起来,形成一个逻辑上的整体。链表由一些称为节点的元素组成,每个节点保存两个部分:数据和指向下一个节点的指针。相比于数组这种静态数据结构,链表具有动态性,我们可以通过动态的增加或删除节点来改变链表的大小。

链表的分类

  1. 单向链表:每个节点只有一个指向下一个节点的指针。
  2. 双向链表:每个节点既有一个指向下一个节点的指针,也有一个指向前一个节点的指针。这样做可以使得链表具备双向遍历的能力。
  3. 循环链表:形式上是一个环形结构的链表,也就是最后一个节点指向第一个节点,或者说第一个节点的前驱节点是最后一个节点。
  4. 双向循环链表:结合前面两种链表的特点,它既可以双向遍历,也可以形成一个闭合的环形结构。

链表的基本操作

插入操作

链表插入操作可以分为两类:头插法和尾插法,它们的区别在于插入节点的位置不同。

头插法

头插法是将新增节点插入到链表的头部,即成为新的头节点。具体步骤如下:

  1. 创建一个新的节点,将数据存入其中。
  2. 将这个节点的next指针指向原链表的头节点。
  3. 更新链表的头节点指针指向这个新节点。

代码示例如下:

public void insertAtBeginning(int data) {
    Node newNode = new Node(data);
    newNode.next = head;
    head = newNode;
}

尾插法

与头插法不同,尾插法是将新增节点插入到链表的尾部,成为链表的最后一个节点。具体步骤如下:

  1. 创建一个新的节点,将数据存入其中。
  2. 遍历链表,找到最后一个节点。
  3. 将最后一个节点的next指针指向新节点。

代码示例如下:

public void insertAtEnd(int data) {
    Node newNode = new Node(data);
    if (head == null) {
        head = newNode;
    } else {
        Node last = head;
        while (last.next != null) {
            last = last.next;
        }
        last.next = newNode;
    }
}

删除操作

链表删除操作主要有两种方式:删除头节点和删除指定节点。具体操作如下:

删除头节点

  1. 更新链表的头节点指针指向下一个节点。
  2. 释放原头节点的空间。

代码示例如下:

public void deleteAtBeginning() {
    if (head != null) {
        Node temp = head;
        head = head.next;
        temp.next = null;
        temp = null;
    }
}

删除指定节点

  1. 遍历链表,找到要删除节点的前驱节点。
  2. 更新前驱节点的next指针。

代码示例如下:

public void deleteByValue(int data) {
    if (head == null) {
        return;
    }
    if (head.data == data) {
        head = head.next;
        return;
    }
    Node temp = head;
    while (temp.next != null && temp.next.data != data) {
        temp = temp.next;
    }
    if (temp.next == null) {
        return;
    }
    temp.next = temp.next.next;
}

链表的应用示例

单向链表实现栈

栈是一种先进后出(FILO)的数据结构,我们可以使用单向链表来实现栈。具体操作如下:

  1. 创建一个空的单向链表,它的头节点为null。
  2. 将新元素插入到链表的头部。
  3. 将链表的头节点作为栈顶,返回它的数据。

代码示例如下:

public class StackByLinkedList {

    private Node head = null;

    public void push(int data) {
        Node newNode = new Node(data);
        newNode.next = head;
        head = newNode;
    }

    public int pop() {
        if (head == null) {
            throw new RuntimeException("Stack is empty");
        }
        int data = head.data;
        head = head.next;
        return data;
    }

    public int peek() {
        if (head == null) {
            throw new RuntimeException("Stack is empty");
        }
        return head.data;
    }

    public boolean isEmpty() {
        return head == null;
    }

    private static class Node {
        int data;
        Node next;

        public Node(int data) {
            this.data = data;
        }
    }
}

双向循环链表实现定时器

定时器是一种常见的应用场景,我们可以使用双向循环链表来实现定时器。具体操作如下:

  1. 创建一个双向循环链表,它的头节点为null。
  2. 将新元素插入到链表尾部,并且根据任务定时时间排序。
  3. 使用线程循环遍历链表,若发现任务到达定时时间,将该任务从链表中删除,并执行任务。

代码示例如下:

public class TimerByLinkedList {

    private TimerTask head = null;

    public synchronized void addTimerTask(TimerTask task) {
        // 略去排序逻辑
        if (head == null) {
            head = task;
            head.prev = head.next = head; // 自己构成转换素环形的节点
        } else {
            TimerTask tail = head.prev;
            tail.next = task;
            task.prev = tail;
            task.next = head;
            head.prev = task;
        }
        notify();
    }

    public synchronized void start() {
        while (true) {
            while (head == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            long delay = head.executeTime - System.currentTimeMillis();
            if (delay <= 0) {
                head.run();
                head = head.next;
                if (head == head.next) {
                    head = null;
                } else {
                    head.prev.next = head; //删除已经执行的任务
                    head.prev = head.prev.prev;
                }
            }
            else {
                try {
                    wait(delay);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static abstract class TimerTask implements Runnable, Comparable<TimerTask> {

        long executeTime;
        TimerTask prev;
        TimerTask next;

        public TimerTask(long executeTime) {
            this.executeTime = executeTime;
        }

        @Override
        public int compareTo(TimerTask o) {
            return Long.compare(executeTime, o.executeTime);
        }
    }
}

总结

链表是一种经典的动态数据结构,其应用场景非常广泛。本文介绍了链表的基本操作,以及一些常见的链表应用示例。需要注意的是,在链表插入和删除操作中要注意避免出现空指针异常,以及链表插入时要注意区分头插法和尾插法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java数据结构之链表详解 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • Java深入了解数据结构之哈希表篇

    Java深入了解数据结构之哈希表篇 1. 哈希表的定义 哈希表(Hash Table),也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构。通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希函数(Hash Function)。 哈希表是基于哈希函数实现的,哈希函数将关键字映射到哈希表中的位置,如果存在两个…

    数据结构 2023年5月17日
    00
  • C语言详解数据结构与算法中枚举和模拟及排序

    我们一步步来详细讲解“C语言详解数据结构与算法中枚举和模拟及排序”的完整攻略。 纲要 本文的主要内容包括: 枚举的概念及应用 模拟的概念及应用 排序的概念及分类 枚举的概念及应用 枚举是一种数据类型,可以将一组具有相关性质的常量定义为枚举常量。枚举常量默认是按照自然数递增的顺序进行编号的。枚举常量可以用于表示状态、类型、结果等概念。以下是一个枚举类型的定义:…

    数据结构 2023年5月17日
    00
  • 使用JavaScript实现链表的数据结构的代码

    要使用JavaScript实现链表数据结构,需要考虑以下几个方面: 链表的基本结构 链表的基本操作(插入、删除、遍历等) JavaScript 实现数据结构的具体步骤 下面我将逐一阐述。 链表的基本结构 链表是由一系列节点所组成的数据结构,每个节点都保存着下一个节点的引用关系。链表可以是单向的,也可以是双向的。单向链表的节点只有指向下一个节点的指针,而双向链…

    数据结构 2023年5月17日
    00
  • 牛客小白月赛71

    A.猫猫与广告 题目: 分析: 只需考虑c * d的矩阵竖着摆和横着摆两种情况。本题提示了考虑两矩阵对应边平行的情况,实际上可以证明倘若能斜着放,那么一定可以横着放或竖着放,证明方式可已通过构造三角形来证明a* b的矩阵的长宽一定小于c * d矩阵的长宽。 code: #include <iostream> #include <cmath&…

    算法与数据结构 2023年4月25日
    00
  • java数据结构排序算法之树形选择排序详解

    Java数据结构排序算法之树形选择排序详解 什么是树形选择排序 树形选择排序是对选择排序的一种改进和优化,它是通过利用完全二叉树的性质对选择排序进行了改进而得到的一种高效的排序算法。 树形选择排序通过将待排序的元素构建成一颗完全二叉树,然后从叶子节点向上比较,选择出最小的元素,并交换位置。这样子,每次选择最小元素的时候,减少了元素之间的比较次数,从而提高了排…

    数据结构 2023年5月17日
    00
  • Java数据结构之顺序表篇

    Java数据结构之顺序表篇 什么是顺序表 顺序表是由一组地址连续、大小相等的存储单元依次存储数据元素的线性表。 顺序表的表示 Java语言中,可以使用数组来表示顺序表。 public class SeqList<T> { private Object[] element;// 定义数组存储数据元素 private int length;// 当前…

    数据结构 2023年5月17日
    00
  • 带你了解Java数据结构和算法之数组

    带你了解Java数据结构和算法之数组 在本教程中,我们将学习Java中的数组数据结构和对应的算法。让我们先来了解什么是数组。 什么是数组? 数组是一个同类型数据元素的集合,在内存中连续存储。数组具有索引性,我们可以使用索引值来访问数组中的元素。 声明和初始化数组 在Java中,声明一个数组需要指定以下三个参数: 数组的类型 数组的名称 数组的大小 以下是一个…

    数据结构 2023年5月17日
    00
  • 稀疏数组

    引入 当在网页上下棋类游戏时,玩到中途想要离开,但是我们需要保存进度,方便下次继续 我们应该怎么实现 ? 以围棋举例 使用二维数组将棋盘记下 ,如 0 为 没有棋子 ,1 为 黑子 , 2为白子 但是没有棋子的地方都为 0 ,整个二维数组充斥着大量的无效数据 0 我们需要想一个办法来 优化存储的方式 基本介绍 当一个数组中大部分元素是同一个值时,我们可以使用…

    算法与数据结构 2023年4月19日
    00
合作推广
合作推广
分享本页
返回顶部