当前位置 博文首页 > 想要上南大的同学的博客:第 4 章 链表

    想要上南大的同学的博客:第 4 章 链表

    作者:[db:作者] 时间:2021-07-17 13:14

    第 4 章 链表

    1 链表(Linked List)介绍

    1.1 内存结构

    内存上来看:链表存储空间不连续(不像数组,地址一直在变)

    1.2 逻辑结构

    img00

    逻辑上来看:链表属于线性结构

    1.3 链表特点

    IMG01
    1.链表是以节点的方式来存储,是链式存储
    2.data 域存放数据,next 域指向下一个节点,最后为null代表结束
    3.链表分带头节点的链表没有头节点的链表,根据实际的需求来确定

    1.4 思路分析

    1)单链表的创建示意图(添加), 显示单链表的分析

    • 不考虑顺序
    1. 先创建一个Head 头节点, 作用是表示单链表的头;
    2. 后面我们每添加一个节点, 就直接加入到 链表 的最后。

    不

    • 考虑顺序
    1. 首先要找到新添加的节点的位置,通过辅助的temp, 遍历
    2. 新的节点.next = temp.next
    3. temp.next = 新的节点

    有

    2 链表应用场景

    2.1 水浒英雄榜

    使用带 head 头的单向链表实现【水浒英雄排行榜管理】

    第一种方法:在添加英雄时,直接添加到链表的尾部【不考虑顺序】
    第二种方式:在添加英雄时,根据排名将英雄插入到指定位置 (如果有这个排名,则添加失败,并给出提示)【考虑顺序】

    2.2 代码实现

    2.2.1 不考虑顺序

    package practice;
    //此时为不考虑顺序, 只能按照加入的先后来排序
    public class SingleLinkedListDemo {
        public static void main(String[] args) {
            //测试
            // 1 先创建节点
            HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
            HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
            HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
            HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
    
            //创建链表
            SingleLinkedList singleLinkedList = new SingleLinkedList();
            //加入
            singleLinkedList.add(hero1);
            singleLinkedList.add(hero2);
            singleLinkedList.add(hero3);
            singleLinkedList.add(hero4);
            //显示
            singleLinkedList.list();
        }
    }
    
    //定义一个SingleLinkedList 管理我们的英雄
    class SingleLinkedList {
        // 1 创建一个头节点, 头节点不要动, 且不存放任何数据
        private HeroNode head = new HeroNode(0, "", "");
    
        // 2 添加节点到单向链表
        // 思路: 当不考虑编号顺序时
        //      1) 找到当前链表的最后节点
        //      2) 将最后这个节点的 next 指向 新的节点
        public void add(HeroNode heroNode) {
    
            // 因为 head 节点不能动, 所以我们需要一个辅助遍历 temp
            HeroNode temp = head;
            // 遍历链表, 找到最后
            while (true) {
                //找到链表最后
                if (temp.next == null) {
                    break;
                }
                //如果没找到, 将 temp 后移
                temp = temp.next;
            }
            //当退出 while 循环时, temp 就指向链表的最后了
            temp.next = heroNode;
        }
    
        //显示链表
        public void list() {
            //判断链表是否为空
            if (head.next == null) {
                System.out.println("链表为空。");
                return;
            }
            //因为头节点不能动, 我们需要一个 辅助变量
            HeroNode temp = head.next;
            while (true) {
            //判断是否到链表最后了
                if (temp == null) {
                    break;
                }
    //            System.out.println(temp.toString());
                System.out.println(temp);
                //将temp 后移, 一定要
                temp = temp.next;
            }
        }
    }
    
    //定义一个 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;
        }
    
        //为了显示方便,我们重写一下toString方法
        @Override
        public String toString() {
            return "HeroNode{" +
                    "no=" + no +
                    ", name='" + name + '\'' +
                    ", nickName='" + nickName + '\'' +
                    '}';
        }
    }
    

    程序运行结果

    HeroNode [no=1, name=宋江, nickName=及时雨]
    HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
    HeroNode [no=3, name=吴用, nickName=智多星]
    HeroNode [no=4, name=林冲, nickName=豹子头]
    

    2.2.2 考虑顺序

    代码实现

    package practiceOrder;
    
    public class SingleLinkedListDemo {
        public static void main(String[] args) {
            //测试
            // 1 先创建节点
            HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
            HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
            HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
            HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
    
            //创建链表
            SingleLinkedList singleLinkedList = new SingleLinkedList();
            //加入
            singleLinkedList.addByOrder(hero3);
            singleLinkedList.addByOrder(hero4);
            singleLinkedList.addByOrder(hero1);
            singleLinkedList.addByOrder(hero2);
            //显示
            singleLinkedList.list();
        }
    }
    
    //定义一个SingleLinkedList 管理我们的英雄
    class SingleLinkedList {
        // 1 创建一个头节点, 头节点不要动, 且不存放任何数据
        private HeroNode head = new HeroNode(0, "", "");
    
        // 2 添加节点到单向链表
        // 思路: 当考虑编号顺序时
        //       1、 首先要找到新添加的节点的位置,通过辅助的temp, 遍历
        //       2、 `新的节点.next` = `temp.next`
        //       3、 将 `temp.next` = 新的节点
        public void addByOrder(HeroNode heroNode) {
    
            // 因为 head 节点不能动, 所以我们需要一个辅助遍历 temp
            HeroNode temp = head;
            boolean flag = false;
            // 遍历链表, 找到最后
            while (true) {
                if (temp.next == null) {//temp 已在链表最后
                    break;
                }
                if (temp.next.no > heroNode.no) { //位置找到了, 就在 temp 后面插入
                    break;
                } else if (temp.next.no == heroNode.no) {//说明希望添加的heroNode的编号已经存在
                    flag = true;//说明编号存在
                    break;
                }
                temp = temp.next;
            }
            //判断flag 的值
            if (flag) {
                System.out.printf("准备添加的英雄编号 %d 已经存在,不能能再添加。", heroNode.no);
            } else {
                //插入到链表中
                heroNode.next = temp.next;
                temp.next = heroNode;
            }
        }
    
        //显示链表
        public void list() {
            //判断链表是否为空
            if (head.next == null) {
                System.out.println("链表为空。");
                return;
            }
            //因为头节点不能动, 我们需要一个 辅助变量
            HeroNode temp = head.next;
            while (true) {
                //判断是否到链表最后了
                if (temp == null) {
                    break;
                }
    //            System.out.println(temp.toString());
                System.out.println(temp);
                //将temp 后移, 一定要
                temp = temp.next;
            }
        }
    }
    
    //定义一个 HeroNode, 每一个对象就是一个节点
    class HeroNode {
        public int no;
        public String name;
        public String nickName;
        public HeroNode next;
    
        //构造器
        public HeroNode(int no, String name, String nickName) {
            this