1. 程式人生 > >java資料結構——雙向連結串列

java資料結構——雙向連結串列

連結串列是非常常見的一類線性結構的資料結構,每個節點包含有指標域和資料域,常見的包括單項列表、雙向列表、迴圈列表。這篇文章將詳細介紹雙向連結串列。

雙端連結串列不同於單向連結串列僅有一個指標域指向下一個節點,而是同時持有下一個和上一個指標域,分別指向下一個和上一個節點,如下:

本文將介紹雙向連結串列的插入節點、根據位置插入節點、刪除頭結點、刪除尾節點、刪除指定位置節點,檢視連結串列元素、檢視頭結點、檢視尾節點、檢視連結串列長度、判斷連結串列是否為空。

連結串列的節點表示:

class Node {

    //資料域
    public String data;
    //上一個節點
    public Node prev;
    //下一個節點
    public Node next;

    public Node(String data) {
        this.data = data;
    }
}

在建立好連結串列節點之後下來看連結串列的構造方法和成員變數,成員方法包括一個完整連結串列的頭結點、尾節點以及連結串列的長度:

class DoubleLinkedList {

    private Node tailNode;
    private Node headNode;
    private int length;

    public DoubleLinkedList() {
        tailNode = null;
        headNode = null;
    }
}

1、插入元素:尾部插入

    /**
     * 插入元素
     */
    public void insert(String value) {
        if (value == null || value.isEmpty()) {
            throw new NullPointerException();
        }
        Node node = new Node(value);
        if (headNode == null) {
            headNode = node;
            tailNode = headNode;
            tailNode.prev = null;
            tailNode.next = null;
        } else {
            tailNode.next = node;
            node.prev = tailNode;
            tailNode = node;
        }
        length++;
    }

2、插入元素:指定位置

    /**
     * 根據位置插入節點
     */
    public void insert(int position, String value) {
        //建立要插入的節點
        Node node = new Node(value);
        if (position >= length) {
            //直接插入到尾部
            insert(value);
            return;
        }
        if (position == 0) {
            Node firstNode = headNode;
            headNode = node;
            headNode.prev = null;
            headNode.next = firstNode;
            firstNode.prev = node;
        } else {
            //獲取到該位置的節點
            Node nodeByPosition = getNodeByPosition(position);
            //上一個節點
            Node prevNode = nodeByPosition.prev;
            //下一個節點
            Node nextNode = nodeByPosition.next;
            //上一個節點next指向他
            prevNode.next = node;
            //他的上一個節點指向prev
            node.prev = prevNode;
            //他的下一個節點指向next
            node.next = nodeByPosition;
            //下一個節點的pre指向他
            nodeByPosition.prev = node;
        }
        length++;
    }

3、刪除元素:刪除頭部

    /**
     * 刪除連結串列頭部
     */
    public Node deleteHead() {
        //獲取根節點的下一個節點
        Node nextNode = null;
        Node firstNode = null;
        if (headNode != null) {
            nextNode = headNode.next;
        } else {
            return null;
        }
        if (nextNode == null) {
            headNode = null;
        } else {
            firstNode = headNode;
            nextNode.prev = null;
            headNode.next = null;
            headNode = nextNode;
        }
        length--;
        return firstNode;
    }

4、刪除元素:刪除尾部

    /**
     * 刪除連結串列尾部
     */
    public Node deleteTail() {
        //獲取根節點的下一個節點
        Node preNode = null;
        Node lastNode = null;
        if (tailNode != null) {
            preNode = tailNode.prev;
        } else {
            return null;
        }
        if (preNode == null) {
            headNode = tailNode;
        } else {
            lastNode = tailNode;
            tailNode.prev = null;
            preNode.next = null;
            tailNode = preNode;
        }
        length--;
        return lastNode;
    }

5、刪除元素:刪除指定位置

    /**
     * 刪除指定位置節點
     */
    public Node deleteByPosition(int position) {
        if (position >= length) {
            throw new IllegalArgumentException(" position must be less than linklist all length ");
        } else {
            Node nodeByPosition = getNodeByPosition(position);
            if (position == 0) {
                //刪除頭結點
                Node deleteHead = deleteHead();
                return deleteHead;
            } else if (position == length - 1) {
                //刪除尾節點
                Node deleteTail = deleteTail();
                return deleteTail;
            } else {
                //有頭有尾
                //獲取該節點的前一個和後一個節點
                Node prevNode = nodeByPosition.prev;
                Node nextNode = nodeByPosition.next;
                prevNode.next = nextNode;
                nextNode.prev = prevNode;
                length--;
                return nodeByPosition;
            }
        }
    }

6、根據位置獲取節點

    /**
     * 根據位置獲取節點
     */
    public Node getNodeByPosition(int position) {
        Node current = headNode;
        if (position >= length) {
            throw new IllegalArgumentException(" position must be less than linklist all length ");
        } else {
            for (int i = 0; i < length; i++) {
                if (i == position) {
                    break;
                }
                if (current != null) {
                    current = current.next;
                }
            }
        }
        return current;
    }

7、檢視所有節點

    /**
     * 列印所有節點
     */
    public void displayAll() {
        Node current = headNode;
        while (current != null) {
            System.out.print(current.data + " ");
            current = current.next;
        }
    }

8、檢視頭結點

    /**
     * 檢視頭結點
     */
    public Node getheadNode() {
        return headNode;
    }

9、檢視尾節點

    /**
     * 檢視當尾節點
     */
    public Node getTailNode() {
        return tailNode;
    }

10、獲取連結串列長度

    /**
     * 連結串列長度
     */
    public int length() {
        return length;
    }

11、判斷連結串列是否為空

    /**
     * 判斷連結串列是否為空
     */
    public boolean isEmpty() {
        return length == 0;
    }