• 数据结构和算法——基于Java——3.1链表(单链表)


    理论补充

    概念:链表是以节点的方式存储,是链式存储
    特性

    1. 每个节点包含一个data数据域(存放数据),一个next域(指向下一个节点)
    2. 链表分带头结点和不带头节点(单链表带头)
    3. 链表的内存分布是无序的(我们画的图看上去是顺序但是内存分布是无序的,每一个节点可以在内存中呈离散分布)
      在这里插入图片描述

    代码实现

    1.基础增加查询功能

    package com.b0.a1_3linkedList;
    
    public class SingleLinkedListDemo {
        public static void main(String[] args) {
            //进行测试
            //先创建节点
            HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
            HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
            HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
            HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
            //创建一个链表
            SingleLinkedList linkedList = new SingleLinkedList();
            linkedList.add(hero1);
            linkedList.add(hero2);
            linkedList.add(hero3);
            linkedList.add(hero4);
            linkedList.list();
        }
    }
    //定义一个SingleLinkedList来管理角色
    class SingleLinkedList{
        //初始化头节点,头节点不存放具体的数据
        private HeroNode head = new HeroNode(0,"","");
        public void add(HeroNode node){
            //因为头节点不能移动,所以需要一个辅助变量temp
            HeroNode temp = head;
            while (true){
                //找到链表最后
                if (temp.next == null){
                    break;
                }
                temp = temp.next;
            }
            //最后一个节点指向node
            temp.next = node;
        }
        //显示链表【遍历】
        public void list(){
            if (head.next == null){
                System.out.println("链表为空!");
                return;
            }
            //因为头节点不能移动,所以需要一个辅助变量temp
            HeroNode temp = head.next;
            while (true){
                //判断链表是否到最后
                if (temp == null){
                    break;
                }
                //输出节点信息
                System.out.println(temp);
                //输出结束必须要节点后移,不然会死循环
                temp = temp.next;
            }
        }
    }
    
    //定义一个HeroNode,每一个HeroNode对象就是一个节点
    class HeroNode{
        public int no;
        public String name;
        public String nickname;
        public HeroNode next;//指向下一个节点
        //构造器
        public HeroNode(int no,String name,String nickname){
            this.no = no;
            this.name = name;
            this.nickname = nickname;
        }
        @Override
        public String toString() {
            return "HeroNode{" +
                    "no=" + no +
                    ", name='" + name + '\'' +
                    ", nickname='" + nickname + '\'' +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    2.按顺序插入节点

    上述实现中我们只是进行了基本插入,其中每个数据有一个编号,若需要按照编号排名顺序插入如何实现?
    在这里插入图片描述
    思路:
    第一步:将初始化node值赋给一个temp变量,再通过temp遍历找到插入节点的位置
    第二步:新节点.next = temp.next;temp.next = 新节点
    SingleLinkedList类中新增方法addByOrder

    	//第二种方式再添加英雄时,根据排名将英雄插入到指定位置
        //如果有这个排名,添加失败,并给出提示
        public void addByOrder(HeroNode heroNode){
            //头节点不能动,因此需要使用一个辅助变量temp来找到添加位置
            //单链表,需要找到的temp是位于添加位置的前一个节点,否则插入不了
            HeroNode  temp = head;
            boolean flag = false;//标识插入的编号是否存在,默认false
            while (true){
                if (temp.next == null){
                    break;
                } else if (temp.next.no >heroNode.no) {//找到位置
                    break;
                }else if (temp.next.no == heroNode.no) {
                    flag = true;
                    break;
                }else {
                    temp = temp.next;//后移,遍历当前链表
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    修改main方法不按顺序插入

    		//不按照编号顺序添加
            linkedList.addByOrder(hero1);
            linkedList.addByOrder(hero4);
            linkedList.addByOrder(hero3);
            linkedList.addByOrder(hero2);
            linkedList.list();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出结果仍然按照顺序输出
    在这里插入图片描述

    3.单链表的修改、删除和查找节点

    3.1修改节点

    根据新节点的no编号修改数据
    在SingleLinkedList类中添加方法update

    //修改节点信息,根据no编号修改,no编号不能修改。
        //1.根据newHeroNode的no来修改
        public void update(HeroNode newHeroNode){
            //判断链表是否为空
            if (head.next == null){
                System.out.println("链表为空~");
                return;
            }
            //找到需要修改的节点,根据no编号
            //定义一个辅助遍历
            HeroNode temp = head.next;
            boolean flag = false;//表示该节点是否被找到
            while (true){
                if (temp == null){
                    break;//链表已经遍历完
                }
                if (temp.no == newHeroNode.no){
                    flag = true;//找到节点
                    break;
                }
                temp = temp.next;
            }
            if (flag){
                temp.name = newHeroNode.name;
                temp.nickname = newHeroNode.nickname;
            }else {//没有找到
                System.out.println("没有找到编号:"+newHeroNode.no+"的节点,不能修改!");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    主程序中实例节点然后调用

     		//测试修改节点
            HeroNode heroNode = new HeroNode(2, "小卢", "玉麒麟!");
            linkedList.update(heroNode);
    
    • 1
    • 2
    • 3

    3.2 删除节点

    在这里插入图片描述
    SingleLinkedList类中编写delete方法

    //思路1.head不能变动,我们需要一个temp辅助节点找到待删除节点的前一个节点
        //2.说明我们比较时,是temp.next.no和 需要删除的节点的no比较
        public void delete(int no){
            HeroNode temp = head;
            boolean flag = false;//标志是否找到链表的最后
            while (true){
                if (temp.next == null){//链表已经到最后
                    break;
                }
                if (temp.next.no == no){//找到待删除节点的前一个节点
                    flag = true;
                    break;
                }
                temp = temp.next;//后移,加上循环实现遍历
            }
            //判断flag
            if (flag){
                temp.next = temp.next.next;
            }else {
                System.out.println("要删除的节点:"+no+"不存在") ;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    主函数中编写测试

    		//...省略添加元素代码
     		//删除节点
            linkedList.delete(1);
            linkedList.delete(4);
            linkedList.delete(2);
            linkedList.delete(3);
            // 显示数据
            linkedList.list();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    注意此处:被删除的节点会被gc垃圾回收机制回收

    3.4 查找节点

    链表中查找效率是较低的时间复杂度为O(n),若现实场景存在查询较多不推荐使用链表,推荐使用其他类型数据结构。
    SingleLinkedList类中编写get方法

     //查找
        public HeroNode get(int no){
            HeroNode temp = head;
            while (true){
                if (temp.next == null){//空表直接返回null
                    return null;
                }
                if (temp.no == no){//根据no遍历查找
                    break;
                }
                temp = temp.next;
            }
            return temp;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    主函数中编写测试

    System.out.println(linkedList.get(1));
    
    • 1

    参考资料:B站尚硅谷

  • 相关阅读:
    dsu on tree模板
    php简单后门实现及php连接数据库
    动态规划:组成目标货币的最少货币数
    Git 查看提交历史
    《lwip学习7》-- IP协议
    ✨Linux定时备份mysql中的数据库(包括Docker)
    微信小程序的民宿客房预订uniapp小程序
    js 定时器 setInterval(图片的自动变换)
    【JavaScript】运算符及其优先级
    mac 图文一步一步安装单节点etcd并配置可视化界面
  • 原文地址:https://blog.csdn.net/G_change_/article/details/128074552