4.3 Java实现循环链表(完整代码及详细注释)

文章目录

  • 1. 循环链表
    • 1.1 什么是循环链表?
  • 2.循环链表的实现
    • 2.1 节点定义
    • 2.2 操作方法定义
      • 2.2.1 计算链表长度
      • 2.2.2 打印链表内容
      • 2.2.3 获取链表最后一个节点
      • 2.2.4 插入节点
      • 2.2.5 删除指定位置的节点
  • 3.循环链表测试
    • 3.1 编写循环链表自动生成方法
    • 3.2 然后进行测试用例编写
  • 4.项目地址

1. 循环链表

1.1 什么是循环链表?

顾名思义,就是可以循环的链表哈哈哈,说白了就是收尾相连的链表,
也就是说在这个链表里,任何节点都可能是头节点,也可以是尾节点。

为了简单理解,这里只演示单向循环链表。

4.3 Java实现循环链表(完整代码及详细注释)_第1张图片

从图中可以看出,他和单向链表基本没差别,无非就是将尾节点的next设置为头节点即可(注意这个点就理解了),
也就是说单向循环链表的定义和单向链表的定义基本一致,只是多了一个标志,用于结束循环。

2.循环链表的实现

2.1 节点定义

/**
 * 单向循环链表
 */
public class Node {

    //存储数据的变量
    public int data;

    //它存储了下一个节点对象引用
    public Node next;

    //节点名称
    public String nodeName;

    //是否头节点标识
    public boolean isHead = false;

    public Node(int data, String nodeName){
        this.data=data;
        if(nodeName==null){
            nodeName=""+data;
        }
        this.nodeName = nodeName;
    }
}

2.2 操作方法定义

2.2.1 计算链表长度

    /**
     * 以输入节点为头,计算出链表长度
     * @param head 任意节点
     * @return 链表长度
     */
    static int ListLength(Node head) {
        int length = 0;
        Node cur = head;
        if(cur==null) return length;
        //先把第一个节点设置为头节点
        cur.isHead = true;
        length++;
        cur = cur.next;
        while (!cur.isHead) {
            length++;
            cur = cur.next;
        }
        // 还原
        head.isHead = false;
        return length;
    }

2.2.2 打印链表内容

    /**
     * 遍历打印链表内容
     * @param headNode 链表头节点
     */
    static void toString(Node headNode) {
        Node check = headNode;
        int size = ListLength(headNode);
        if(check==null){
            System.out.print("null");
            return;
        }
        for(int i=0; i < size+1; i++){
            System.out.print(check.nodeName+"->");
            check = check.next;
        }
    }

2.2.3 获取链表最后一个节点

    /**
     * 此方法用于获得链表的最后一个节点
     * @param head 头节点
     * @return 循环链表的最后一个节点
     */
    static Node getLastNode(Node head) {
        Node cur = head;
        Node pre = head;
        if(cur==null) return null;
        cur.isHead = true;
        cur = cur.next;
        while (cur!=null&&!cur.isHead){
            pre = cur;
            cur = cur.next;
        }
        head.isHead = false;
        return pre;
    }

2.2.4 插入节点

    /**
     * 主要思路是:
     *      先判断链表中存不存在position位置,若没有输出错误信息并返回头节点;
     *      若存在则进行插入操作:首先判断position是不是为1,因为这种情况不同于其他的。
     *      否则,先找到第position-1个节点和position个节点,将前一个节点的下一节点设为nodeToInsert
     *      将nodeToInsert的下一个节点设置为position节点,这样完成插入操作
     * @param headNode 链表头节点
     * @param nodeToInsert 要插入的节点
     * @param position 指定插入的位置
     * @return 插入后的链表头节点
     */
    static Node Insert(Node headNode, Node nodeToInsert, int position ) {
        if(headNode == null) {
            return nodeToInsert;
        }
        //获得输入链表的长度
        int size = ListLength(headNode);
        //判断链表内是否存在此位置
        if(position>size || position<0) {
            System.out.println("Position of node to insert is invalid.The valid inputs are 0 to"+(size));
            return headNode;
        }
        //获取尾节点
        Node lastNode = getLastNode(headNode);
        //在链表开头插入
        if(position == 0) {
            nodeToInsert.next = headNode;
            //让尾节点指向该节点
            if(lastNode!=null)
                lastNode.next = nodeToInsert;
            return nodeToInsert;
        }
        //在末尾插入
        else if(position == size) {
            //插入操作
            nodeToInsert.next = headNode;
            if(lastNode!=null)
                lastNode.next = nodeToInsert;
        }
        //在中间插入
        else {
            Node pre = headNode;
            int count = 0;
            //找到那个位置的前一个节点
            while(count < position-1) {
                //获得第position-1位置的节点
                pre = pre.next;
                count++;
            }
            //获得第position位置的节点
            Node currentNode = pre.next;
            //插入操作
            nodeToInsert.next = currentNode;
            pre.next = nodeToInsert;
        }
        return headNode;
    }

2.2.5 删除指定位置的节点

    /**
     * 方法和前面的插入方法有异曲同工之妙:
     *  主要思想是找到position的前一个节点和后一个节点,然后将他们连接
     * @param headNode 头节点
     * @param position 删除的位置
     * @return 删除后的链表头节点
     */
    static Node Delete(Node headNode, int position) {
        if(headNode == null) return null;
        int size = ListLength(headNode);
        if(position > size-1||position < 0) {
            System.out.println("Position of node to delete is invalid. The valid inputs are 0 to "+(size-1));
            return headNode;
        }
        Node lastNode = getLastNode(headNode);
        //删除表头
        if(position == 0) {
            if(lastNode!=null) {
                lastNode.next = headNode.next;
                return headNode.next;
            }else return null;
        }
        //删除中间或结尾节点
        else {
            Node previousNode = headNode;
            int count = 0 ;
            //获得目标节点的上一个节点
            while(count < position-1) {
                previousNode = previousNode.next;
                count++;
            }
            //要删除目标节点
            Node currentNode = previousNode.next;
            previousNode.next = currentNode.next;
        }
        return headNode;
    }

3.循环链表测试

3.1 编写循环链表自动生成方法

    /**
     * 生成一个min 到 max之间的随机数
     * @param min 最小数
     * @param max 最大数
     * @return 随机数
     */
    public static int numberGenerator(int min,int max) {
        int number= (int) (Math.random()*max);
        while (number<min){
            number= (int) (Math.random()*max);
        }
        return number;
    }
    /**
     * 自动随机创建循环链表,用于测试
     * @param length 链表长度
     * @param min 链表最小值
     * @param max 链表最大值
     * @return 生成的循环链表
     */
    public static Node generatorCycleList(int length, int min, int max) {
        Node headNode = null;
        Node nextNode = null;
        for(int i=0;i<length;i++){
            int num = numberGenerator(min,max);
            if(headNode==null){
                headNode = new Node(num,null);
                nextNode = headNode;
            }
            else {
                Node node = new Node(num,null);
                nextNode.next = (node);
                nextNode = node;
                if(i==length-1){
                    node.next = headNode;
                }
            }
        }
        return headNode;
    }

3.2 然后进行测试用例编写


    public void LengthTest() {
        Node cycleListNode= generatorCycleList(10,1,18);
        System.out.print("循环链表长度:");
        System.out.println(CycleList.ListLength(cycleListNode));
        CycleList.toString(cycleListNode);
    }


    public void InsertTest() {
        Node cycleListNode= generatorCycleList(10,1,18);
        System.out.print("循环链表长度:");
        System.out.println(CycleList.ListLength(cycleListNode));
        CycleList.toString(cycleListNode);
        System.out.println();
        System.out.println("插入操作:");
        Node test1 = new Node(23,null);
        cycleListNode= CycleList.Insert(cycleListNode,test1,9);
        CycleList.toString(cycleListNode);
        System.out.println();
    }


    public void DeleteTest() {
        Node cycleListNode= generatorCycleList(10,1,18);
        System.out.print("循环链表长度如下:");
        System.out.println(CycleList.ListLength(cycleListNode));
        CycleList.toString(cycleListNode);
        System.out.println();
        System.out.println("删除操作:");
        cycleListNode= CycleList.Delete(cycleListNode,10);
        CycleList.toString(cycleListNode);
    }

最后,就可以进行各种场景的测试与进一步学习了!!

4.项目地址

https://gitee.com/yan-jiadou/algorithm-study/tree/master/algorithmStudy/src/main/java/course/p4_list/s4_CycleList

你可能感兴趣的:(算法基础学习,链表,数据结构,list)