单链表操作

一,Java中的链表

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

  2. 总结:

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

1,单链表介绍

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

在这里插入图片描述


2,单链表的CRUD操作案例
2.1,定义一个头节点做为单链表的开始,其中头节点不做数据处理,只是单链表的开始

代码:

/**
 * 定义一个单链表的头节点对象
 * 其中头节点对象包括了两部分
 * 1,data域(no,name,nameNick)
 * 2,next域(表示指向下一个节点的指针)
 */
class HeadNode_01{
    public int no;
    public String name;
    public String nameNick;
    public HeadNode_01 next;

    /**
     * 节点对象的构造方法(其中只是包括了data域看做一个对象)
     * @param no
     * @param name
     * @param nameNick
     */
    public HeadNode_01(int no,String name,String nameNick){
        this.no=no;
        this.name=name;
        this.nameNick=nameNick;
    }

    @Override
    public String toString() {
        return "HeadNode_01{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nameNick='" + nameNick + '\'' +
                '}';
    }
}

2.2,创建一个单链表对象来管理我们的实际对象数据
class SingleLinkedList_01{
    //先初始化一个头节点对象(头节点的作用是表示链表的开头,不存放任何数据)
    private HeadNode_01 head=new HeadNode_01(0,"","");

    public HeadNode_01 getHead() {
        return head;
    }
}

2.3,向单链表中添加元素(不考虑顺序)
/**
     * 单链表的创建(添加)思路
     * 1,先创建一个head头节点,作用就是表示单链表的头
     * 2,后面每添加一个节点的时候,就直接加入到链表的最后
     * 3,找到当前链表的最后一个节点
     * 4,将最后节点的next指向新增加的节点heroNode
     * @param heroNode
     */
    public void add(HeadNode_01 heroNode){
        //因为head节点不能动,因此我们需要一个辅助节点temp
        HeadNode_01 temp=head;
        //遍历找到链表的最后一个节点
        while (true){
            //找到链表的最后节点
            if(temp.next==null){
                break;
            }
            //如果没有找到最后节点,temp后移动继续往下一个节点找
            temp=temp.next;
        }
        //当退出while循环的时候,temp就指向了链表的最后,则将最后节点的next指向新增加的节点heroNode
        temp.next=heroNode;
    }

2.4,向单链表中添加元素(考虑顺序)
/**
     * 思路:
     * 1,首先找到添加节点的位置,是通过辅助变量(指针)变量来找到该位置
     * 2,将新添加的节点和后一个节点进行连线,即:新增节点.next=temp.next
     * 3,将temp和新增节点进行连线,即:temp.next=新增节点
     * @param heroNode 新增加的节点
     */
    public void addOrderHero(HeadNode_01 heroNode){
        HeadNode_01 temp=head;
        //flag标记新增加的节点标号是否已经存在
        boolean flag = false;
        while (true){
            if(temp.next==null){//说明temp已经是链表的最后
                break;
            }
            if(temp.next.no>heroNode.no){//新增的节点位置是在temp和temp.next之间
                break;
            }
            else if(temp.next.no==heroNode.no){//新增的节点标号已经存在
                flag=true;
                break;
            }
            //节点后续,继续对下一个节点进行上诉判断
            temp=temp.next;
        }
        //退出循环之后,对flag进行判断
        if(flag){
            System.out.println("新增节点的标号已经存在"+heroNode.no);
        }else{
            heroNode.next=temp.next;//将原来temp的下一个节点复制为新增节点的下一个节点上,即:将新增的节点发在temp和temp.next之间
            temp.next=heroNode;
        }
    }

2.5,通过遍历的方式,查询单链表中的所有节点信息
/**
     * 遍历整个单链表的思路
     * 1,通过一个辅助指针来实现遍历整个单链表
     * 2,判断链表是否为空,如果是空则退出循环遍历,如果不是空则输出该节点,并且后移
     *    继续对下一个节点进行判断
     */
    public void list(){
        if(head.next==null){
            System.out.println("链表为空,退出!");
            return;
        }
        //因为头节点不能动,所有借助辅助节点temp
        HeadNode_01 temp=head.next;
        while (true){
            //判断链表是否为空
            if(temp==null){
                break;
            }
            System.out.println(temp);//调试使用代码,可删除
            //将temp.next后移,继续对下个节点进行判断
            temp=temp.next;
        }
    }

2.6,修改单链表中对应节点的信息
/**
     * 修改对应编号的英雄信息
     * 1,判断链表为空的时候,直接退出
     * 2,定义一个flag标识来表示是否找到对应需要修改的节点编号
     * 3,遍历,如果到了链表最后,直接退出
     * 4,遍历,如果找到传入的编号和链表节点编号相同,则flag=true
     * @param heroNode
     */
    public void updateHero(HeadNode_01 heroNode){
        if(head.next==null){
            System.out.println("链表为空,退出!!");
            return;
        }
        HeadNode_01 temp=head.next;
        //表示是否找到需要修改的英雄编号
        boolean flag=false;
        while (true){
            if(temp==null){
                break;
            }
            if(temp.no==heroNode.no){
                flag=true;
                break;
            }
            temp=temp.next;//节点后移,对下一个节点进行遍历判断
        }
        if(flag){
            temp.name=heroNode.name;
            temp.nameNick=heroNode.nameNick;
        }else{
            System.out.println("需要修改的英雄编号不存在"+heroNode.no);
        }
    }

2.7,删除单链表中节点的信息(根据编号进行删除)
/**
     * 根据指定的英雄编号进行英雄删除
     * 思路如下:
     * 1,找到待删除节点的上一个节点
     * 2,然后将temp.next指向temp.next.next即可
     * @param no
     */
    public void deleteHero(int no){
        HeadNode_01 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);
        }
    }

3,单链表的其他常见操作
3.1,获取单链表中有效节点的个数(如果是带头节点的链表,不统计头节点)
/**
     *
     * @param headNode_01 表示链表的头节点
     * @return 返回值是链表的有效节点数
     */
    public static int getLengthLinkedList(HeadNode_01 headNode_01){
        if(headNode_01.next==null){//带头节点的空链表
            return 0;
        }
        int length=0;
        HeadNode_01 curNode=headNode_01.next;//表示不统计头节点
        while (curNode!=null){
            length++;
            curNode=curNode.next;
        }
        return length;
    }

3.2,查找单链表中的倒数第K个节点
/**
 * 思路:
 * 1,编写一个方法,接收head节点,同时接收一个index
 * 2,index表示倒数第index个节点
 * 3,先遍历得到单链表的长度size
 * 4,得到size之后,我们从链表的第一个开始遍历,遍历到(size-index),即得到结果
 * 5,如果找到,则返回该结果,否则返回null
 */
public static HeadNode_01 findLastIndexNode(HeadNode_01 headNode_01,int index){
    if(headNode_01.next==null){
        return null;
    }
    //第一次遍历
    int size = getLengthLinkedList(headNode_01);
    //第二次遍历
    if(index<=0||size<index){
        return null;
    }
    //定义一个辅助变量
    HeadNode_01 curNode=headNode_01.next;
    for(int i=0;i<size-index;i++){
        curNode=curNode.next;
    }
    return curNode;
}

3.3,实现单链表的反转功能
/**
     * 实现单链表的反转功能
     * @param headNode_01
     */
    public static void reverseHeadNode(HeadNode_01 headNode_01){
        //如果单链表为空或者单例表只有一个节点之间返回
        if(headNode_01.next==null||headNode_01.next.next==null){
            return;
        }
        //定义一个辅助指针
        HeadNode_01 curNode=headNode_01.next;
        HeadNode_01 nextNode=null;//指向当前节点【curNode】的下一个节点
        HeadNode_01 reverseNode=new HeadNode_01(0,"","");
        //遍历原来的链表,每遍历一个节点,就将其取出,并且放到新的reverseNode的最前端
        while (curNode!=null){
            nextNode=curNode.next;//暂时保存当前节点的下一个节点
            curNode.next=reverseNode.next;//将curNode的下一个节点指向新的链表的最前端
            reverseNode.next=curNode;//将curNode连接到新的链表上
            curNode=nextNode;//curNode后移动
        }
        //将原来链表的头换到反转链表的头上,即
        headNode_01.next=reverseNode.next;
    }

3.4,实现单链表的逆序打印
    /**
     * 思路
     * 1,先将单链表进行反转,然后遍历即可
     * 2,可以利用栈这个数据结构,将各个节点压入到栈中,然后利用栈的先进后出的特点,就可以实现逆序打印的效果
     */
    public static void reversePoint(HeadNode_01 headNode_01){
        //如果传入进来的节点的next为空,则说明该链表是一个空链表,直接返回不做任何处理
        if(headNode_01.next==null){
            return;
        }
        //创建一个栈,将传入进来的单链表的各个节点压入栈中
        Stack<HeadNode_01> headNode_01s = new Stack<>();
        HeadNode_01 curNode=headNode_01.next;
        //将单链表的所有节点压入栈中
        while (curNode!=null){
            headNode_01s.add(curNode);
            curNode=curNode.next;//当前节点后移,压入下一个节点到栈中
        }
        //遍历将栈中的节点打印
        while (headNode_01s.size()>0){
            //栈的特点是先进后出
            System.out.println(headNode_01s.pop());
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值