韩老师——数据结构与算法—单链表的生成及增删改查操作和常见关于链表的面试题java代码实现

话不多说直接上代码。 

public class SingleLinkedListDemo {

    public static void main(String[] args) {
        //测试
        HeroNode node1 = new HeroNode(1,"宋江","及时雨");
        HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
        HeroNode node3 = new HeroNode(3,"吴用","智多星");
        HeroNode node4 = new HeroNode(4,"林冲","豹子头");

        //创建链表
        SingleLinkedList list = new SingleLinkedList();
        //添加
//        list.add(node1);
//        list.add(node2);
//        list.add(node3);
//        list.add(node4);

        //按照编号添加
        list.addByOrder(node1);
        list.addByOrder(node4);
        list.addByOrder(node3);
        list.addByOrder(node2);

        //测试getLength()方法
        System.out.println("有效的节点长度为:"+getLength(list.getHead()));
        //显示链表
        list.listNode();
    }


    //常见面试题

    /**
     * 1.求链表长度
     * @param head 头节点
     * @return 链表长度(不包含头节点)
     */
    public static int getLength(HeroNode head){
        if (head.next == null){ //空链表
            return 0;
        }
        HeroNode current = head.next;
        int length = 0;
        while(current != null){
            length++;
            current = current.next;
        }
        return length;
    }


    /**2.返回链表中倒数第n个元素
     * 思路:①编写方法,接收head节点,和index
     *             index表示倒数第index个节点
     *             ②先把链表遍历,得到链表长度
     *             ③得到length后,从链表第一个开始遍历,遍历(length-index)个,就得到目标节点
     * @param head 头节点
     * @param index 倒数索引
     * @return
     */
    public static HeroNode findLastIndexNode(HeroNode head,int index){
        //判断链表是否为空
        if (head.next == null){
            System.out.println("链表为空");
            return null; //没找到
        }
        //遍历得到长度
        int length = getLength(head);
        //第二次遍历length-index个,就是目标节点
        //先校验index的合理性
        if (index <= 0 || index > length){
            return null;
        }
        HeroNode current = head.next; //指向第一个节点
        for (int i = 0;i<length-index;i++){
            current = current.next;
        }
        return current;
    }


    /**
     * 3.链表反转
     *         思路:①先定义一个节点reverseHead = new HeroNode();
     *             ②从头遍历原来的链表,每遍历一个节点,将其取出,放到reverseHead的最前端
     *             ③原来链表的head.next = reverseHead.next;
     * @param head
     */
    public static void reverseList(HeroNode head){
        //如果当前链表为空,或者只有一个节点,无需反转
        if (head.next == null || head.next.next == null){
            return;
        }
        //定义一个辅助指针,帮助我们遍历原来的链表
        HeroNode current = head.next;
        HeroNode next = null; //指向当前节点的下一个节点,后边会用
        HeroNode reverseHead = new HeroNode(0,"","");
        //遍历原来的链表,每遍历一个就放在reverseHead的最前端
        while (current != null){
            next = current.next; //暂时保存当前节点的下一个节点
            current.next = reverseHead.next; //将current节点插入到reverseHead最前端
            reverseHead.next = current;
            current = next; //指针后移
        }
        //将head.next指向reverseHead.next,实现反转
        head.next = reverseHead.next;
    }

    /**
     * 4.连表的反向输出
     * 方式一:先将链表反转,之后遍历链表输出。但是此方式破坏了原来链表的结构
     * 方式二:使用栈的先进后出原则实现反向输出
     * @param head
     */
    public static void reversePrint(HeroNode head){
        if (head.next == null){
            System.out.println("链表为空");
        }
        //创建栈对象,将各节点入栈
        Stack<HeroNode> stack = new Stack<>();
        //遍历入栈
        HeroNode current = head.next;
        while (current != null){
            stack.add(current);
            current = current.next;
        }
        while (stack.size() > 0){
            System.out.println(stack.pop());
        }
    }
    //合并两个有序的单链表,合并后依然有序
    public static SingleLinkedList mergeList(SingleLinkedList list1,SingleLinkedList list2){
        HeroNode head1 = list1.getHead();
        HeroNode head2 = list2.getHead();
        //创建一个新的单链表用来存放合并后的数据。
        SingleLinkedList mergeList = new SingleLinkedList();
        HeroNode mergeHead = mergeList.getHead();
        if (head1.next == null && head2.next == null){
            return null;
        }
        if (head1.next == null && head2.next != null){
            return list2;
        }
        if (head1.next != null && head2.next == null){
            return list1;
        }

        HeroNode temp1 = head1.next; //指向第一个链表的第一个元素
        HeroNode temp2 = head2.next; //指向第二个链表的第一个元素
        HeroNode next; //保存当前节点下一节点的临时变量
        while(temp1 != null && temp2 != null){
            if (temp1.no < temp2.no){
                next = temp1.next; //将当前要插入的节点的下一节点的指针给next,后边会用
                temp1.next = null; //将当前节点的next域置空,不然其后边的节点也会插入合并后的链表
                mergeList.add(temp1);
                temp1 = next;
            }else if (temp1.no > temp2.no){
                next = temp2.next;
                temp2.next = null;
                mergeList.add(temp2);
                temp2 = next;
            }else{  //如果两个序号相等,只加入其中一个链表的数据即可
                next = temp1.next; //将当前要插入的节点的下一节点的指针给next,后边会用
                temp1.next = null; //将当前节点的next域置空,不然其后边的节点也会插入合并后的链表
                mergeList.add(temp1);
                temp1 = next;
                temp2 = temp2.next;  //因为只加入一个且两节点的序号相同,所以2表的指针也要后移。
            }
        }
        // 出了循环会有一张表有剩余,处理剩余的节点
        if (temp1 != null && temp2 == null){
            while(temp1 != null){
                next = temp1.next;
                temp1.next = null;
                mergeList.add(temp1);
                temp1 = next;
            }
        }else if (temp1 == null && temp2 != null){
            while (temp2 != null){
                next = temp2.next;
                temp2.next = null;
                mergeList.add(temp2);
                temp2 = next;
            }
        }
        return mergeList;

    }

}


//定义一个SingleLinkedList来管理节点
class SingleLinkedList{
    //初始化一个头节点,不存放具体数据,只指向表头

    private HeroNode head = new HeroNode(0,"","");

    public HeroNode getHead() {
        return head;
    }

    /*
    添加节点到链表
    当不考虑编号顺序时:①先找到链表的最后一个节点 ②将最后节点的next域指向新的节点
    */
    public void add(HeroNode heroNode){

        //因为头节点不能动,所以需要一个辅助变量来遍历
        HeroNode temp = head;
        //遍历链表,找到最后的节点
        while(true){

            if (temp.next == null){
                break;
            }
            //如果没到最后就修改指针,指向下一个节点
            temp = temp.next;
        }
        //当退出循环时,说明到了链表的最后节点
        //将最后节点的next域修改为要插入的节点即可
        temp.next = heroNode;
    }

    /**
     * 需求:按照编号顺序添加
     * 思路:①首先找到新节点在链表中的位置(通过辅助变量遍历)
     *      ②新节点的next域等于临时变量的next域(新节点.next = temp.next)
     *      ③将temp的next域指向新节点(temp.next = 新节点)
     */
    public void addByOrder(HeroNode node){
        //头节点不能动,所以还是需要辅助变量来遍历
        //因为是单链表,需要找到要插入位置的前一个元素
        HeroNode temp = head;
        boolean flag = false;  //添加的编号是否存在的标志,默认为false
        while (true){
            if (temp.next == null){ //说明temp已经是链表的最后一个节点
                break;
            }
            if (temp.next.no > node.no){  //说明已经找到插入位置,就在temp之后插入
                break;
            }else if (temp.next.no == node.no){ //说明要插入的节点已经存在
                flag = true;
                break;
            }
        }
        if (flag){
            System.out.println("要添加的英雄已经存在,添加失败"+ node.no);
        }else{
            //添加
            node.next = temp.next;
            temp.next = node;
        }
    }
    //修改元素,按照编号修改
    public void update(HeroNode newHeroNode){
        if (head.next == null){
            System.out.println("链表为空!");
            return;
        }
        //遍历寻找
        HeroNode temp = head.next;
        boolean flag = false; //标志找到没找到
        while (true){
            if (temp == null){
                break; //遍历完了
            }
            if (temp.no == newHeroNode.no){
                flag = true;
                break;  //找到了
            }
            temp = temp.next;  //没找到,一直往后遍历
        }
        if (flag){
            temp.name = newHeroNode.name;
            temp.nickname = newHeroNode.nickname;
        }else{
            System.out.println("没有找到编号为"+newHeroNode.no+"的节点,不能修改");
        }
    }

    /**
     * 删除节点
     * 思路:①因为是单链表,需要先找到待删除节点的前一个节点temp
     *      ②temp.next = temp.next.next;
     *      被删除的节点将不会被引用,被垃圾回收机制回收
     * 比较是否是待删除节点的时候是比较temp.next.no和需要删除的节点的no做比较
     */

    public void delete(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);
        }
    }

    //显示链表
    public void listNode(){

        //判断链表是否为空
        if (head.next == null){
            System.out.println("链表为空!");
            return;
        }
        //定义临时变量辅助遍历
        //前边已经判断过是否为空,所以到这里,至少有一个元素
        HeroNode temp = head.next;
        while (true){
            //判断是否到链表最后
            if (temp == null){
                break;
            }
            //输出节点信息,指针后移
            System.out.println(temp.toString());
            temp = temp.next;
        }
    }
}
//定义一个HeroNode,每个HeroNode对象就是一个节点
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  + ']';
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值