单向链表

链表是一个有序的列表,它在内存中的存储(实际结构)如下

在这里插入图片描述
链表的特点:

  1. 链表是以节点的方式来存储的
  2. 每个节点包含data域、next域:data域存放数据、next域指向下一个节点(也就是存放下一个节点的地址)
  3. 如图可以发现链表的各个节点不一定是按照内存地址连续存储的,他是按照next域中的指向的地址的顺序
  4. 链表分为带着头节点的链表和没有头节点的链表。

单链表(带头节点)逻辑结构示意图如下:

我们要知道在内存当中实际上他并不是按照顺序排列的,按照顺序排列的只是为了方便我们的理解的一个逻辑结构
在这里插入图片描述

单链表的应用实例

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

  1. 完成对英雄任务的增删改查操作
  2. 第一种方法在添加英雄时,直接添加到链表的尾部
  3. 第二种方式再添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并且给出提示

第一种方式思路分析

思路分析
在这里插入图片描述

第一种完成方式的代码实现:

package com.imagpie.linkedlist;

/**
 * @author 14767
 * 单链表代码实现
 */
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 singleLinkedList = new SingleLinkedList();
        singleLinkedList.add(hero1);
        singleLinkedList.add(hero2);
        singleLinkedList.add(hero3);
        singleLinkedList.add(hero4);
        singleLinkedList.list();


    }
}
/**
 * 定义一个SingLinkedList来管理我们的英雄节点
 */

class SingleLinkedList{
    /**
     * 先初始化一个头节点,头节点不能改变,不存放具体的数据
     */
    private HeroNode head = new HeroNode(0,"","");

    /**
     * 当不考虑编号的顺序的时候添加节点到单向链表
     * 思路
     * 1、找到当前链表的最后节点
     * 2、将最后这个节点的next指向新的节点
     */
    public void add(HeroNode heroNode){
        //由于head节点不能动,因此我们需要一个变量辅助我们遍历
        HeroNode temp = head;
        while (true){
            //找到链表的最后
            if (temp.next == null){
                break;
            }
            //如果没有找到最后,则将temp后移
            temp =temp.next;

        }
        //当退出while循环时,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);
            temp = temp.next;

        }
    }

}

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 +
                '}';
    }
}

第二种方式思路分析

在这里插入图片描述
第二种方式代码实现

 /**
     * 第二种方式在添加英雄时,根据排名将英雄插入到指定的位置
     * 如果有这个排名,则添加失败,并且给出提示
     * @param heroNode
     */
    public void addByOrder(HeroNode heroNode){
        //先创建一个临时变量用来辅助遍历
        HeroNode temp = head;
        //flag用来标记添加的节点的编号是否存在,默认为false(默认不存在)
        boolean flag = false;
        //循环查找插入的位置,找到并插入新节点
        while (true){
            //当temp中的next遍历是null的时候则表明,当前节点为末尾节点
            if (temp.next == null){
                break;
            }
            //当满足temp的next变量中的no属性大于我们传递进来变量的no属性的时候表示找到了插入的位置,就在temp后面
            if (temp.next.no > heroNode.no){
                break;
            }else if (temp.next.no == heroNode.no){
                //进到该条件那么表示,插入的HeroNode对象的no已经存在了,这时候需要将标记改为true
                flag = true;
                break;
            }
            //后移,用于遍历当前链表
            temp = temp.next;
        }
        if (flag){
            System.out.println("准备插入的英雄编号"+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);
            temp = temp.next;

        }
    }

}

修改链表中某个节点的信息

代码实现

  /**
     * 通过no来更新节点中的名称和昵称信息
     * @param heroNode
     */
    public void update(HeroNode heroNode){
        HeroNode temp = head;
        boolean flag = false;
        while (true){
            if (temp.next == null){
                break;
            }
            if (temp.next.no == heroNode.no){
                flag =true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            temp.next.name = heroNode.name;
            temp.next.nickname = heroNode.nickname;
        }else {
            System.out.println("没有找到编号为:"+heroNode.no+"的英雄");
        }
    }

删除链表中的某个节点

思路分析
在这里插入图片描述
代码实现

 /**
     * 删除节点
     * 1、head不能动,因此我们需要一个temp辅助节点找到待删除结点的前一个结点
     * 2、说明我们在比较时,是temp.next.no和需要删除的节点的no比较
     * @param no
     */
    public void del(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.println("要删除的"+no+"节点不存在");
        }
    }
posted @ 2020-12-23 17:32  谢海川  阅读(32)  评论(0)    收藏  举报