Java数据结构(4)链表——环形链表

Java数据结构(4)链表——环形链表

1.环形链表简介

如图所示:环形链表和单向链表的唯一区别就是尾节点指向头节点

关于单向链表的相关内容可查看:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HQoBABqo-1572091678783)(D:\markdowm笔记软件\images\java数据结构\环形链表.png)]

以下代码中使用的节点类代码如下:

/**
 * 代码实现环形链表——节点类
 */
class Node {
    int bookId;//书籍序列号
    String bookName;//书籍名称
    Node next;//节点

    //节点的构造方法:初始化数据域,将节点指向空
    public Node(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
        this.next = null;
    }
}

2.环形链表的打印

//打印链表(从链表头打印到链表尾) 循环结束条件不同
    public void printLinkedList() {
        Node current = first;//定义一个暂时的节点,赋值为头节点
        while (current != last) {
            System.out.println(current.bookId + current.bookName);
            current = current.next;
        }
        System.out.println(current.bookId + current.bookName);
    }

3.环形链表节点插入

   /**
     * 环形链表插入节点
     *
     * @param needInsertNode 新插入节点 已初始化数据域与节点属性
     */
    public void insertNode(Node needInsertNode) {
        Node tempNode;
        Node newNode;
        if (this.isEmpty()) {//原环形链表空
            first = needInsertNode;//头尾节点为新插入节点
            last = needInsertNode;
            last.next = first;//尾节点指向头节点
        } else if (needInsertNode.next == null) {//next为空 插在表尾
            last.next = needInsertNode;//原尾节点的下一节点赋值为新插入节点
            last = needInsertNode;//重新设置头节点
            last.next = first;//重新设置尾节点指向头节点
        } else if (needInsertNode.next == first) {//插入链表头
            first=needInsertNode;//设置新头节点
            last.next=first;//重新设置尾节点指向头节点
        } else {//插入链表中间 寻找新插入节点的next节点的前一个节点
            System.out.println("插中间");
            newNode = first;
            while (newNode.next != needInsertNode.next) {//遍历链表至:newNode为新插入节点的next节点
                newNode = newNode.next;
            }
            newNode.next=needInsertNode;
        }
    }

    //插入节点测试
    public static void main(String[] args) {
        CircleLinkedList circleLinkedList = new CircleLinkedList();
        Node node1 = new Node(12086, "《 数据结构 》");
        Node node2 = new Node(18002, "《 计算机网络 》");
        Node node3 = new Node(19121, "《 数据库概论 》");
        Node node4 = new Node(39991, "《 设计模式 》");
        Node node5 = new Node(34171, "《 Springboot 》");
        //空表插
        System.out.println("空表插");
        circleLinkedList.insertNode(node1);
        circleLinkedList.printLinkedList();
        //插尾
        System.out.println("插尾");
        circleLinkedList.insertNode(node2);
        circleLinkedList.insertNode(node3);
        circleLinkedList.printLinkedList();
        //插头
        System.out.println("插头");
        System.out.println("原头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
        node4.next = circleLinkedList.first;
        circleLinkedList.insertNode(node4);
        System.out.println("新头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
        circleLinkedList.printLinkedList();
        //插中间
        System.out.println("插中间");
        Node node=circleLinkedList.last;
        node5.next=node;
        System.out.println("插在"+node.bookName+"之前");
        circleLinkedList.insertNode(node5);


        System.out.println("插入测试后");
        circleLinkedList.printLinkedList();
        //circleLinkedList.deleteNode();
    }
}

测试结果

空表插
12086《 数据结构 》
插尾
12086《 数据结构 》
18002《 计算机网络 》
19121《 数据库概论 》
插头
原头:12086《 数据结构 》
新头:39991《 设计模式 》
39991《 设计模式 》
12086《 数据结构 》
18002《 计算机网络 》
19121《 数据库概论 》
插中间
插在《 数据库概论 》之前
插中间
插入测试后
39991《 设计模式 》
12086《 数据结构 》
18002《 计算机网络 》
34171《 Springboot 》
19121《 数据库概论 》

4. 环形链表节点删除

    /**
     * 环形链表 删除节点
     *
     * @param needDeleteNode 需删除节点 已初始化数据域与节点属性
     */
    public void deleteNode(Node needDeleteNode) {
        Node newNode;
        Node tempNode;
        if (this.isEmpty()) {
            System.out.println("环形链表已空");
            return;
        } else if (first.bookId == needDeleteNode.bookId) {//删头
            first = first.next;
            if (first == null) {
                System.out.println("删除的是头节点,环形链表已空");
                return;
            }
        } else if (last.bookId == needDeleteNode.bookId) {//删尾
            newNode = first;//用于保存尾节点前一节点
            //遍历环形链表至尾节点前一节点 并保存至newNode
            while (newNode.next != last) newNode = newNode.next;
            newNode.next = null;//将原尾节点前一节点的next置空
            last = newNode;//重新设置新的尾节点
            last.next = first;//重新设置尾节点指向头节点
        }else {//删中间
            newNode = first;//用于遍历至需要删除节点 
            tempNode = first;//用于保存newNode的前一节点,即需要删除节点的前一节点
            //遍历至需要删除节点 
            while (newNode.bookId!=needDeleteNode.bookId){
                tempNode=newNode;
                newNode=newNode.next;
            }
            //重新设置需要删除节点的前一节点的next属性 跳过needDeleteNode 指向它的后一个节点
            tempNode.next=needDeleteNode.next;
        }
    }
//插入与删除测试
    public static void main(String[] args) {
        CircleLinkedList circleLinkedList = new CircleLinkedList();
        Node node1 = new Node(12086, "《 数据结构 》");
        Node node2 = new Node(18002, "《 计算机网络 》");
        Node node3 = new Node(19121, "《 数据库概论 》");
        Node node4 = new Node(39991, "《 设计模式 》");
        Node node5 = new Node(34171, "《 Springboot 》");
        //空表插
        System.out.println("空表插");
        circleLinkedList.insertNode(node1);
        circleLinkedList.printLinkedList();
        //插尾
        System.out.println("插尾");
        circleLinkedList.insertNode(node2);
        circleLinkedList.insertNode(node3);
        circleLinkedList.printLinkedList();
        //插头
        System.out.println("插头");
        System.out.println("原头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
        node4.next = circleLinkedList.first;
        circleLinkedList.insertNode(node4);
        System.out.println("新头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
        circleLinkedList.printLinkedList();
        //插中间
        System.out.println("插中间");
        Node node = circleLinkedList.last;
        node5.next = node;
        System.out.println("插在" + node.bookName + "之前");
        circleLinkedList.insertNode(node5);


        System.out.println("插入测试后");
        circleLinkedList.printLinkedList();

        System.out.println();
        System.out.println("删头");
        circleLinkedList.deleteNode(circleLinkedList.first);
        circleLinkedList.printLinkedList();
        System.out.println("删尾");
        circleLinkedList.deleteNode(circleLinkedList.last);
        circleLinkedList.printLinkedList();
        System.out.println("删中间");
        circleLinkedList.deleteNode(circleLinkedList.first.next);
        circleLinkedList.printLinkedList();
        //circleLinkedList.deleteNode();
    }

测试代码是接着上述插入的结果来的,测试结果如下:

插入测试后
39991《 设计模式 》
12086《 数据结构 》
18002《 计算机网络 》
34171《 Springboot 》
19121《 数据库概论 》

删头
12086《 数据结构 》
18002《 计算机网络 》
34171《 Springboot 》
19121《 数据库概论 》
删尾
12086《 数据结构 》
18002《 计算机网络 》
34171《 Springboot 》
删中间
12086《 数据结构 》
34171《 Springboot 》

5.完整代码

package DataStructure.LinkedList;

/**
 * 代码实现环形链表——节点类
 */
class Node {
    int bookId;//书籍序列号
    String bookName;//书籍名称
    Node next;//节点

    //节点的构造方法:初始化数据域,将节点指向空
    public Node(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
        this.next = null;
    }
}

/**
 * 代码实现环形链表——主类
 */
public class CircleLinkedList {
    private Node first;
    private Node last;

    //判空
    public boolean isEmpty() {
        return first == null;//布尔表达式,头节点空返回true,反之返回false
    }

    //打印链表(从链表头打印到链表尾) 循环结束条件不同
    public void printLinkedList() {
        Node current = first;//定义一个暂时的节点,赋值为头节点
        while (current != last) {
            System.out.println(current.bookId + current.bookName);
            current = current.next;
        }
        System.out.println(current.bookId + current.bookName);
    }

    /**
     * 环形链表插入节点
     *
     * @param needInsertNode 新插入节点 已初始化数据域与节点属性
     */
    public void insertNode(Node needInsertNode) {
        Node tempNode;
        Node newNode;
        if (this.isEmpty()) {//原环形链表空
            first = needInsertNode;//头尾节点为新插入节点
            last = needInsertNode;
            last.next = first;//尾节点指向头节点
        } else if (needInsertNode.next == null) {//next为空 插在表尾
            last.next = needInsertNode;//原尾节点的下一节点赋值为新插入节点
            last = needInsertNode;//重新设置头节点
            last.next = first;//重新设置尾节点指向头节点
        } else if (needInsertNode.next == first) {//插入链表头
            first = needInsertNode;//设置新头节点
            last.next = first;//重新设置尾节点指向头节点
        } else {//插入链表中间 寻找新插入节点的next节点的前一个节点
            System.out.println("插中间");
            newNode = first;
            //遍历链表至:newNode为新插入节点的next节点
            while (newNode.next != needInsertNode.next) newNode = newNode.next;
            newNode.next = needInsertNode;
        }
    }

    /**
     * 环形链表 删除节点
     *
     * @param needDeleteNode 需删除节点 已初始化数据域与节点属性
     */
    public void deleteNode(Node needDeleteNode) {
        Node newNode;
        Node tempNode;
        if (this.isEmpty()) {
            System.out.println("环形链表已空");
            return;
        } else if (first.bookId == needDeleteNode.bookId) {//删头
            first = first.next;
            if (first == null) {
                System.out.println("删除的是头节点,环形链表已空");
                return;
            }
        } else if (last.bookId == needDeleteNode.bookId) {//删尾
            newNode = first;//用于保存尾节点前一节点
            //遍历环形链表至尾节点前一节点 并保存至newNode
            while (newNode.next != last) newNode = newNode.next;
            newNode.next = null;//将原尾节点前一节点的next置空
            last = newNode;//重新设置新的尾节点
            last.next = first;//重新设置尾节点指向头节点
        }else {//删中间
            newNode = first;//用于遍历至需要删除节点
            tempNode = first;//用于保存newNode的前一节点,即需要删除节点的前一节点
            //遍历至需要删除节点
            while (newNode.bookId!=needDeleteNode.bookId){
                tempNode=newNode;
                newNode=newNode.next;
            }
            //重新设置需要删除节点的前一节点的next属性 跳过needDeleteNode 指向它的后一个节点
            tempNode.next=needDeleteNode.next;
        }
    }

    //插入节点与删除节点的测试
    public static void main(String[] args) {
        CircleLinkedList circleLinkedList = new CircleLinkedList();
        Node node1 = new Node(12086, "《 数据结构 》");
        Node node2 = new Node(18002, "《 计算机网络 》");
        Node node3 = new Node(19121, "《 数据库概论 》");
        Node node4 = new Node(39991, "《 设计模式 》");
        Node node5 = new Node(34171, "《 Springboot 》");
        //空表插
        System.out.println("空表插");
        circleLinkedList.insertNode(node1);
        circleLinkedList.printLinkedList();
        //插尾
        System.out.println("插尾");
        circleLinkedList.insertNode(node2);
        circleLinkedList.insertNode(node3);
        circleLinkedList.printLinkedList();
        //插头
        System.out.println("插头");
        System.out.println("原头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
        node4.next = circleLinkedList.first;
        circleLinkedList.insertNode(node4);
        System.out.println("新头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
        circleLinkedList.printLinkedList();
        //插中间
        System.out.println("插中间");
        Node node = circleLinkedList.last;
        node5.next = node;
        System.out.println("插在" + node.bookName + "之前");
        circleLinkedList.insertNode(node5);

        System.out.println("插入测试后");
        circleLinkedList.printLinkedList();

        System.out.println();
        System.out.println("删头");
        circleLinkedList.deleteNode(circleLinkedList.first);
        circleLinkedList.printLinkedList();
        System.out.println("删尾");
        circleLinkedList.deleteNode(circleLinkedList.last);
        circleLinkedList.printLinkedList();
        System.out.println("删中间");
        circleLinkedList.deleteNode(circleLinkedList.first.next);
        circleLinkedList.printLinkedList();
    }
}

6.环形链表的更多

关于环形链表的常见问题,将在之后的文章中提及,比如 环形链表的串联,利用环形链表解决约瑟夫问题等

发布了67 篇原创文章 · 获赞 32 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42391904/article/details/102760577