05數據結構和算法(Java描述)~環形單鏈表

05數據結構和算法(Java描述)~環形單鏈表

本文是上一篇文章的後續,詳情點擊該鏈接

環形鏈表的概述:

       環形鏈表依舊採用的是鏈式存儲結構,它的特點就是設置首節點和尾節點相互指向,從而實現 讓整個鏈表形成一個環。在我們實際開發中,常見的環形鏈表有:

環形單鏈表

       在單鏈表中,尾節點的指針指向了首節點,從而整個鏈表形成一個環,如下圖所示:

在這裏插入圖片描述

環形雙鏈表

       在雙鏈表中,尾節點的指針指向了首節點,首節點的指針指向了尾節點,從而整個鏈表形成一 個環,如下圖所示:

在這裏插入圖片描述

代碼模擬實現

List接口
public interface List {
    int size();
    void add(Object element);
    Object get(int index);
    void remove(int index);
    void add(int index, Object element);
}
接口實現
package cyclesinglelinkedlist;

/**
 * 模擬環形單鏈表的實現
 */
public class CycleSingleLinkedList implements List{
    /**
     * 用於保存單鏈表中的首節點
     */
    private Node headNode;
    /**
     * 用於保存單鏈表中的尾節點
     */
    private Node lastNode;
    /**
     * 用於保存單鏈表中節點的個數
     */
    private int size;

    /**
     * 獲取單鏈表中節點的個數
     * @return
     */
    public int size() {
        return this.size;
    }

    /**
     * 添加元素
     * @param element 需要添加的數據
     */
    public void add(Object element) {
        // 1.把需要添加的數據封裝成節點對象
        Node node = new Node(element);
        // 2.處理單鏈表爲空表的情況
        if(headNode == null) {
            // 2.1把node節點設置爲單鏈表的首節點
            headNode = node;
            // 2.2把node節點設置爲單鏈表的尾節點
            lastNode = node;
        }
        // 3.處理單鏈表不是空表的情況
        else {
            // 3.1讓lastNode指向node節點
            lastNode.next = node;
            // 3.2更新lastNode的值
            lastNode = node;
        }
        // 4.設置lastNode的next值爲headNode
        lastNode.next = headNode;
        // 5.更新size的值
        size++;
    }

    /**
     * 根據序號獲取元素
     * @param index 序號
     * @return 序號所對應節點的數據值
     */
    public Object get(int index) {
        // 1.如果序號的取值小於0,則證明是不合法的情況
        if(index < 0) {
            throw new IndexOutOfBoundsException("序號不合法,index:" + index);
        }
        // 2.根據序號獲得對應的節點對象
        Node node = node(index);
        // 3.獲取並返回node節點的數據值
        return node.data;
    }

    /**
     * 根據序號刪除元素
     * @param index 序號
     */
    public void remove(int index) {
        // 1.判斷序號是否合法,合法取值範圍:[0, size - 1]
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("序號不合法,index:" + index);
        }
        // 2.處理刪除節點在開頭的情況
        if (index == 0) {
            // 2.1獲得刪除節點的後一個節點
            Node nextNode = headNode.next;
            // 2.2設置headNode的next值爲null
            headNode.next = null;
            // 2.3設置nextNode爲單鏈表的首節點
            headNode = nextNode;
            // 2.4設置lastNode的next值爲headNode
            lastNode.next = headNode;
        }
        // 3.處理刪除節點在末尾的情況
        else if (index == size - 1) {
            // 3.1獲得刪除節點的前一個節點
            Node preNode = node(index - 1);
            // 3.2設置preNode的next值爲null
            preNode.next = null;
            // 3.3設置preNode爲單鏈表的尾節點
            lastNode = preNode;
            // 3.4設置lastNode的next值爲headNode
            lastNode.next = headNode;
        }
        // 4.處理刪除節點在中間的情況
        else {
            // 4.1獲得index-1所對應的節點對象
            Node preNode = node(index - 1);
            // 4.2獲得index+1所對應的節點對象
            Node nextNode = preNode.next.next;
            // 4.3獲得刪除節點並設置next值爲null
            preNode.next.next = null;
            // 4.4設置preNode的next值爲nextNode
            preNode.next = nextNode;
        }
        // 5.更新size的值
        size--;
        // 6.判斷size的值是否爲0,如果size的值爲0,則設置headNode和lastNode爲null
        if(size == 0) {
            headNode = null;
            lastNode = null;
        }
    }

    /**
     * 根據序號插入元素
     * @param index 序號
     * @param element 需要插入的數據
     */
    public void add(int index, Object element) {
        // 1.判斷序號是否合法,合法取值範圍:[0, size]
        if(index < 0 || index > size) {
            throw new IndexOutOfBoundsException("序號不合法,index:" + index);
        }
        // 2.把需要添加的數據封裝成節點對象
        Node node = new Node(element);
        // 3.處理插入節點在開頭位置的情況
        if(index == 0) {
            // 3.1設置node的next值爲headNode
            node.next = headNode;
            // 3.2設置node節點爲單鏈表的首節點
            headNode = node;
            // 3.3設置lastNode的next值爲headNode
            lastNode.next = headNode;
        }
        // 4.處理插入節點在末尾位置的情況
        else if(index == size) {
            // 4.1設置lastNode的next值爲node
            lastNode.next = node;
            // 4.2設置node節點爲單鏈表的尾節點
            lastNode = node;
            // 4.3設置lastNode的next值爲headNode
            lastNode.next = headNode;
        }
        // 5.處理插入節點在中間位置的情況
        else {
            // 5.1獲得index-1所對應的節點對象
            Node preNode = node(index - 1);
            // 5.2獲得index所對應的節點對象
            Node curNode = preNode.next;
            // 5.3設置preNode的next爲node
            preNode.next = node;
            // 5.4設置node的next爲curNode
            node.next = curNode;
        }
        // 6.更新size的值
        size++;
    }

    /**
     * 根據序號獲得對應的節點對象
     * @param index 序號
     * @return 序號對應的節點對象
     */
    private Node node(int index) {
        // 0.判斷環形單鏈表是否爲空表
        if(headNode == null) {
            throw new NullPointerException("環形單鏈表爲空表");
        }
        // 1.定義一個零時節點,用於輔助單鏈表的遍歷操作
        Node tempNode = headNode;
        // 2.定義一個循環,用於獲取index對應的節點對象
        for(int i = 0; i < index % size; i++) {
            // 3.更新tempNode的值
            tempNode = tempNode.next;
        }
        // 4.返回index對應的節點對象
        return tempNode;
    }

    /**
     * 節點類
     */
    private static class Node {
        /**
         * 用於保存節點中的數據
         */
        private Object data;
        /**
         * 用於保存指向下一個節點的地址值
         */
        private Node next;
        /**
         * 構造方法
         * @param data
         */
        public Node(Object data) {
            this.data = data;
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章