2、java数据结构和算法:单链表: 反转,逆序打印, 合并二个有序链表,获取倒数第n个节点, 链表的有序插入

什么也不说, 直接上代码:
功能点有:
1, 获取尾结点
2, 添加(添加节点到链表的最后面)
3, 添加(根据节点的no(排名)的大小, 有序添加)
4, 单向链表的 遍历
5, 链表的长度
6, 删除某一个节点
7, 更换指定位置的节点
8, 查询第n个节点
9, 查询倒数第n个节点
10, 链表反转, 使用递归实现
11, 逆序打印
12, 合并二个有序链表, 且结果仍然是有序的

//英雄节点
class HeroNodeLv{
    public int no;//英雄排名
    public String name;//名字
    public String nickName;//花名
    public HeroNodeLv next;//指向下一节点

    public HeroNodeLv(int no, String name, String nickName) {
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }

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

//链表对象

    class SingleLinkListLvcai {
          //单链表是由节点组成,  节点由 数据+ next(指向下一节点)组成
          // 定义一个头结点,为空
          public HeroNodeLv head = new HeroNodeLv(0,"","");
          public void setHead(HeroNodeLv head) {
              this.head = head;
          }

    // 获取头结点
    public HeroNodeLv getHeadNode(){return head;}

    //1, 获取尾结点
    public HeroNodeLv getLastNode(){
        //head头结点不能动, 定义第三方对象来遍历
        HeroNodeLv temp = head;
        while(true){
            if(temp.next == null){
                //说明是尾结点
                return temp;
            }
            temp = temp.next;
        }
    }

    //2, 添加(添加节点到链表的最后面)
    public void add(HeroNodeLv node){
        //head头结点不能动, 定义第三方对象来遍历
        HeroNodeLv temp = head;
        while(true){
            if(temp.next == null){
                //说明是尾结点
                break;
            }
            temp = temp.next;
        }
        //遍历完后,此时temp就是尾结点
        temp.next = node;
    }

    //3, 添加(根据节点的no(排名)的大小, 有序添加)
    public void addByHeroNo(HeroNodeLv node){
        HeroNodeLv temp = head;
        boolean flag = false; //该节点是否已存在标识, 默认false,不存在
        while(true){
            if (temp.next == null) {
                //说明到尾节点
                break;
            }
            if(temp.next.no > node.no){
                //说明 node 是需要放在 temp的下一个节点
                break;
            }else if(temp.next.no == node.no){
                flag = true;//该节点已存在
                break;
            }
            temp = temp.next;
        }

        if(false){
            System.out.println("该节点已存在");
        }else{
            //插在temp的后面, 这里先将node的next指定好,之后,再指定插入, 这二行代码顺序不能变,否则会出现死循环
            node.next = temp.next;
            temp.next = node;
        }
    }

    //4, 单向链表的 遍历
    public void show(){
        if(head.next== null){
            //空链表
            System.out.println("空链表");
            return;
        }
        HeroNodeLv temp = head;
        while(true){
            if(temp.next == null){
                break;
            }
            System.out.println(temp);
            temp = temp.next;
        }
        System.out.println(temp);
    }

    //5, 链表的长度
    public int length(){
        if(head.next == null){
            return 0;//这里头节点 不计入长度
        }
        HeroNodeLv temp = head.next;//这里头节点 不计入长度
        int count = 0;
        while(temp!= null){
            count++;
            temp = temp.next;
        }
        return count;
    }
    //6, 删除某一个节点
    public void delNode(int no){
       HeroNodeLv temp = head;
       boolean flag = false;//该链表是否存在这个节点,默认为false, 不存在
       while(true){
           if(temp.next == null){
               break;//链表尾部
           }
           if(temp.next.no == no){
               flag = true;
               break;//删除此时的这个节点的下一节点
           }
           temp = temp.next;
       }
        //循环完后,,此时temp的 next就是要删除的节点
        if(flag){
            temp.next = temp.next.next;
        }else {
            System.out.println("链表中不存在这个节点");
        }
    }
    //7, 更换指定位置的节点
    public void updateNode(int no,HeroNodeLv node){
        HeroNodeLv temp = head;
        boolean flag = false;//该链表是否存在这个节点, 默认为false 不存在
        while (true) {
            if (temp.next == null) {
                break;//链表尾部
            }
            if (temp.next.no == no) {
                flag = true; //temp的next就是要替换的节点
                break;
            }
            temp = temp.next;
        }

        if (flag) {
            //更换
            temp.next = node;//更换next.
            node.next = temp.next.next;//指定node的next
        }else{
            System.out.println("不存在这个节点");
        }
    }

    //8, 查询第n个节点
    public HeroNodeLv getByNo(int no){
        //获取链表长度
        if(no == 0){
            return getHeadNode();//头结点
        }
        if(no >length()){
            System.out.println("超出链表的长度:"+length());
            return null;
        }
        HeroNodeLv temp = head.next;
        int count = 0;
        while(temp != null){
            count++;
            if(count == no){
                //这就是要找的节点
                break;
            }
            temp = temp.next;
        }
        return temp;
    }

    //9, 查询倒数第n个节点
    public HeroNodeLv getByBackwordNum(int no){
        //思路: 查询倒数第n个节点, 就是查询正数第 length-n+1 个节点
        //如果为0 或者超出链表长度, 返回null
        if(no == 0 || no > length()){
            System.out.println("不能为0,或者,超出链表长度:链表长度为"+length());
            return null;
        }
        return getByNo(length() - no +1);
    }
}

    //10, 链表反转, 使用递归实现
    public static void reverseList(HeroNodeLv node){
        //思路: 遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead 的最前端
        if(node.next == null || node.next.next == null){
            return ;//空链表,只有一个节点的链表
        }
        HeroNodeLv cur = node.next;//定义指针变量,便于遍历原来的链表
        HeroNodeLv next = null;//next 指的是当前节点(cur)的下一个节点
        HeroNodeLv reverseHead = new HeroNodeLv(0,"","");
        while(cur!= null){
            next = cur.next;//先保存当前节点的写一个节点
            cur.next = reverseHead.next;//将cur的下一个节点 指向新链表的最前端
            reverseHead.next = cur;//将cur连接到新的链表上
            cur = next;//后移
        }
        //循环完之后,newNode就是一个反转的链表了,,此时将newNode链表的头节点 , 变为原来链表的头节点
        node.next = reverseHead.next;
    }

    //11, 逆序打印
    public static void reversePrint(HeroNodeLv node){
        //思路: 将单链表遍历,一个个取出,放到栈中,然后栈遍历, 利用栈的特点:先进后出
       if(node.next == null){
           return;
       }
       HeroNodeLv cur = node.next;
       Stack<HeroNodeLv> stack = new Stack<HeroNodeLv>();
       while(cur != null){
           stack.push(cur);
           cur = cur.next;
       }
       //遍历stack
        while(stack.size() > 0){
            System.out.println(stack.pop());
        }
    }


    //12, 合并二个有序链表, 且结果仍然是有序的, 此方法的入参节点,从第一个节点开始, 不带头节点
    public static HeroNodeLv mergeLinkList(HeroNodeLv node1 ,HeroNodeLv node2){
        if(node1 == null && node2 == null){
            return null;
        }
        if(node1 == null){
            return node2;
        }

        if (node2 == null) {
            return node1;
        }
        HeroNodeLv head = null ;
        if(node1.no > node2.no){
            head = node2;
            head.next = mergeLinkList(node1,node2.next);
        }else if(node1.no < node2.no){
            head = node1;
            head.next = mergeLinkList(node1.next,node2);
        }else{
            //相等的情况
            head = node1;
            head.next = mergeLinkList(node1.next,node2.next);
        }
        return head;
    }

测试结果:
合并链表:

         public static void main(String[] args) {
              HeroNodeLv node1 = new HeroNodeLv(1, "宋江", "及时雨");
              HeroNodeLv node2 = new HeroNodeLv(2, "吴用", "神算子");
              HeroNodeLv node3 = new HeroNodeLv(3, "卢俊义", "玉麒麟");
              HeroNodeLv node4 = new HeroNodeLv(4, "武松", "打老虎");
              HeroNodeLv node5 = new HeroNodeLv(5, "吕财", "打老虎");
              HeroNodeLv node6 = new HeroNodeLv(6, "吴二娘", "打老虎");
              HeroNodeLv node7 = new HeroNodeLv(7, "吴二娘", "打老虎");
              HeroNodeLv node8 = new HeroNodeLv(8, "吴二娘", "打老虎");
              HeroNodeLv node9 = new HeroNodeLv(9, "吴二娘", "打老虎");
              HeroNodeLv node10 = new HeroNodeLv(10, "吴二娘", "打老虎");
        
        SingleLinkListLvcai linkListLv = new SingleLinkListLvcai();
        linkListLv.add(node1);
        linkListLv.add(node7);
        linkListLv.add(node8);
        linkListLv.addByHeroNo(node3);//这里的添加,是有序添加
        linkListLv.addByHeroNo(node9);
        System.out.println("链表linkListLv:");
        linkListLv.show();// 1-3-7-8-9
        System.out.println("==============================================");
        
        
        SingleLinkListLvcai linkListLv2 = new SingleLinkListLvcai();
        linkListLv2.addByHeroNo(node7);
        linkListLv2.addByHeroNo(node4);
        linkListLv2.addByHeroNo(node2);
        linkListLv2.addByHeroNo(node8);
        linkListLv2.addByHeroNo(node6);
        linkListLv2.addByHeroNo(node5);
        System.out.println("链表linkListLv2:");
        linkListLv2.show();//2-4-5-6-7-8
        System.out.println("==============================================");

        HeroNodeLv heroNodeLv = mergeLinkList(linkListLv.getHeadNode().next, linkListLv2.getHeadNode().next);
        //合并后的链表没有头结点,所以需要加上头结点
        HeroNodeLv newLinkList = new HeroNodeLv(0, "", "");
        newLinkList.next= heroNodeLv;
        linkListLv.setHead(newLinkList);
        System.out.println("合并后的新链表为:newLinkList");
        linkListLv.show();//1-2-3-4-5-6-7-8
   }

合并二个有序链表结果:

链表反转结果:

链表反转打印的结果,不破坏原有链表结构:

获取链表倒数第n个节点:

其余的几个功能点可以自己测试......

posted @ 2020-05-30 17:47  死不了好气呦  阅读(158)  评论(0编辑  收藏  举报