单链表的有关知识以及增删改查

16 篇文章 0 订阅
14 篇文章 0 订阅

1,单链表是一种线性数据结构,但是它不一定是连续的,是一种链式存储结构(如下图)

单链表的每个节点分为data域(值域)和next域(指向下一个节点)

单链表分为有头节点没有头节点,有头结点,头结点只有next域而没有data域

image-20200713192621025

2,单链表的应用场景:举例水浒英雄排行榜(尚硅谷官方讲解):

定义:

no:英雄编号

name:英雄名称

nikeName:英雄昵称

next:指向下一个英雄节点

特别注意:

插入的时候判断的条件是新插入节点的编号与temp.next.no做比较,即temp.next.no>NewHeroNode.no,所以temp=head

显示链表的时候是从head.next显示的,所以temp=head.next

更新的时候是判断输入的点的no与每个节点的no是否相等,即temp.no==heroNode.no.所以temp=head.next

删除的时候是让删除节点的前一个节点的next.next与删除节点的next相等,即temp.next==temp.next.next,所以temp=head

换句话说:

遍历链表,执行操作时,判断条件有时候是 temp ,有时候是 temp.next ,Why?
对于插入、删除节点来说,需要知道当前待操作的节点(heroNode)前一个节点的地址(指针),如果直接定位至当前待操作的节点 heroNode ,那没得玩。。。因为不知道heroNode 前一个节点的地址,无法进行插入、删除操作,所以 while 循环中的条件使用 temp.next 进行判断
对于更新、遍历操作来说,我需要的仅仅就只是当前节点的信息,所以 while 循环中的条件使用 temp进行判断

public class singleList {
    public static void main(String[] args) {
        System.out.println("没有按照英雄序号的单链表如下");
            // 进行测试
            // 先创建节点
            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(hero2);
            singleLinkedList.add(hero1);
            singleLinkedList.add(hero3);
            singleLinkedList.add(hero4);
            //删除

        singleLinkedList.del(1);

            singleLinkedList.list();


        System.out.println("修改过后的单链表为");
            HeroNode newHeroNode=new HeroNode(2,"小卢~~~","玉麒麟~~~");
            singleLinkedList.update(newHeroNode);
            singleLinkedList.list();
        System.out.println("按照英雄序号的单链表如下");

        // 创建要给链表
        SingleLinkedList singleLinkedList2 = new SingleLinkedList();
        // 加入
        singleLinkedList2.addByOrder(hero2);
        singleLinkedList2.addByOrder(hero1);
        singleLinkedList2.addByOrder(hero3);
        singleLinkedList2.addByOrder(hero4);
        singleLinkedList2.list();
        }
}
//定义 HeroNode类,里面定义了每一个英雄节点
class HeroNode{
    public int no;
    public  String name;
    public  String nikeName;
    public HeroNode next;
//定义构造器,输入每一个英雄的编号,姓名,绰号
    public HeroNode(int no, String name, String nikeName) {
        this.no = no;
        this.name = name;
        this.nikeName = nikeName;
    }
//重写toString方法,吧我们输入的节点值输出出来
    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nikeName='" + nikeName + '\'' +
                '}';
    }
}
//定义一个单链表SingleLinkedList来管理我们的英雄们
class SingleLinkedList{
    //创建一个头结点,头结点是单链表的入口,不能动,也不春芳具体的数据,只指向下一个节点
    private HeroNode head=new HeroNode(0,"","");
    //我们定义一个现实该单链表的方法list()
    //首先我们定义辅助变量temp,相当于一个指针,指向当前节点的下一个节点
    //当temp==null的时候表示到底了
    //遍历的时候我们只需要temp=temp.next
    public void list(){
        if (head.next==null){
            System.out.println("链表为空");
            return;
        }
        //因为我们不出书head,所以我们遍历链表的时候把temp首先指向head.next
        HeroNode temp=head.next;
        while (true){
            //判断是否到链表的最后
            if (temp==null){
                break;
            }
            System.out.println(temp);
            temp=temp.next;
        }
    }
    //我们在向链表中插入数据时候,先不考虑英雄的编号问题,我们用尾部插入法来插入数据
//找到当前链表的最后一个节点
// 然后差这个节点的next指向新插入的节点
    public void add(HeroNode heroNode){
        //因为head节点不能动,因此我们需要一个辅助遍历temp
        //这时我们是从head的下一个节点开始插入数据,而我们的思路是temp.next=heroNode.所以我们定义temp=head,即从第一个开始插入
        //如果我们定义temp=head.next.这时我们插入的一个节点heroNode是第二个节点,第一个节点空了,就会显示链表为空
        HeroNode temp=head;
        //这个循环就是找到链表的最后
        while (true){
            //找到了链表的最后,遍历结束
            if (temp.next==null){
                break;
            }
            //如果我们没有找到链表的最后,将temp后移
            temp=temp.next;
        }
        //当退出这个循环的时候,temp就是链表的最后
        //这是我们将temp的next指向我们插入的新节点即可
        temp.next=heroNode;
    }

    //我们如何按照英雄的序号来进行单链表的插入呢?
    //1,定义一个辅助变量temp,指向当前节点
    //2,如果temp.next.no>heroNode.no,我们便可以把新的节点插入到temp.next节点之前
    //3.heroNode.next=temp.next;  temp.next=heroNode;
    public void addByOrder(HeroNode heroNode){
        //因为是单链表,我们head不能动,所以我们创建一个辅助指针
        HeroNode temp=head;
        boolean flag=false;//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){//说明添加新的英雄的编号已经存在
                flag=true;//说明编号存在
                break;
            }
            temp=temp.next;
        }
        if (flag){
            System.out.printf("编号%d已经存在,不能插入\n",heroNode.no);
        }else {
            heroNode.next=temp.next;
            temp.next=heroNode;
        }
    }

    //修改节点信息
    //定义一个辅助变量temp指向当前节点,当temp.no=newHeroNode.no的时候,改变temp节点的值
    public void update(HeroNode heroNode){
        if (head.next==null){//判断是否为空
            System.out.println("链表为空");
            return;
        }
        //遍历,这个时候我们要从head.next来判断这个点和我们新输入的点的序号no是否一致
        HeroNode temp=head.next;
        boolean flag=false;//表示是否找到该节点
        while (true){
            if (temp==null){
                break;//已经遍历结束
            }
            if (temp.no==heroNode.no){//找到
                flag=true;
                break;
            }
            temp=temp.next;
        }
        //根据flag判断是否能找到要修改的节点
        if (flag){
            temp.name=heroNode.name;
            temp.nikeName=heroNode.nikeName;
        }else {//没有找到
            System.out.printf("没有找到编号$d的节点,不能修改\n",heroNode.no);
        }
    }
//删除节点
    //1,我们首先找到要删除的节点的前一个节点temp,如果我们找要删除的节点,单向链表无法操作
    //2,然后我们把temp.next=temp.next.next
    //3,被删除的节点.将不会有其他引用指向,会被垃圾回收机制回收
public void del(int no){
        //因为第一个节点也有可能被删除,所以我们把temp=head
        HeroNode temp=head;
        boolean flag=false;//标志着是否找到删除的节点
    while (true){
        if (temp==null){//已经找到看了链表的最后
            break;
        }
        if (temp.next.no==no){//找到删除的节点
            flag=true;
            break;
        }
        temp=temp.next;//temp后移,遍历
    }
    //判断flag
    if (flag){//知道到
        //可以删除
        temp.next=temp.next.next;
    }else{
        System.out.printf("要删除的%d节点不出在\n",no);
    }
}
}



参考文献:第 4 章 链表_Oneby的博客-CSDN博客;尚硅谷Java数据结构与java算法(Java数据结构与算法)_哔哩哔哩_bilibili

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值