Java實現單鏈表的操作

本文實例為大傢分享瞭Java實現單鏈表的基本操作,供大傢參考,具體內容如下

順序表:物理上邏輯上都連續;
鏈表:物理上不一定連續,邏輯上一定連續的。

鏈表的概念及結構

概念:連表示一種物理存儲結構上非連續、非順序的存儲結構,數據元素的邏輯順序是用過鏈表中的引用鏈接次序實現的。

8種鏈表結構:

單項、雙向
帶頭、不帶頭
循環、非循環

主要的三種鏈表:

無頭單項非循環鏈表、帶頭循環單鏈表、不帶頭雙向循環鏈表

代碼實現

1. 接口定義

package com.github.linked.Impl;

public interface ILinked {
    // 頭插法
    void addFirst(int data);

    // 尾插法
    void addLast(int data);

    // 任意位置插入,第一數據節點為0號下標
    boolean addIndex(int index, int data);

    // 查找是否包含關鍵字 key 在單鏈表中
    boolean contains(int key);

    // 刪除第一次出現的關鍵字為 key 的節點
    int remove(int key);

    // 刪除所有值為 key 的節點
    void removeAllKey(int key);

    // 得到單鏈表的長度
    int getLength();

    // 打印單鏈表
    void display();

    // 清空單鏈表以防內存泄漏
    void clear();
}

2. 代碼實現接口

package com.github.linked.Impl;

public class SingleListed implements ILinked {

    // 節點類
    class Node {
        private int data;
        private Node next;

        public Node(int data) {
            this.data = data;
            this.next = next;
        }
    }

    private Node head; //頭節點
    public SingleListed() {
        this.head = head;
    }

    /**
     * 頭插法
     * @param data 要插入的數據
     */
    @Override
    public void addFirst(int data) {
        // 1. 拿到一個實體
        Node node = new Node(data);

        // 2. 插入
        // 如果是第一次插入,直接到頭節點
        if (this.head == null) {
            this.head = node;
        } else { //不是第一次插入
            node.next = this.head; // 插入的節點指向頭節點
            this.head = node;      // 更新頭節點
        }
    }

    /**
     * 尾插法
     * @param data 要插入的數據
     */
    @Override
    public void addLast(int data) {
        // 1. 拿到一個實體
        Node node = new Node(data);
        Node cur = this.head;

        // 2. 插入
        // 如果是第一次插入,直接到頭節點
        if (this.head == null) {
            this.head = node;
        } else {
            // 找尾巴
            while (cur.next != null) {
                cur = cur.next;
            }
            // 退出上面的循環,cur所執行的位置就是尾節點
            cur.next = node;
        }
    }

    // 檢測 index 該下標是否合法
    private void checkIndex(int index) {
        if (index < 0 || index > getLength())
            throw new IndexOutOfBoundsException("下標不合法!");
    }

    // 找到下標為 index-1 位置的節點
    private Node searchIndex(int index) {
        checkIndex(index);
        if (index == 0)
            return null;
        int count = 0; // 記錄行走的步數
        Node cur = this.head;

        while (cur.next != null && count < index-1) {
            cur = cur.next;
            count++;
        }

        return cur;
    }

    /**
     * 任意位置插入,第一數據節點為 0號下標
     * @param index 插入的下標
     * @param data 要插入的數據
     * @return true
     */
    @Override
    public boolean addIndex(int index, int data) {
        Node node = new Node(data);
        Node cur = searchIndex(index);

        // 如果鏈表為空,直接插入到頭節點
        if (cur == null) {
            node.next = this.head;
            this.head = node;
        } else { // 鏈表不為空,插入到 cur 的位置處
            node.next = cur.next;  // 將node鏈接到cur的下一個節點
            cur.next = node;       // 再將cur鏈接到node
        }

        return true;
    }

    /**
     * 查找是否包含關鍵字 key 在單鏈表中
     * @param key 要查找的關鍵字
     * @return 找到key返回true,否則返回false
     */
    @Override
    public boolean contains(int key) {
        Node cur = this.head;
        while (cur != null) {
            if (cur.data == key) {
                return true;
            }
            cur = cur.next;
        }

        return false;
    }

    // 找第一次出現的關鍵字為 key 的節點的前驅
    private Node searchPre(int key) {
        // 1. 是不是第一個節點 if(head,data == key)
        Node pre = this.head;
        if (pre.data == key) {
            // 或者 return null;
            return this.head;
        }

        // 2. if(cur.next.data == key)
        while (pre.next != null) {
            if (pre.next.data == key) {
                return pre;
            }
            pre = pre.next;
        }

        return null;
    }

    /**
     * 刪除第一次出現的關鍵字為 key 的節點
     * @param key 要刪除的關鍵字
     * @return oldData
     */
    @Override
    public int remove(int key) {
        int oldData = 0;
        Node pre = searchPre(key);

        // 1. 若沒有找到
        if (pre == null) {
            // return -1;
            throw new UnsupportedOperationException("沒有key的前驅");
        }

        // 2. 找到瞭,並且在第一個節點
        if (pre == this.head && pre.data == key){
            oldData = this.head.data;
            this.head = this.head.next;
            return oldData;
        }

        // 3. 找到瞭,並且不在第一個節點
        Node delNode = pre.next; // 確定要刪除的節點的位置
        pre.next = delNode.next; // 讓要刪除的節點的前驅指向要刪除的節點的後一個節點,進而刪除該節點

        return 0;
    }

    /**
     * 刪除所有值為 key 的節點
     * @param key 要刪除的節點的值
     */
    @Override
    public void removeAllKey(int key) {
        Node pre = this.head;
        Node cur = this.head.next;

        // 遍歷一遍鏈表
        while (cur != null) {
            // 若找到瞭關鍵字,進行刪除
            if (cur.data == key) {
                pre.next = cur.next;
                cur = cur.next;
            } else { // 若不是關鍵字,繼續查看鏈表的下一個
                pre = cur;
                cur = cur.next;
            }
            if (this.head.data == key) {
                this.head = this.head.next;
            }
        }
    }

    /**
     * 得到單鏈表的長度
     * @return 單鏈表長度
     */
    @Override
    public int getLength() {
        Node cur = this.head;
        int count = 0;  // 節點的個數
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

    /**
     * 打印單鏈表
     */
    @Override
    public void display() {
        Node cur = this.head;
        while (cur != null) {
            System.out.print(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    /**
     * 清空單鏈表以防內存泄漏
     */
    @Override
    public void clear() {
        while (this.head != null) {
            Node cur = this.head.next;
            this.head.next = null;
            this.head = cur;
        }
    }
}

3. 測試代碼

package com.github.linked.Impl;

public class TestDemo {
    public static void main(String[] args) {

        //MySingleListImpl mySingleList = new MySingleListImpl();
        SingleListed mySingleList = new SingleListed();

        mySingleList.addFirst(10);
        mySingleList.addFirst(20);
        mySingleList.addFirst(30);
        mySingleList.addFirst(40);
        mySingleList.addFirst(50);
        System.out.println("頭插:");
        mySingleList.display();

        mySingleList.addLast(100);
        mySingleList.addLast(200);
        System.out.println("尾插:");
        mySingleList.display();
        System.out.println();

        System.out.print("單鏈表的長度:");
        System.out.println(mySingleList.getLength());
        System.out.println();

        mySingleList.addIndex(1,15);
        System.out.println("任意位置插入:");
        mySingleList.display();
        System.out.println();

        System.out.println("查找是否包含關鍵字 key 在單鏈表中:");
        System.out.println("查找關鍵字125:"+mySingleList.contains(125));
        System.out.println("查找關鍵字30:"+mySingleList.contains(30));
        System.out.println();

        System.out.println("刪除第一次出現的關鍵字為 key 的節點:");
        System.out.println("刪除頭節點50:");
        mySingleList.remove(50); //刪除頭節點
        mySingleList.display();
        System.out.println("刪除中間節點30:");
        mySingleList.remove(30); // 刪除中間節點
        mySingleList.display();
        System.out.println("刪除尾節點200:");
        mySingleList.remove(200); // 刪除尾節點
        mySingleList.display();
        System.out.println();

        System.out.println("刪除第一次出現的關鍵字為 key 的節點:");
        mySingleList.addFirst(20);
        mySingleList.display();
        mySingleList.removeAllKey(20);
        mySingleList.display();
        System.out.println();

        System.out.print("單鏈表的長度:");
        System.out.println(mySingleList.getLength());
        System.out.println();

        // 測試內存泄漏
        try {
            Thread.sleep(1000);
            System.out.println("睡醒瞭");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4. 測試結果

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: