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

1. 循环链表

1.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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是Java链表实现代码,包含详细的中文注释: ```java // 定义一个链表节点类 public class ListNode { int val; // 当前节点的值 ListNode next; // 指向下一个节点的指针 // 构造函数 public ListNode(int val) { this.val = val; this.next = null; } } // 定义一个链表类 public class LinkedList { ListNode head; // 链表头节点 // 构造函数 public LinkedList() { this.head = null; } // 在链表末尾添加一个节点 public void addAtTail(int val) { ListNode newNode = new ListNode(val); if (head == null) { head = newNode; // 如果链表为空,则新节点为头节点 } else { ListNode cur = head; while (cur.next != null) { cur = cur.next; // 找到链表的最后一个节点 } cur.next = newNode; // 在最后一个节点的后面添加新节点 } } // 在链表头部添加一个节点 public void addAtHead(int val) { ListNode newNode = new ListNode(val); newNode.next = head; // 将新节点的 next 指针指向原头节点 head = newNode; // 将新节点设为头节点 } // 在指定位置添加一个节点 public void addAtIndex(int index, int val) { if (index <= 0) { addAtHead(val); // 如果插入位置为 0 或负数,则在头部插入 return; } ListNode newNode = new ListNode(val); ListNode cur = head; int i = 0; while (cur != null && i < index - 1) { cur = cur.next; i++; } if (cur == null) { return; // 如果插入位置超出链表长度,则不插入 } newNode.next = cur.next; cur.next = newNode; } // 删除指定位置的节点 public void deleteAtIndex(int index) { if (index < 0) { return; // 如果删除位置为负数,则不删除 } if (index == 0) { head = head.next; // 如果要删除的是头节点,则将头节点指向下一个节点 return; } ListNode cur = head; int i = 0; while (cur != null && i < index - 1) { cur = cur.next; i++; } if (cur == null || cur.next == null) { return; // 如果删除位置超出链表长度,则不删除 } cur.next = cur.next.next; } // 获取指定位置的节点值 public int get(int index) { if (index < 0) { return -1; // 如果获取位置为负数,则返回 -1 } ListNode cur = head; int i = 0; while (cur != null && i < index) { cur = cur.next; i++; } if (cur == null) { return -1; // 如果获取位置超出链表长度,则返回 -1 } return cur.val; } } ``` 以上代码实现链表的基本操作,包括在末尾、头部、指定位置添加节点,删除指定位置的节点以及获取指定位置的节点值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员小牧之

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

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

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

打赏作者

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

抵扣说明:

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

余额充值