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

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

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java集合框架关系图谱

    Java集合框架关系图谱Java集合是用于存储数量不等的对象的容器,还可以保存具有映射关系的关联数组,Collection是集合接口,它提供了对集合对象进行基本操作的通用接口方法。Java集合大致分为下面四种类型:List,Set,Queue,Map。List代表有序,可重复集合,Set代表无序,不可重复集合,Queue代表队列集合,Map代表具有映射关系的集合。Java集合主要有Collection和Map接口派生,…

    2022年6月26日
    52
  • SQL SERVER 中的smalldatetime和datetime区别「建议收藏」

    SQL SERVER 中的smalldatetime和datetime区别「建议收藏」SQLSERVER中的smalldatetime和datetime区别Postedon 2011-01-0410:43 Rainbow.ding 阅读(2371)评论(0) 编辑 收藏 smalldatetime不能到秒. 不過它占的空間小.(4位) datetime(8位) 而且兩者的時間範圍不一樣.   datetime占8字节,精度3.3

    2022年5月19日
    54
  • Linux初识之Kali Linux 系统安装详细教程(虚拟机)[通俗易懂]

    Linux初识之Kali Linux 系统安装详细教程(虚拟机)[通俗易懂]文章出自个人博客https://knightyun.github.io/2018/04/15/kali-linux-install,转载请申明目录一、KaliLinux介绍1、Linux2、Kali二、虚拟机安装与配置1、下载2、安装配置三、Kali系统安装与配置一、KaliLinux介绍1、Linux引用一下百度百科:Li…

    2022年5月18日
    31
  • idea创建Java web项目_idea导入maven项目

    idea创建Java web项目_idea导入maven项目准备:1.安装jdk1.72.安装tomcat1.8一、创建并设置javaweb工程1.创建javaweb工程File–>New–>Project…设置工程名字:创建完成后工程结构如下: 2.Web工程设置2.1在WEB-INF目录下点击右键,New–>Directory,创

    2022年9月19日
    2
  • 手游市场数据分析_梦幻西游手游考古3进4

    手游市场数据分析_梦幻西游手游考古3进4“机”不离手是大多数人的生活状态,甚至有一个用手机形容真爱的段子:“在一起时不看手机,不在一起时秒回信息,就算现代人的真爱了。”随着手机在日常生活中地位的提升,手机游戏也逐渐成为年轻人日常生活不可或缺的一部分。 在7月31日的网易云创大会游戏论坛上,来自TalkingData华南区业务负责人黎丽华给大家带来了“透过数据看真相:手游市场趋势报告”的主题分享。通过一些鲜活的数据向大家展示了…

    2025年6月21日
    3
  • MetaMask使用教程

    MetaMask使用教程MetaMask 是一款在谷歌浏览器 Chrome 上使用的插件类型的以太坊钱包 该钱包不需要下载 只需要在谷歌浏览器添加对应的扩展程序即可 非常轻量级 使用起来也非常方便 1 Chrome 的安装既然是一款运行在谷歌浏览器 Chrome 上的插件 当然首先需要先安装 Chrome 了 读者可以进入官网 https www google co

    2025年10月20日
    4

发表回复

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

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