当前位置 博文首页 > 邱天的henry的博客:第三章 数据结构与算法(链表)

    邱天的henry的博客:第三章 数据结构与算法(链表)

    作者:[db:作者] 时间:2021-07-05 22:08

    3.1链表(Linked List)介绍
    ps:后面实现链表需先创建节点类,然后在创建链表

    链表是有序的列表,但是它在内存中存储如下:
    在这里插入图片描述
    小结上图:

    1. 链表是以节点的方式来存储,是链式存储
    2. 每个节点包含data域,next域:指向下一个节点
    3. 如图:发现链表的各个节点不一定是连续存储
    4. 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定

    @单链表(带头结点)逻辑结构示意图如下
    在这里插入图片描述
    3.2单链表的应用实例
    使用带head头的单向链表实现 -水浒英雄排行榜管理完成对英雄人物的增删改查操作。
    (1)第一种方法在添加英雄时,直接添加到链表的尾部

    思路分析示意图:
    在这里插入图片描述
    (2)第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)

    思路分析示意图:

    在这里插入图片描述
    (3)修改节点功能
    思路1.先找到该节点(通过遍历)2.temp.name=newHeroNode.name;temp.nickname=newHeroNode.nickname
    (4)删除节点

    思路分析示意图:
    在这里插入图片描述
    (5)实现代码演示:

    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, "林冲", "豹子头");
            HeroNode hero5 = new HeroNode(3, "孙悟空", "美猴王");
    
            //创建链表
            SingleHeroNode singleHeroNode = new SingleHeroNode();
    //        singleHeroNode.add(hero1);
    //        singleHeroNode.add(hero2);
    //        singleHeroNode.add(hero3);
    //        singleHeroNode.add(hero4);
            singleHeroNode.addByOrder(hero2);
            singleHeroNode.addByOrder(hero1);
            singleHeroNode.addByOrder(hero3);
            singleHeroNode.addByOrder(hero4);
            //singleHeroNode.addByOrder(hero5);
            singleHeroNode.update(hero5);
            singleHeroNode.delete(1);
            singleHeroNode.delete(2);
            singleHeroNode.delete(3);
            singleHeroNode.delete(4);
    
            //展示
            singleHeroNode.list();
        }
    }
    
    //创建单链表
    class SingleHeroNode{
        //首先定义头结点,头结点用来标记不可移动,所以下面遍历都需重新定义变量temp
        private HeroNode head=new HeroNode(0,"","");
    
        //添加节点方式一:不考虑顺序
        //1.首先定义一个临时变量temp来遍历链表(节点需要添加到末尾遍历出next为null的节点)
        //2.将节点添加
        public void add(HeroNode node){
            HeroNode temp=head;
            //一直循环遍历
            while (true){
                if (temp.next==null){
                    break;
                }
                //如果没有找到,则将此指针后移
                temp=temp.next;
            }
            temp.next=node;
        }
    
        //添加节点方式二:考虑节点的顺序(按照节点的编号进行添加)
        //如果编号已经存在,则提示添加失败
        public void addByOrder(HeroNode node){
            //因为头结点不可移动,所以需定义变量temp来进行遍历
            HeroNode temp=head;
            boolean flag=false; //定义标识符来标识添加的英雄编号是否存在
            //遍历找到加入节点位置的前一个位置
            while (true){
                if (temp.next==null){
                    break;  //遍历到节点末尾
                }
                if (temp.next.no>node.no){
                    break;    //说明加入节点位置的前一个节点找到
                }else if (temp.next.no==node.no){
                    flag=true;
                    break;     //加入英雄的编号已经存在,添加失败
                }
                temp=temp.next;  //以上条件不满足,指针下移
            }
            if (flag){
                System.out.printf("添加的英雄编号%d已经存在,添加失败\n",node.no);
            }else {
                node.next=temp.next;
                temp.next=node;
            }
        }
    
        //修改英雄信息(根据英雄的no修改英雄的名字和别名)
        public void update(HeroNode newHerNode){
            //定义变量temp方便遍历
            HeroNode temp=head;
            boolean falg=false;  //标识找到指定的英雄节点
            while (true){
                if (temp.next==null){
                    break;    //遍历到结尾,没有此结点
                }
                if (temp.next.no==newHerNode.no){
                    falg=true;    //标识已经找到
                    break;
                }
                temp=temp.next;
            }
            if (falg){
                temp.next.name=newHerNode.name;
                temp.next.nickName=newHerNode.nickName;
            }else {
                System.out.printf("没有%号的英雄节点,修改失败\n",newHerNode.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;   //不满足条件后移
            }
            if (flag){
                temp.next=temp.next.next;  //删除元素
            }else {
                System.out.printf("没有%d号英雄节点,删除失败\n",no);
            }
        }
    
        //遍历节点
        public void list(){
            HeroNode temp=head;
            if (temp.next==null){
                System.out.println("单链表为空");
            }
            while (true){
                if (temp.next==null){
                    break;
                }
                System.out.println(temp.next); //注意此处temp定义的头结点,所以打印temp.next
                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方法(因为此类中有next属性,为了防止重复打印后面的节点,所以省略next)
    
    
        @Override
        public String toString() {
            return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickName='" + nickName + '\'' + '}';
        }
    }
    

    单链表*面试题(新浪、百度、腾讯)
    单链表的常见面试题有如下:
    (1)求单链表中有效节点的个数
    (2)查找单链表中的倒数第K个节点【新浪面试题】
    (3)单链表的反转【腾讯面试题,有点难度】
    (4)从尾到头打印单链表【百度,要求方式1;反向遍历。方式2:Stack栈】

    代码:为了方便书写和观看,上述的题目直接写在实现单链表的上面

    package com.itcast.linkedList;
    
    import java.util.Stack;
    
    public class SingleLinkedListDemo {
        public static void main(String[] args) {
            //测试,先创建节点
            HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
            HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
            HeroNode hero3 = new HeroNode(