数据结构单链表的算法描述_数据结构创建单链表及其实现

数据结构单链表的算法描述_数据结构创建单链表及其实现一、什么是链表链表是一种数据结构,跟数组不同,链表不需要连续的内存空间,而是通过指针将零散的内存块连接起来。因此,链表的查找需要通过节点按顺序遍历,而增加与删除通过只需要操作指针指向,这也造成了相

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、什么是链表

链表是一种数据结构,跟数组不同,链表不需要连续的内存空间,而是通过指针将零散的内存块连接起来。

因此,链表的查找需要通过节点按顺序遍历,而增加与删除通过只需要操作指针指向,这也造成了相比数组,链表的查找性能消耗大增加和删除消耗小的特点。

链表由节点组成,一般每个节点最少包含用于储存数据的data区和用于指向下一个节点的指针next,有的链表可能会有头结点或尾结点用于存储链表长度等信息。

数据结构单链表的算法描述_数据结构创建单链表及其实现

二、链表的简单实现

先来实现一个简单的节点类:

/**
 * @Author:huang
 * @Date:2020-06-20 10:19
 * @Description:节点类
 */
public class Node {

    //节点序号
    int num;

    //数据
    Object data;

    //下一个节点
    Node next;

    public Node(int num, Object data) {
        this.num = num;
        this.data = data;
    }
    
    public int getNum() {
        return num;
    }

    public Object getData() {
        return data;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public void setData(Object data) {
        this.data = data;
    }
    
    @Override
    public String toString() {
        return "Node{" +
            "num=" + num +
            ", data=" + data +
            '}';
    }
}

1.插入节点

1.1不按照排序的插入

/**
 * @Author:huang
 * @Date:2020-06-20 10:19
 * @Description:单链表
 */
public class SingleLinkList {
	//默认初始化一个头节点
    private Node head = new Node(0, "我是头结点");

    /**
     * 添加节点到链表
     * @param node
     */
    public void add(Node node) {
        Node temp = head;
        //遍历链表
        while (true) {
            if (temp.next == null) {
                break;
            }
            //不是尾节点就继续遍历下一个节点
            temp = temp.next;
        }
        //将尾节点指向即将插入的新节点
        temp.next = node;
    }
}

1.2按照排序插入

数据结构单链表的算法描述_数据结构创建单链表及其实现

要想按顺序插入节点,需要确定节点的位置,也就是确定新节点的大小,以图为例:

遍历链表,我们把遍历到的节点叫A,A之前的节点叫A-1,A之后的节点叫A+1,要插入的节点叫B,有以下几种情况:

  1. 当A的序号大于B时,就把B插到A前,也就是原本的A和A-1之间
  2. 当A的序号等于B时,抛出异常禁止插入
  3. 当A的序号小于B时,就跳过这个节点,继续遍历,然后对比A+1和B的大小
  4. 当A就是链表最后一个节点时,A还是小于B,那就直接让B插到A后,变成链表的尾节点

按这个思路,我们在原来的类里新增一个方法:

/**
 * 按顺序添加节点到链表
 * @param node 要插入的节点
 */
public void addByOrder(Node node) {
    Node temp = head;
    //遍历链表
    while (true) {
        //如果链表到底了就直接插入
        if (temp.next == null) {
            temp.next = node;
            return;
        }else if (temp.next.num > node.num){
            //如果当前节点比当要插入的节点大,就把新节点插到当前节点之前
            node.next = temp.next;
            temp.next = node;
            return;
        }else if (temp.next.num == node.num){
            //如果有节点序号和要插入的节点重复就抛异常
            throw new RuntimeException("插入节点与已有节点序号重复!");
        }
        //如果当前节点比当要插入的节点小,就继续遍历
        temp = temp.next;
    }
}

2.查找节点

/**
 * 展示链表全部节点
 */
public void show() {
    //判断链表是否为空
    if (head.next == null) {
        throw new RuntimeException("链表为空!");
    }
    Node temp = head.next;
    //遍历链表
    while (true) {
        if (temp == null) {
            break;
        }
        System.out.println(temp.toString());
        temp = temp.next;
    }
}

/**
 * 根据序号获取节点
 * @param num 要获取的节点序号
 * @return
 */
public Node get(int num){
    //判断链表是否为空
    if (head.next == null) {
        throw new RuntimeException("链表为空!");
    }
    Node temp = head.next;
    //遍历链表
    while (true) {
        if (temp == null) {
            throw new RuntimeException("编号为" + num + "的节点不存在!");
        }
        //如果是要获取的节点
        if (temp.num == num) {
            return temp;
        }
        temp = temp.next;
    }
}

3.修改节点

修改节点与按顺序插入逻辑相似,需要先遍历并找到要修改的节点,然后用新节点去替换旧节点,或者干脆直接修改节点内的信息

数据结构单链表的算法描述_数据结构创建单链表及其实现

/**
 * 修改节点
 * @param node 要更新的节点
 */
public void update(Node node) {
    Node temp = head;
    //判断链表是否为空
    if (temp.next == null) {
        throw new RuntimeException("链表为空!");
    }
    //获取要更新的节点序号
    int nodeNum = node.num;
    //遍历链表
    while (true) {
        //如果已经遍历完链表
        if (temp == null) {
            throw new RuntimeException("编号为" + temp.num + "的节点不存在!");
        }
        //如果找到了该节点
        if (temp.num == nodeNum) {
            temp.data = node.data;
            return;
        }
        //继续遍历下一节点
        temp = temp.next;
    }
}

4.删除节点

数据结构单链表的算法描述_数据结构创建单链表及其实现

因为在单向链表中,节点无法知道自己前一个节点的情况,以图为例:

如果我们想要删除节点A,那么就要找到A的前一个节点A-1,根据是否存在A后的节点A+1有以下几种情况:

  1. A节点就是链表尾节点,此时只需让A-1节点的next指向null即可

    nodeA-1.next = null

  2. A节点后有A+1,此时让A-1节点指向A+1节点

    nodeA-1.next = nodeA-1.next.next

按这个思路,在类里新加一个方法:

/**
 * 删除节点
 * @param num 要删除的节点编号
 */
public void delete(int num) {
    Node temp = head;
    //判断链表是否为空
    if (temp.next == null) {
        throw new RuntimeException("链表为空!");
    }
    //遍历链表
    while (true) {
        //如果链表到底了
        if (temp.next == null) {
            throw new RuntimeException("编号为" + num + "的节点不存在!");
        }
        //如果找到了待删除节点的前一个节点
        if (temp.next.num == num) {
            //判断待删除节点是否为尾节点
            if (temp.next.next == null){
                temp.next = null;
            }else {
                temp.next = temp.next.next;
            }
            return;
        }
        //继续遍历下一节点
        temp = temp.next;
    }
}

三、完整实现代码

/**
 * @Author:huang
 * @Date:2020-06-20 10:19
 * @Description:单链表
 */
public class SingleLinkList {

    private Node head = new Node(0, "我是头结点");

    /**
     * 添加节点到链表
     * @param node 要插入的节点
     */
    public void add(Node node) {
        Node temp = head;
        //遍历链表
        while (true) {
            if (temp.next == null) {
                break;
            }
            //不是尾节点就继续遍历下一个节点
            temp = temp.next;
        }
        //将尾节点指向即将插入的新节点
        temp.next = node;
    }

    /**
     * 展示链表
     */
    public void show() {
        //判断链表是否为空
        if (head.next == null) {
            throw new RuntimeException("链表为空!");
        }
        Node temp = head.next;
        //遍历链表
        while (true) {
            if (temp == null) {
                break;
            }
            System.out.println(temp.toString());
            temp = temp.next;
        }
    }

    /**
     * 根据序号获取节点
     * @param num 要获取的节点序号
     * @return
     */
    public Node get(int num){
        //判断链表是否为空
        if (head.next == null) {
            throw new RuntimeException("链表为空!");
        }
        Node temp = head.next;
        //遍历链表
        while (true) {
            if (temp == null) {
                throw new RuntimeException("编号为" + num + "的节点不存在!");
            }
            if (temp.num == num) {
                return temp;
            }
            temp = temp.next;
        }
    }

    /**
     * 按顺序添加节点到链表
     * @param node 要插入的节点
     */
    public void addByOrder(Node node) {
        Node temp = head;
        //遍历链表
        while (true) {
            //如果链表到底了就直接插入
            if (temp.next == null) {
                temp.next = node;
                return;
            }
            else if (temp.next.num > node.num){
                //如果后一节点比当新节点大,就插入当前节点
                node.next = temp.next;
                temp.next = node;
                return;
            }else if (temp.next.num == node.num){
                //如果后一节点等于新节点,抛异常
                throw new RuntimeException("插入节点与已有节点序号重复!");
            }
            //如果后一节点比当前节点小,就继续遍历
            temp = temp.next;
        }
    }

    /**
     * 修改节点
     * @param node 要更新的节点
     */
    public void update(Node node) {
        Node temp = head;
        //判断链表是否为空
        if (temp.next == null) {
            throw new RuntimeException("链表为空!");
        }
        //获取要更新的节点序号
        int nodeNum = node.num;
        //遍历链表
        while (true) {
            //如果已经遍历完链表
            if (temp == null) {
                throw new RuntimeException("编号为" + temp.num + "的节点不存在!");
            }
            //如果找到了该节点
            if (temp.num == nodeNum) {
                temp.data = node.data;
                return;
            }
            //继续遍历下一节点
            temp = temp.next;
        }
    }

    /**
     * 删除节点
     * @param num 要删除的节点编号
     */
    public void delete(int num) {
        Node temp = head;
        //判断链表是否为空
        if (temp.next == null) {
            throw new RuntimeException("链表为空!");
        }
        //遍历链表
        while (true) {
            //如果链表到底了
            if (temp.next == null) {
                throw new RuntimeException("编号为" + num + "的节点不存在!");
            }
            //如果找到了待删除节点的前一个节点
            if (temp.next.num == num) {
                //判断待删除节点是否为尾节点
                if (temp.next.next == null){
                    temp.next = null;
                }else {
                    temp.next = temp.next.next;
                }
                return;
            }
            //继续遍历下一节点
            temp = temp.next;
        }
    }
}

四、环形链表

循环链表是一种特殊单链表,他跟单链表的区别在于尾节点的尾指针指向了链表的头结点,也就是相当于将链表连接成了一个环形。

环形链表可以用于处理能描述为环形的数据,典型的比如约瑟夫问题。

数据结构单链表的算法描述_数据结构创建单链表及其实现

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/170818.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • shuffleNet_shuffer

    shuffleNet_shuffer论文:ShuffleNet:AnExtremelyEfficientConvolutionalNeuralNetworkforMobileDevices论文提到模型加速的方法为:1) 修剪网络,减少分支(pruningnetworkconnections)。2) 对于一个训练好的网络(pre-trainedmodel),在性能不下降的情况下减少冗余的分支。3) 量化(qua…

    2025年10月16日
    4
  • windows 激活状况 命令查询

    windows 激活状况 命令查询slmgr-ipkKey安装产品密钥slmgr-upk卸载密钥slmgr-ato激活密钥sLUI4显示电话激活选项msinfo32查看电脑组件系统详细信息slmgr-skms激活服务器以下又是产品win8版本激活的显示状态:slmgr.vbs-dlv显示:最为详尽的激活信息,包括:激活ID、安装ID、激活截止日期slmgr.vbs-dli显示:…

    2022年5月11日
    51
  • 局域网,园区网,广域网的区别是什么_局域网和互联网的区别与联系

    局域网,园区网,广域网的区别是什么_局域网和互联网的区别与联系局域网局域网LAN(LocalAreaNetwork):一般不大于10公里,而且通常只使用一种传输介质;地域上看局域网通常是用在一座建筑物或一个工厂内,使用上通常是某一单位或某一部门使用,规模上一般不超过几百个用户。(局域网也是相对而言,一栋楼可以看作一个局域网,一个国家性对于世界来说也可以看作一个局域网。多个楼栋,组成的局域网就可以看作一个园区网。)城域网MAN(MetropolitanAreaNetwork):城域网是一种比局域网更大的网,通常覆盖一个城市,从几十公里到100公里不等,可能

    2022年8月31日
    3
  • 【免费分享】让思路更清晰,思维导图教程及工具[通俗易懂]

    思维导图,让思路更清晰,结构更完整。当你大脑一片混乱不知道该从什么地方做起,可以试着使用一下思维导图工具。昨天列了一下这一年关于自己提升的一些方面,使用思维导图进行简单的列举,有一些好友希望知道我使用的是那个工具来画思维导图的。下面简单介绍一些思维导图工具,在日常生活和工作中希望能够帮助到你。XMind【离线】XMind是一个开源的脑图项目,可以自由下载使用。有XMind Plus…

    2022年2月28日
    52
  • PriorityQueue 解析

    PriorityQueue 解析Java1.5版本后就提供了一个具备了小根堆性质的数据结构也就是优先队列PriorityQueue。//PriorityQueue默认是一个小顶堆,然而可以通过传入自定义的Comparator函数来实现大顶堆。实际上是一个堆(不指定Comparator时默认为最小堆)队列既可以根据元素的自然顺序来排序,也可以根据 Comparator来设置排序规则。队列的头是按指定排序方式的最小元素…

    2022年5月1日
    48
  • Etcd – 分布式配置中心

    Etcd – 分布式配置中心Etcd简介Etcd是一种分布式kv存储设施,他具有一定的一致性,高性能,高可用的方案.类似的zookeeper,但没有zookeeper那么重型,功能也没有覆盖那么多.简单直接的应用就是配置中心架构设计总览clients为多个需要配置的服务,中间层为多个grpc-proxy做均衡负载,以免一个proxy挂了之后导致单点问题.grpc…

    2025年6月22日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号