单向链表的基本操作

生活中,有一种单线联络的方式;即该工作者只有一个上级和一个下级,不与其他人发生工作联系。这种方式在计算机中也有很好的体现,例如数据结构中的链表。

链表

链表是一种在物理上非连续,非顺序的数据结构,是以若干个节点组成的链式存储形式。
在这里插入图片描述
在这里插入图片描述
上图是两种形式的链表:单向链表和双向链表,下面主要介绍单向链表。

单向链表

单向链表的每一个节点包含两部分:一部分为存储数据的变量Date,一部分是指向下一个节点的指针next,链表的第一个节点称为头结点,最后一个节点称为尾节点,尾节点的next指针指向空。
与数组按照下标来寻找元素不同,链表只能通过从头结点开始遍历,然后通过next指针来找到下一个节点。

单向链表的基本操作

1.查找节点
    链表在查找节点元素的时候,只能从头节点开始一个一个节点遍历查找。

在这里插入图片描述

2.更新节点
   先通过遍历查找到该节点,然后直接对该节点的数据进行替换即可完成节点的更新。

在这里插入图片描述

3.插入节点
       - 尾部插入:直接把之后一个节点的next指针指向心插入的节点即可。
       - 中间插入:新节点的next指针,指向插入位置的节点;插入位置前置节点的next指针,指向新节点。
       - 头部插入:把新节点的next指向原链表的头节点;将新节点变成链表的头节点。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.删除节点
      - 尾部删除:将尾部节点的前置节点的next指针指向null即可。
      - 中间删除:将需要删除的节点的前置节点的next指针,直接指向需要删除节点的后置节点即可。
      - 头部删除:将链表的头部直接设置为原链表头节点的next指针即可。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上是链表操作的基本思路,在链表操作中,一般分为两种情况:第一种是头节点不存储数据;第二种是头节点存储数据。但是整体上的操作思路不会有大的变化。
以下为头节点不存储有效数据的一些功能实现

/**
 * 定义水浒英雄节点类
 */
class HeroNode{
    public int rank;//排名
    public String name;//姓名
    public String nickname;//昵称
    public HeroNode next = null;//指针: 指向下一个节点

    /**
     * 构造方法:用于构建英雄对象
     * @param rank 排名
     * @param name 姓名
     * @param nickname  昵称
     */
    public HeroNode(int rank, String name,String nickname){
        this.rank = rank;
        this.name = name;
        this.nickname = nickname;
    }
    @Override
    public String toString() {
        return "HeroNode{" +
                "rank=" + rank +
                ", name='" + name + '\'' +
                ", nickname='" + nickname + '\'' +
                '}';
    }
}

/**
 * 单向链表实现: 头结点不存储有效数据
 */
class SingleLinkedList{

    //初始化头结点 头结点不存储有效数据
    HeroNode head = new HeroNode(0,"","");

    /**
     * 遍历链表的有效数据
     */
    public void showNode(){
        //头节点的next指针指向空,表明该链表没有有效数据
        if(head.next == null){
            System.out.println(" 链表为空... ");
            return;
        }
        //通过辅助指针temp操作数据
        HeroNode temp = head.next;
        while(true){
            if(temp == null){//如果节点为空,表明链表已遍历完毕
                return;
            }
            System.out.println(temp);//打印节点数据
            temp = temp.next;//移动辅助指针指向下一个节点
        }
    }

    /**
     * 在链表末尾添加节点
     *      遍历链表,通过当前节点的next指针指向是否为空来确定当前指针是否是尾节点
     *      若当前指针是尾节点,则将当前节点的next指针指向要添加的节点
     *      若当前指针不是尾节点,则继续遍历,直到找到尾节点
     * @param node
     */
    public void addNode(HeroNode node){
        //定义辅助指针 指向头节点
        HeroNode temp = head;
        while(true){
            if(temp.next == null){//如果当前节点的next指针指向空,表明为尾节点
                temp.next = node;//将尾节点的next指向新节点,实现尾部插入。
                return;
            }
            temp = temp.next;//移动辅助指针指向下一个节点
        }
    }

    /**
     * 根据排名将英雄插入指定位置(英雄排名从 1 开始增加)
     *      遍历链表,当前节点的next指针指向的下一个节点的英雄排名大于要添加的英雄,则表名找到了添加位置
     *               当前节点的next指针指向了null,则表明当前节点是尾节点,要添加的英雄排名数字比链表中任何的一个都大,所以直接添加到末尾即可
     *               当前节点的next指针指向节点的英雄排名等于要添加的英雄,则表名该排名已存在英雄,做出相应提示
     */
    public void addNodeByOrder(HeroNode heroNode){
        //定义辅助指针 指向头节点
        HeroNode temp = head;
        while(true){
            //在链表中没找到该节点的插入位置,将该节点插入到尾部
            if(temp.next == null){//如果当前节点的next指针指向空,表明为尾节点
                temp.next = heroNode;//将尾节点的next指向新节点,实现尾部插入。
                return;
            }
            //在链表中找到了该节点的插入位置
            if(temp.next.rank > heroNode.rank){
                heroNode.next = temp.next;
                temp.next = heroNode;
                return;
            }
            if(temp.next.rank == heroNode.rank){
                System.out.println("该排名已经存在,不能添加");
                return;
            }
            temp = temp.next;
        }
    }


    /**
     * 通过英雄排名  修改节点信息
     *    遍历链表,若当前节点为空,则表明该链表中没有该英雄 无法完成删除
     *             若当前节点的英雄排名等于要修改的英雄排名,直接对英雄信息做出修改即可
     *
     * @param heroNode
     */
    public void updateNode(HeroNode heroNode){
        //定义辅助指针 指向头节点
        HeroNode temp = head;
        while(true){
            if (temp != null){//当前节点不为空, 则判断当前节点是否为要修改的节点
                if(temp.rank == heroNode.rank){//是需要修改的节点
                    //修改节点信息
                    temp.name = heroNode.name;
                    temp.nickname = heroNode.nickname;
                    return;
                }
                //不是需要修改的节点 则移动辅助指针指向下一个节点
                temp = temp.next;
            }else {//当前节点为空,表明链表中不存在该需要修改的节点
                System.out.println("没有该排名的英雄,无法完成修改");
                return;
            }
        }
    }

    /**
     * 根据排名删除节点
     *     遍历链表,判断当前节点的next指针指向的英雄是否为要删除的英雄
     *          若是: 则将当前节点的next指针直接指向当前节点的next指针指向的节点的next指针的节点
     *          若不是:继续遍历,当当前节点的next指针指向了空,则表明当前节点为尾节点,链表中没有要删除的那个节点
     * @param rank
     */
    public void deleteNode(int rank){
        //定义辅助指针 指向头节点
        HeroNode temp = head;
        while (true){
            //遍历寻找要删除节点的前置节点
            if(temp.next != null){
                if(temp.next.rank == rank){
                    temp.next = temp.next.next;
                    return;
                }
                //不是要删除的节点 则移动辅助指针指向下一个节点
                temp = temp.next;
            }else {
                System.out.println("没有该节点,无法完成删除");
                return;
            }

        }
    }
}
/**
 * 测试单向链表
 */
public class SingleLinkedListDemo {

    public static void main(String[] args) {

        //创建链表对象
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        //创建节点对象
        HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
        HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode hero3 = new HeroNode(3, "吴用", "小星星");
        HeroNode hero4 = new HeroNode(6, "林冲", "豹子头");
        //将节点添加到链表中
        singleLinkedList.addNode(hero1);
        singleLinkedList.addNode(hero2);
        singleLinkedList.addNode(hero3);
        singleLinkedList.addNode(hero4);
        System.out.println("--------添加英雄到链表-----------");
        //遍历链表
        singleLinkedList.showNode();
        System.out.println("-------------------");

        System.out.println("----------按照排名添加英雄到链表---------");
        HeroNode hero5 = new HeroNode(4, "公孙胜", "入云龙");
        HeroNode hero6 = new HeroNode(5, "关胜", "大刀");
        //按照排名添加英雄
        singleLinkedList.addNodeByOrder(hero5);
        singleLinkedList.addNodeByOrder(hero6);
        //遍历链表
        singleLinkedList.showNode();
        System.out.println("-------------------");

        System.out.println("---------修改英雄信息----------");
        //修改英雄信息
        hero3 = new HeroNode(3, "吴用", "智多星");
        singleLinkedList.updateNode(hero3);
        //遍历链表
        singleLinkedList.showNode();
        System.out.println("-------------------");

        System.out.println("---------删除英雄----------");
        //删除英雄
        singleLinkedList.deleteNode(4);
        //遍历链表
        singleLinkedList.showNode();
        System.out.println("-------------------");

    }
}

当头节点存储有效数据时,通过分析主要修改的是插入和删除,还有遍历会有点小的变动。修改单链表实现类如下:

/**
 * 单向链表实现: 头结点存储有效数据
 */
class SingleLinkedList{

    //初始化头结点
    HeroNode head;
    boolean flag = true;

    /**
     * 遍历链表的有效数据
     */
    public void showNode(){
        if(head.next == null){
            return;
        }
        //头结点不能移动 所以需要辅助节点
        HeroNode temp = head;
        while(true){
            if(temp == null){
                return;
            }
            System.out.println(temp);
            temp = temp.next;
        }
    }

    /**
     * 在链表末尾添加节点
     * @param node
     */
    public void addNode(HeroNode node){
        if(flag){
            head = node;
            flag = false;
            return;
        }
        //头结点不能移动 所以需要辅助节点
        HeroNode temp = head;
        while(true){
            if(temp.next == null){
                temp.next = node;
                return;
            }
            temp = temp.next;
        }

    }

    /**
     * 根据排名将英雄插入指定位置
     */
    public void addNodeByOrder(HeroNode heroNode){
        //判断头节点为空时
        if(flag){
            head = heroNode;
            flag = false;
            return;
        }
        HeroNode temp = head;
        if(head != null && heroNode.rank < head.rank){
            heroNode.next = temp;
            head = heroNode;
            return;
        }
        while(true){
            if(temp.next == null){
                temp.next = heroNode;
                return;
            }
            if(temp.next.rank > heroNode.rank){
                heroNode.next = temp.next;
                temp.next = heroNode;
                return;
            }
            if(temp.next.rank == heroNode.rank){
                System.out.println("该排名已经存在,不能添加");
                return;
            }
            temp = temp.next;
        }
    }


    /**
     * 通过英雄排名  修改节点信息
     * @param heroNode
     */
    public void updateNode(HeroNode heroNode){
        HeroNode temp = head;
        while(true){
            if (temp != null){
                if(temp.rank == heroNode.rank){
                    temp.name = heroNode.name;
                    temp.nickname = heroNode.nickname;
                    return;
                }
                temp = temp.next;
            }else {
                System.out.println("没有该排名的英雄,无法完成修改");
                return;
            }
        }
    }

    /**
     * 根据排名删除节点
     * @param rank
     */
    public void deleteNode(int rank){
        //删除头节点
        if(rank == head.rank){
            head = head.next;
            return;
        }
        //删除其他节点
        HeroNode temp = head;
        while (true){
            if(temp.next != null){
                if(temp.next.rank == rank){
                    temp.next = temp.next.next;
                    return;
                }
                temp = temp.next;
            }else {
                System.out.println("没有该节点,无法完成删除");
                return;
            }

        }
    }
}

以上主要是通过一个标志位实现的头节点存储有效数据,其实实现方式多种多样,欢迎大家给我提供各种思路来实现,同时帮助我查出我的代码错误之处,谢谢。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值