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 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构与算法03-链表(单链表、循环链表、双向循环链表)-java实现 -> 正文阅读

[数据结构与算法]数据结构与算法03-链表(单链表、循环链表、双向循环链表)-java实现

链表

1. 简介

所谓链表,通俗的说就是用一条链把数据都串起来

前面我们提到的数组、栈和队列都是顺序存储结构,这里的链表属于链式存储结构

什么是链表呢,我们直接上图

在这里插入图片描述

我们可以看到:每个链表结点至少包含两个元素:数据data、地址next(指向下一个数据)

分类:
最基础的链表就是单链表,在单链表的基础上有循环链表、双向链表、双向循环链表。
下面会分别进行介绍和实现。

2. 单链表

你猜的没错,前面我们看到的链表图,其实就是单链表。
单链表除了最后一个结点以外,其他结点都由数据data和t指向下一结点的nex组成
而最后一个结点的next为null

常见操作(方法):
getData()—获取当前结点数据
next()—返回下一个结点
append()—结点追加-追加在链表最后
insertAfter()—结点插入
removeNode()—结点移除
show()—输出当前链表
isLast()—判断是否是最后一个结点

代码:

public class Node {
    //结点数据
    private int data;
    //指向下一个结点
    private Node next;
    //构造函数中对结点赋值
    public Node(int data){
        this.data=data;
    }
    //返回当前结点数据
    public int getData(){
        return this.data;
    }
    //追加结点
    public Node append(Node node){
        //点前结点
        Node currentNode=this;
        //从当前结点开始依次往后寻找为null的结点进行追加
        while(true){
            //如果下一个结点为空,进行追加结点并调出循环
            if(currentNode.next==null){
                currentNode.next=node;
                break;
            }
            //不是空,将下一个结点指向当前结点,接着向后寻找
            currentNode=currentNode.next;
        }
        //返回当前结点方便调用
        return this;
    }
    //获取下一个结点
    public Node next(){
        return this.next;
    }
    //判断是否最后一个结点
    public Boolean isLast(){
        return this.next==null;
    }
    //输出链表 (此方法只能输出当前结点及往后的元素结点内容)
    public void show(){
        //当前结点
        Node CurrentNode=this;
        while (true){
            System.out.print(CurrentNode.data);
            //如果没有下一个结点,结束
            if(CurrentNode.next==null){
                System.out.println();
                break;
            }else{
                System.out.print("->");
                //向后查找
                CurrentNode=CurrentNode.next;
            }
        }
    }

    //删除下一个结点
    public void removeNode(){
        //将下下个结点指向当前结点的下一个结点
        this.next=this.next.next;
    }
    //插入一个结点(当前结点后面)
    public void insetAfter(Node node){
        //保存下一个结点
        Node nextNode=this.next;
        //将插入的元素指向当前结点的下一个结点
        this.next=node;
        //最后将保存的结点指向刚刚插入结点的下一个结点
        node.next=nextNode;
    }
}

测试类

public class TestNode {
    public static void main(String[] args) {
        //创建三个结点,现在他们之间没有任何关联
        Node node1 = new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        Node node4 = new Node(4);
        //将node1和node2追加到node上面形成链表
        node1.append(node2).append(node3).append(node4);
        //通过node1获取node3的数据
        System.out.println(node1.next().next().getData());
        node1.show();
        //移除node2
        node1.removeNode();
        node1.show();
        //插入元素
        node1.insetAfter(new Node(100));
        node3.insetAfter(new Node(200));
        node1.show();
    }
}

结果:

3
1->2->3->4
1->3->4
1->100->3->200->4

3. 循环链表

在这里插入图片描述

循环链表就是将单链表最后一个结点指向第一个结点,这样让整个链表形成一个循环
循环链表由于没有尾结点,所以不能append结点

注意:循环链表只能插入结点,删除结点

在单链表基础上,我们将结点中的next初始化为this,也就是指向当前结点自己,就变成了循环链表,话不多说,下面直接上代码。

代码:

public class LoopNode {
    //结点数据
    private int data;
    //指向下一个结点
    private LoopNode next=this;
    //构造函数中对结点赋值
    public LoopNode(int data){
        this.data=data;
    }
    //返回当前结点数据
    public int getData(){
        return this.data;
    }

    //获取下一个结点
    public LoopNode next(){
        return this.next;
    }

    //删除下一个结点
    public void removeNode(){
        //将下下个结点指向当前结点的下一个结点
        this.next=this.next.next;
    }

    //插入一个结点(当前结点后面)
    public void insetAfter(LoopNode node){
        //保存下一个结点
        LoopNode nextNode=this.next;
        //将插入的元素指向当前结点的下一个结点
        this.next=node;
        //最后将保存的结点指向刚刚插入结点的下一个结点
        node.next=nextNode;
    }
}

测试类:

public class TestLoopNode {
    public static void main(String[] args) {
        //新增循环链表结点
        LoopNode loopNode1 = new LoopNode(1);
        LoopNode loopNode2 = new LoopNode(2);
        LoopNode loopNode3 = new LoopNode(3);
        //将loopNode2、loopNode3插入
        loopNode1.insetAfter(loopNode2);
        loopNode2.insetAfter(loopNode3);
        //通过next查看下一个结点的值
        System.out.println(loopNode1.next().getData());
        System.out.println(loopNode2.next().getData());
        //循环链表的特征
        //注意:这里通过loopNode3.next() 访问到loopNode1 
        System.out.println(loopNode3.next().getData());
    }
}

运行结果

2
3
1

4. 双向循环链表

双向循环链表:顾名思义就是每一个结点都可以访问其前后两个结点,并且是循环链表
在这里插入图片描述
特点:每一个结点都有pre和next分别指向相邻结点
特别的:第一个结点的pre指向最后一个结点,而最后一个结点的next指向第一个结点

每一个结点都可以访问到其前后两个结点所我们需要增加一个pre指向上一个结点
同时插入操作相比于单链表较为复杂,需要修改四个指向,见代码

代码:

public class DoubleNode {
    //结点数据、指向前一个结点、指向后一个结点
    private int data;
    //如果没有结点插入(一个结点)默认指向自己
    private DoubleNode pre=this;
    private DoubleNode next=this;
    public DoubleNode(int data){
        this.data=data;
    }
    //返回当前结点的上一个结点
    public DoubleNode pre(){
        return this.pre;
    }
    //返回当前结点的下一个结点
    public DoubleNode next(){
        return this.next;
    }
    //获取数据
    public int getData(){
        return this.data;
    }
    //插入元素
    public void insertAfter(DoubleNode doubleNode){
        //保存当前结点的下一个结点(简称保存结点)
        DoubleNode nextDoubleNode=this.next;
        //将插入的结点指向当前结点的下一个结点next
        this.next=doubleNode;
        //同时将当前结点指向插入结点的上一个结点pre
        doubleNode.pre=this;
        //将保存结点指向插入结点的下一结点next
        doubleNode.next=nextDoubleNode;
        //同时将插入结点指向保存结点的上一结点pre
        nextDoubleNode.pre=doubleNode;
    }
}

测试类:

public class TestDoubleNode {
    public static void main(String[] args) {
        //初始化双向循环链表
        DoubleNode doubleNode1 = new DoubleNode(1);
        DoubleNode doubleNode2 = new DoubleNode(2);
        DoubleNode doubleNode3 = new DoubleNode(3);
        //将doubleNode2、doubleNode3插入doubleNode1
        doubleNode1.insertAfter(doubleNode2);
        doubleNode2.insertAfter(doubleNode3);
        //输出检验
        System.out.println(doubleNode1.pre().getData());
        System.out.println(doubleNode1.next().getData());
        System.out.println(doubleNode2.pre().getData());
        System.out.println(doubleNode2.next().getData());
        System.out.println(doubleNode3.pre().getData());
        System.out.println(doubleNode3.next().getData());
    }
}

结果:

3
2
1
3
2
1
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-09 19:49:07  更:2021-11-09 19:51:41 
 
开发: 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年11日历 -2024/11/26 10:21:51-

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