算法是什么(二)手寫個鏈表(java)


算法是什么(二)手寫個鏈表(java)

 

liuyuhang原創,未經允許禁止轉載

 

目錄

算法是什么(〇)

 

很多語言的API中都提供了鏈表實現,或者擴展庫中實現了鏈表。

但是更多的情況下,Map(或hash)和List(非定容數組)的使用率更高。

這並非意味着鏈表不應該掌握或不使用了。

 

鏈表本質上是一種及其高等的數據結構展現,擴展性極強。

鏈表可輕松擴展成樹結構,二叉樹,環,棧,隊列,雙向隊列等。

 

很多種數據結構都是依據鏈表的形式擴展出來的,雖然我知道的並不多,但是我知道鏈表的重要性。

所以,手寫一個鏈表試試。

 

1、本質

 

鏈表的本質是Node(節點),其中保存着信息(info),前一個節點(prevNode),后一個節點(nextNode)。

和基礎操作API構成

 

2、特性

 

鏈表為了操作的方便性,多數會將鏈表做成雙向鏈表,即既包含next,又包含prev

 

3、基礎API

 

鏈表的操作,至少需要增刪改查,不然還算啥容器了:

  增:默認從末尾添加,添加指定index,在首添加三種方式添加單一元素。

  刪:刪除頭,刪除尾,刪除指定index的元素,刪除當前指針元素。

  改:設置頭,設置尾,設置指定index的元素,設置當前指針元素。

  查:獲取當前指針元素,獲取首元素,獲取尾元素,獲取下一個元素,獲取上一個元素,獲取指定index的元素

 

  有些API還提供了更多的操作:

  獲取當前容器的size

  獲取當前指針的index

  迭代器

  排序工具

  判空

  克隆

  轉數組

  逆轉

  去重復

  序列化

  等等。。。

 

鏈表可做的操作會比想象的多的多。

 

4、Java中的鏈表

 

Java中常用的鏈表是LinkedList,實現了List接口,繼承AbstractLinkedList。同時還有其他接口

 

同時,還有Queue大類,並非在Collection接口下,但是底層有些是使用鏈表實現的,功能有些是重復的。

對於需要作為原子操作的各種功能的隊列來說,可以考慮。

 

在擴展Java中的鏈表的時候,有幾種方式供選擇:

  ①繼承LinkedList,添加擴展算法;

  ②實現List,繼承AbstractLinkedList,同時擴展算法;

  ③使用裝飾模式,在構造器中調用鏈表的構造器,同時擴展算法;

  ④不受約束自己寫一個吧。。。

 

5、寫一個簡單的鏈表

 

我嘗試寫了一個簡單的鏈表,以前也大概看過C的鏈表和Java的鏈表,寫的過程中全憑記憶,

大約花了十個小時才寫完,哩哩啦啦好多天。

 

代碼拙劣,為了以后嘗試鏈表的其他算法(排序,轉換,反轉,環鏈表,擴展二叉樹)做准備。

 

代碼如下:

 

package com.FM.ArrayStudy;

public class SimpleLinkedList<T> {

    private Node<T> pointer;// 當前指針節點
    private Node<T> firstNode;// 首個節點
    private Node<T> lastNode;// 末尾節點
    private Integer index = 0;// 當前指針index
    private Integer size = 0;// 當前容量

    /**
     * 獲取當前pointer的info
     * @return
     */
    public T getThis() {
        if (null == pointer) {
            return firstNode.info;
        } else {
            return pointer.info;
        }
    }

    /**
     * 獲取下一個元素的內容,若沒有下一個元素,則返回null
     * 
     * @return
     */
    public T getNext() {
        if (index.equals(size - 1)) {
            return null;
        } else {
            if (null == pointer) {
                pointer = firstNode;
                pointer = pointer.next;
                T info = pointer.info;
                index++;
                return info;
            } else {
                pointer = pointer.next;
                T info = pointer.info;
                index++;
                return info;
            }
        }
    }

    /**
     * 修改指定index的元素的方法
     * 
     * @param index
     * @param t
     * @throws Exception
     */
    public void set(Integer index, T t) throws Exception {
        if (index > -1 && index < size - 1) {
            Node<T> node = getNodeByIndex(index);
            node.info = t;
        } else {
            throw new Exception("get ele " + index + " out of index");
        }
    }

    /**
     * 修改首元素
     * 
     * @param t
     */
    public void setFirst(T t) {
        firstNode.info = t;
    }

    /**
     * 修改尾元素
     * 
     * @param t
     */
    public void setLast(T t) {
        lastNode.info = t;
    }

    /**
     * 從指定index移除node的方法
     * 
     * @param index
     * @throws Exception
     */
    public void remove(Integer index) throws Exception {
        if (index > -1 && index < size) {
            if (index.equals(0)) {
                Node<T> node = getNodeByIndex(1);
                firstNode = node;
                firstNode.prve = null;
            } else if (index.equals(size - 1)) {
                Node<T> node = getNodeByIndex(size - 2);
                lastNode = node;
                lastNode.next = null;
            } else {
                Node<T> node = getNodeByIndex(index);
                Node<T> nextNode = node.next;
                Node<T> prveNode = node.prve;
                prveNode.next = nextNode;
                nextNode.prve = prveNode;
                node = null;
            }
            size--;
        } else {
            throw new Exception("get ele " + index + " out of index");
        }

    }

    /**
     * 獲取當前元素在鏈表中的位置
     * 
     * @return
     */
    public int getIndex() {
        return index;
    }

    /**
     * 獲取當前鏈表size的方法
     * 
     * @return
     */
    public Integer size() {
        return size;
    }

    /**
     * 判斷容器是否為空的方法,為空返回true
     * 
     * @return
     */
    public boolean isEmpty() {
        if (size.equals(0)) {
            return true;
        } else {
            return false;
        }

    }

    /**
     * 根據index查詢鏈表中元素的方法
     * 
     * @param index
     * @return
     * @throws Exception
     */
    public T getByIndex(Integer index) throws Exception {
        if (index > -1 && index < size) {
            Node<T> nodeByIndex = getNodeByIndex(index);
            return nodeByIndex.info;
        } else {
            throw new Exception("get ele " + index + " out of index");
        }
    }

    /**
     * 根據index獲取node的方法
     * 
     * @param index
     * @return
     */
    private Node<T> getNodeByIndex(Integer index) {
        Node<T> temp = firstNode;// 取firstnode
        if (index != 0) {// 查看當前index,若index!=0,則遞歸直到index
            for (int i = 0; i < index; i++) {
                temp = temp.next;
            }
        }
        this.index = index;// 調整當前index
        return temp;// 返回節點
    }

    /**
     * 向鏈表末尾默認添加一個元素的方法
     * 
     * @param t
     */
    public void add(T t) {
        if (size == 0) {// 首次創建
            Node<T> node = new Node<T>();
            firstNode = node;
            lastNode = node;
            node.info = t;
            size++;
        } else {
            lastNode.next = new Node<T>();
            lastNode.next.info = t;
            lastNode.next.prve = lastNode;
            lastNode = lastNode.next;
            size++;
        }
    }

    /**
     * 在首添加元素
     * 
     * @param t
     */
    public void addFirst(T t) {
        if (size == 0) {
            add(t);
        } else {
            Node<T> node = new Node<T>();
            node.info = t;
            node.next = firstNode;
            node.prve = null;
            firstNode.next = node;
            size++;
        }
    }

    /**
     * 在尾部添加元素
     * 
     * @param t
     */
    public void addLast(T t) {
        add(t);
    }

    /**
     * Node節點 鏈表內部數據結構和指針
     * 
     * @author Liuyuhang
     * @param <T>
     */
    private class Node<T> {
        T info;// 儲存info
        Node<T> next;// 下一個節點指針
        Node<T> prve;// 上一個節點指針

        @Override
        public String toString() {// 同時打印next和prev會導致無限引用,堆棧溢出
            return "Node [info=" + info + ", next=" + next + "]";
        }

    }

    @Override
    public String toString() {// 打印first節點會因為next引出整個鏈表的所有內容
        return "SimpleLinkedList [node=" + firstNode + "]";
    }

}

 

測試可用,自己拿去玩吧。

 

以上!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM