線性表的基本特徵:java
線性表按物理存儲結構的不一樣可分爲順序表(順序存儲)和鏈表(鏈式存儲):算法
順序表是在計算機內存中以數組的形式保存的線性表,是指用一組地址連續的存儲單元依次存儲數據元素的線性結構。線性表採用順序存儲的方式存儲就稱之爲順序表。編程
插入刪除操做如圖:數組
抽象數據類型(ADT)是指一個數學模型及定義在該模型上的一組操做。於Java語言中的抽象類和接口設計理念是想通的。安全
abstract class SequenceListAbst{ //順序表 private static final int DEFAULT_CAPACITY=10; private int size; private Object[] elements; //Object數組 public SequenceListAbst(){ size=0; elements=new Object[DEFAULT_CAPACITY]; } //順序表大小 public abstract int size(); //判斷是不是空 public abstract boolean isEmpty(); //清空順序表 public abstract void clear(); //在index處添加元素 public abstract void add(int index, Object element); //刪除指定索引的元素 public abstract boolean delete(int index); //獲取指定索引的元素 public abstract Object get(int index); //遍歷鏈表 public abstract void iterator(); }
具體的代碼省略...數據結構
順序表效率分析:dom
順序表的優缺點:編程語言
順序表適合元素個數變化不大,且更可能是讀取數據的場合。ide
擴展:性能
Java中AarrayList是系統實現的順序表,它是一個動態數組。添加時會有擴容,刪除時會有縮容。
擴容:經過無參構造的話,初始數組容量根據JDK版本不一樣策略不一樣,每次經過copeOf的方式擴容後容量爲原來的1.5倍。
縮容:ArrayList不會自動縮小容積,有一個方法 trimToSize 能夠縮小容積。
其餘描述:
ArrayList是基於數組實現的,是一個動態數組,其容量能自動增加。 ArrayList不是線程安全的,只能用在單線程環境下。 實現了Serializable接口,所以它支持序列化,可以經過序列化傳輸; 實現了RandomAccess接口,支持快速隨機訪問,實際上就是經過下標序號進行快速訪問; 實現了Cloneable接口,能被克隆。
鏈表(LinkedList)一般由一連串節點組成,每一個節點包含任意的實例數據(data fields)和一或兩個用來指向上一個/或下一個節點的位置的連接("links")
鏈表是一種常見的基礎數據結構,是一種線性表,可是並不會按線性的順序存儲數據,而是在每個節點裏存放指向下一個節點的指針(Pointer),Java中稱之爲引用。
使用鏈表結構能夠克服數組鏈表須要預先知道數據大小的缺點,鏈表結構能夠充分利用計算機內存空間,實現靈活的內存動態管理。可是鏈表失去了數組隨機讀取的優勢,同時鏈表因爲增長告終點的指針域,空間開銷比較大。
(1)單鏈表是鏈表中結構最簡單的。一個單鏈表的節點(Node)分爲兩個部分,第一個部分(data)保存或者顯示關於節點的信息,另外一個部分存儲下一個節點的地址。最後一個節點存儲地址的部分指向空值。
單鏈表有帶頭結點和不帶頭結點兩種結構,其結構以下
因爲帶頭結點的鏈表更容易操做,這裏僅實現帶頭結點的單鏈表
帶頭結點的鏈表插入與刪除示意圖:
抽象數據類型(ADT)是指一個數學模型及定義在該模型上的一組操做。於Java語言中的抽象類和接口設計理念是想通的。
abstract class SingleLinkedListAbst{ //單鏈表 protected int size; //鏈表節點的個數 protected Node head; //頭節點 //鏈表的每一個節點類 protected class Node{ //內部類 protected Object data; //每一個節點的數據 protected Node next; //每一個節點指向下一個節點的引用 public Node(Object data){ this.data=data; } } //單鏈表的大小 public abstract int size(); //判斷鏈表是否爲空 public abstract boolean isEmpty(); //在鏈表index處添加元素 public abstract void add(int index, Object element); //刪除指定索引的元素 public abstract boolean delete(int index); //判斷元素是否存在 public abstract boolean exist(Object obj); //查找元素,根據索引index返回節點Node public abstract Node get(int index); //遍歷鏈表 public abstract void print(); }
具體的代碼:
class SingleLinkedList extends SingleLinkedListAbst{ //實現單鏈表 public SingleLinkedList(){ //構造方法初始化一個頭結點 head=new Node("head"); head.next=null; size=0; } @Override public int size() { return size; } @Override public boolean isEmpty() { return size==0; } @Override public void add(int index, Object element) { if(index<0 || index>size){ throw new IndexOutOfBoundsException("參數輸入錯誤:"+index); } //找到索引index結點以前的結點 Node before=head; int temp=index; while(temp-->0){ before=before.next; } //構造新的待插入結點 Node newNode=new Node(element); //若索引index處的結點不存在,就在最後插入 if(index==(size+1)){ before=newNode; newNode.next=null; size++; return; } //插入結點(斷開舊引用,構造新的引用) Node after=before.next; before.next=newNode; newNode.next=after; size++; } @Override public boolean delete(int index) { // TODO Auto-generated method stub return false; } @Override public boolean exist(Object obj) { // TODO Auto-generated method stub return false; } @Override public Node get(int index) { // TODO Auto-generated method stub return null; } @Override public void print() { Node currentNode=head.next; if(currentNode==null){ return; } int temp=size; while(temp--!=0){ //循環 System.out.println((String)currentNode.data); currentNode=currentNode.next; } } }
此處因爲時間緣由做者只寫了一部分,如是想提高能力的讀者必然是所有寫完。
單鏈表效率分析:
在單鏈表上插入和刪除數據時,首先須要找出插入或刪除元素的位置。對於單鏈表其查找操做的時間複雜度爲 O(n),因此
鏈表插入和刪除操做的時間複雜度均爲 O(n)
鏈表讀取操做的時間複雜度爲 O(n)
單鏈表優缺點:
(2)單向循環鏈表
將單鏈表中終端結點的指針指向頭結點,使整個單鏈表造成一個環,這種頭尾相接的單鏈表稱爲單循環鏈表,簡稱循環鏈表。
對於循環鏈表,爲了使空鏈表與非空鏈表處理一致,一般設一個頭結點。如圖:
循環鏈表和單鏈表的主要差別在於鏈表結束的判斷條件不一樣,單鏈表爲current.next
是否爲空,而循環鏈表爲current.next
不等於頭結點。對於循環鏈表的增刪改查操做與單鏈表基本相同,僅僅須要將鏈表結束的條件變成current.next != head
便可。
(3)雙向鏈表
雙向鏈表是在單鏈表的每一個結點中,再設置一個指向其前驅結點的指針域。使得兩個指針域一個指向其前驅結點,一個指向其後繼結點。
對於雙向鏈表,其空和非空結構以下圖:
雙向鏈表是單鏈表擴展出來的結構,它能夠反向遍歷、查找元素,它的不少操做和單鏈表相同,好比求長度size()、查找元素get()。這些操做只涉及一個方向的指針便可。插入和刪除操做時,須要更改兩個指針變量。
插入操做:注意操做順序
雙向鏈表相對於單鏈表來講佔用了更多的空間,但因爲其良好的對稱性,使得可以方便的訪問某個結點的先後結點,提升了算法的時間性能。是用空間換時間的一個典型應用。
不少代碼的實現沒有寫完,如是想提高能力的讀者必然是所有寫完(附:對於數據結構初學者(已熟練駕馭編程語言自己),鏈表的編寫必然是熬三天三夜才能搞清楚脈絡的)。
舒適提示:看的懂和能寫出來絕對是兩回事!