数据结构第二天之单链表

单链表结构的创建及实现单链表的增删改查:

//定义一个LinkedList来管理我们的英雄
class LinkedList{
    //初始化头节点,头节点不能动
    private HeroNode head = new HeroNode(0,"","");
    //返回头节点
    public HeroNode getHead(){
        return head;
    }
    //添加英雄的方法(不考虑排名)
    public void addNode(HeroNode heroNode){
        //定义一个临时节点,用于遍历链表
        HeroNode temp = head;
        //当temp.next=null时可以把节点添加到链表中
        while (true){
            if (temp.next==null){
                break;
            }
            //如果temp.next不为空,则temp后移
            temp = temp.next;
        }
        //退出循环时进行添加节点,加在temp后面
        temp.next = heroNode;
    }

    //遍历链表的方法,用于查看排行
    public void showLinkedList(){
        //判断链表是否为空
        if (head.next==null){
            System.out.println("链表为空");
        }
        //定义一个临时节点,用于遍历链表
        HeroNode temp = head.next;
        while (true){
            if (temp==null){
                break;
            }
            System.out.println(temp);
            //每次输出完信息后,指针后移
            temp = temp.next;
        }
    }

    //第二种方式在添加英雄时,根据排名将英雄插入到指定位置
    //(如果有这个排名,则添加失败,并给出提示)
    public void addByOrder(HeroNode heroNode){
        //定义一个临时变量,用于遍历链表
        HeroNode temp = head;
        boolean flag = false;
        while (true){
            if (temp.next==null){
                //链表为空,直接插入
                break;
            }

            if (temp.next.no>heroNode.no){
                //要插入的节点的排名位于temp和temp.next之间,可以插入
                break;
            }else if (temp.next.no == heroNode.no){
                //要插入的节点以及存在,不可以插入
                flag = true;
            }

            //temp后移
            temp = temp.next;
        }
        if (flag){
            System.out.println("要插入的节点已存在,不能进行添加");
        }else{
            //插入到temp的后面
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }

    //删除节点的方法
    public void delNode(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){
            //找到则进行删除
            //遍历节点的下一个节点是要删除的节点,把临时节点,赋值给删除的节点的下一个节点,则要删除的节点会被gc回收
            temp.next = temp.next.next;
        }else {
            System.out.printf("要删除的%d节点不存在\n",no);
        }

    }

    //修改节点信息
    public void upgradeNode(HeroNode newNode){
        if (head.next==null){
            System.out.println("链表为空~");
            return;
        }
        //定义一个临时节点
        //通过no来修改
        HeroNode temp = head;
        boolean flag = false;//标志是否找到该节点
        while (true){
            if (temp.next == null){
                break;
            }
            if(temp.next.no==newNode.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            //进行修改
            temp.next.name = newNode.name;
            temp.next.nickName = newNode.nickName;
        }else {
            System.out.println("没有找到该节点");
        }
    }
}
//英雄节点,每个节点中存放数据域data和指向的下一个节点next指针
class HeroNode{
    public int no;//英雄排名
    public String name;//英雄名字
    public String nickName;//英雄绰号
    public HeroNode next;//指向下一个节点

    public HeroNode(int hNo,String hName,String hNickname){
        this.no = hNo;
        this.name = hName;
        this.nickName = hNickname;
    }

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

单链表的练习题:

package com.xatu.linkedlist;

import org.junit.Test;

import java.util.Stack;

/**
 * @author blackCat
 * @create 2022-07-28 22:26
 */
public class SingleLinkedListExer {
    /*
        求单链表中有效节点的个数
     */
    @Test
    public void test1(){
        HeroNode node1 = new HeroNode(1,"宋江","及时雨");
        HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
        HeroNode node3 = new HeroNode(3,"林冲","豹子头");
        HeroNode node4 = new HeroNode(4,"关胜","大刀");
        LinkedList list = new LinkedList();
        list.addNode(node1);
        list.addNode(node2);
        list.addNode(node3);
        list.addNode(node4);
        list.showLinkedList();
        int length = getLength(list.getHead());
        System.out.println("有效节点的个数为:"+length);
    }
    //不计算头节点
    public static int getLength(HeroNode head) {
        if (head.next==null){
            return 0;
        }
        //定义一个临时变量用于遍历链表
        HeroNode temp = head.next;
        int length = 0;
        while (temp!=null){
            length++;
            temp = temp.next;
        }
        return length;
    }

    /*
        查找单链表中的倒数第k个节点
     */
    @Test
    public void test2(){
        HeroNode node1 = new HeroNode(1,"宋江","及时雨");
        HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
        HeroNode node3 = new HeroNode(3,"林冲","豹子头");
        HeroNode node4 = new HeroNode(4,"关胜","大刀");
        LinkedList list = new LinkedList();
        list.addNode(node1);
        list.addNode(node2);
        list.addNode(node3);
        list.addNode(node4);
        //list.showLinkedList();
        HeroNode lastIndexNode = findLastIndexNode(list.getHead(), 3);
        System.out.println("单链表倒数第k个节点为:"+lastIndexNode);
    }

    public HeroNode findLastIndexNode(HeroNode head,int index){
        if (head.next==null){
            //链表为空,返回null
            return null;
        }
        //获取链表的有效个数
        int size = getLength(head);
        //校验index的有效性
        if (index<0||index>size){
            return null;
        }
        //遍历链表,遍历(size-index)次
        //定义一个临时节点,用于遍历
        HeroNode temp = head.next;
        for (int i = 0; i < (size - index); i++) {
            temp = temp.next;
        }
        return temp;
    }
    /*
        单链表的反转
     */
    @Test
    public void test3(){
        HeroNode node1 = new HeroNode(1,"宋江","及时雨");
        HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
        HeroNode node3 = new HeroNode(3,"林冲","豹子头");
        HeroNode node4 = new HeroNode(4,"关胜","大刀");
        LinkedList list = new LinkedList();
        list.addNode(node1);
        list.addNode(node2);
        list.addNode(node3);
        list.addNode(node4);
        reverseList(list.getHead());
        System.out.println("反转后的单链表为:");
        list.showLinkedList();
    }
    //思路:1.先定义一个节点reverseHead
    //2.遍历初始链表,每遍历一个节点,就将其取出,并放在新链表的头节点reverseHead的最前端
    public void reverseList(HeroNode head){
        //如果链表为空,或链表只有一个元素则无需反转
        if (head.next==null||head.next.next==null){
            return;
        }
        //定义一个reverseHead
        HeroNode reverseHead = new HeroNode(0,"","");
        //定义一个临时节点,用于遍历
        HeroNode temp = head.next;
        //定义一个节点,用于保存[temp]后一个节点
        HeroNode next = null;
        while (temp!=null){
            next = temp.next;
            temp.next = reverseHead.next;//保证reverseHead每次都连接的是temp的后面的节点
            reverseHead.next = temp;
            temp = next;//把temp连接到新链表上
        }
        head.next = reverseHead.next;//原始链表的同节点取代新链表的头节点,实现反转
    }

    /*
        从头到尾打印单链表(使用栈存取节点、利用栈先进后出的特点)
     */
    @Test
    public void test4(){
        HeroNode node1 = new HeroNode(1,"宋江","及时雨");
        HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
        HeroNode node3 = new HeroNode(3,"林冲","豹子头");
        HeroNode node4 = new HeroNode(4,"关胜","大刀");
        LinkedList list = new LinkedList();
        list.addNode(node1);
        list.addNode(node2);
        list.addNode(node3);
        list.addNode(node4);
        System.out.println("从头到尾打印单链表:");
        reversePrint(list.getHead());
    }

    public void reversePrint(HeroNode head){
        if (head.next==null){
            return;//空链表
        }
        Stack<HeroNode> stack = new Stack<>();
        HeroNode temp = head.next;
        while (temp!=null){
            stack.push(temp);//把数据压入栈
             temp = temp.next;//指针后移
        }
        //遍历栈中的数据
        while (stack.size()>0){
            System.out.println(stack.pop());
        }
    }
    //将两个有序单链表合并成一个有序单链表
    @Test
    public void test(){
        HeroNode node1 = new HeroNode(3,"宋江","及时雨");
        HeroNode node2 = new HeroNode(5,"卢俊义","玉麒麟");
        HeroNode node3 = new HeroNode(9,"林冲","豹子头");
        HeroNode node4 = new HeroNode(7,"关胜","大刀");
        LinkedList list1 = new LinkedList();
        list1.addByOrder(node1);
        list1.addByOrder(node2);
        list1.addByOrder(node3);
        list1.addByOrder(node4);

        HeroNode node5 = new HeroNode(1,"张无忌","大魔头");
        HeroNode node6 = new HeroNode(6,"张三丰","大大魔头");
        HeroNode node7 = new HeroNode(2,"谢逊","小魔头");
        HeroNode node8 = new HeroNode(4,"周芷若","小小魔头");
        HeroNode node9 = new HeroNode(8,"张翠山","小小小魔头");
        LinkedList list2 = new LinkedList();
        list2.addByOrder(node5);
        list2.addByOrder(node6);
        list2.addByOrder(node7);
        list2.addByOrder(node8);
        list2.addByOrder(node9);
        System.out.println("合并前的两个有序列表");
        list1.showLinkedList();
        System.out.println();
        list2.showLinkedList();
        LinkedList list3 = mergeList(list1, list2);
        System.out.println("两个有序列表合并后的有序列表");
        list3.showLinkedList();

    }

    public LinkedList mergeList(LinkedList list1,LinkedList list2){
        //思路
        //初始化n1,n2两个指针,n1指向list1的第一个节点,n2指向list2的第一个节点
        //初始化n3,指向list1的头节点
        //当n1,n2没有到达单链表的尾部时,选出排名较小的节点赋值给n3.next
        //当n1或n2到达链表尾部时,n3指向后到达尾部的节点
        HeroNode n1 = list1.getHead().next;
        HeroNode n2 = list2.getHead().next;
        HeroNode n3 = list1.getHead();
        while (n1!=null&&n2!=null){
            if (n1.no>=n2.no){
                n3.next = n2;
                n2 = n2.next;
            }else {
                n3.next = n1;
                n1 = n1.next;
            }
            n3 = n3.next;
        }
        n3.next = n1 == null ?n1:n2;
        return list1;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

helloworld*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值