算法是什麼(二)手寫個鏈表(java)html
liuyuhang原創,未經容許禁止轉載java
目錄node
算法是什麼(〇)算法
不少語言的API中都提供了鏈表實現,或者擴展庫中實現了鏈表。
數組
可是更多的狀況下,Map(或hash)和List(非定容數組)的使用率更高。數據結構
這並不是意味着鏈表不該該掌握或不使用了。ide
鏈表本質上是一種及其高等的數據結構展示,擴展性極強。工具
鏈表可輕鬆擴展成樹結構,二叉樹,環,棧,隊列,雙向隊列等。post
不少種數據結構都是依據鏈表的形式擴展出來的,雖然我知道的並很少,可是我知道鏈表的重要性。測試
因此,手寫一個鏈表試試。
一、本質
鏈表的本質是Node(節點),其中保存着信息(info),前一個節點(prevNode),後一個節點(nextNode)。
和基礎操做API構成
二、特性
鏈表爲了操做的方便性,多數會將鏈表作成雙向鏈表,即既包含next,又包含prev
三、基礎API
鏈表的操做,至少須要增刪改查,否則還算啥容器了:
增:默認從末尾添加,添加指定index,在首添加三種方式添加單一元素。
刪:刪除頭,刪除尾,刪除指定index的元素,刪除當前指針元素。
改:設置頭,設置尾,設置指定index的元素,設置當前指針元素。
查:獲取當前指針元素,獲取首元素,獲取尾元素,獲取下一個元素,獲取上一個元素,獲取指定index的元素
有些API還提供了更多的操做:
獲取當前容器的size
獲取當前指針的index
迭代器
排序工具
判空
克隆
轉數組
逆轉
去重複
序列化
等等。。。
鏈表可作的操做會比想象的多的多。
四、Java中的鏈表
Java中經常使用的鏈表是LinkedList,實現了List接口,繼承AbstractLinkedList。同時還有其餘接口
同時,還有Queue大類,並不是在Collection接口下,可是底層有些是使用鏈表實現的,功能有些是重複的。
對於須要做爲原子操做的各類功能的隊列來講,能夠考慮。
在擴展Java中的鏈表的時候,有幾種方式供選擇:
①繼承LinkedList,添加擴展算法;
②實現List,繼承AbstractLinkedList,同時擴展算法;
③使用裝飾模式,在構造器中調用鏈表的構造器,同時擴展算法;
④不受約束本身寫一個吧。。。
五、寫一個簡單的鏈表
我嘗試寫了一個簡單的鏈表,之前也大概看過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 + "]"; } }
測試可用,本身拿去玩吧。
以上!