線性表是一種十分基礎且重要的數據結構,它主要包括如下內容:git
接下來,我將對這四種數據結構作一個詳細的總結,其中對鏈表實現了十幾種常見的操做。但願對你有所幫助。github
數組(Array)是一種線性表數據結構。它用一組連續的內存空間,來存儲一組具備相同類型的數據。
注意點:①.數組是一種線性表;②.連續的內存空間和相同類型的數據
因爲第二個性質,數組支持 「隨機訪問」,根據下表隨機訪問的時間複雜度爲O(1);但與此同時卻使得在數組中刪除,插入數據須要大量的數據搬移工做。算法
假如數組的長度爲n,咱們須要將一個數據插入到數組的第k個位置,咱們須要將第k~n位元素都順序地日後挪動一位。
最好狀況時間複雜度爲O(1),此時對應着在數組末尾插入元素;
最壞狀況時間複雜度爲O(n),此時對應着在數組開頭插入元素;
平均狀況時間複雜度爲O(n),由於咱們在每一個位置插入元素的機率相同,故(1+2+3+……+n)/n=O(n);
可是根據咱們的需求,有一個特定的場景。若是數組的數據是有序的,那麼咱們在插入時就必定要那麼作;可是若是數組中存儲的數據並無任何規律,數組只是被當成一個存儲數據的集合,咱們能夠有一個取巧的方法:
直接將第k個元素搬移到數組元素的最後,把新的數據直接放入第k個位置便可(是否是很簡單啊),這時插入元素的複雜度爲O(1)。數組
和插入操做同樣,爲了保證內存的連續性,刪除操做也須要搬移數據。
最好狀況時間複雜度爲O(1),此時對應着刪除數組末尾的元素;
最壞狀況時間複雜度爲O(n),此時對應着刪除數組開頭的元素;
平均狀況時間複雜度爲O(n),由於咱們刪除每一個位置的元素的機率相同,故(1+2+3+……+n)/n=O(n);
固然,在某些特殊狀況下,咱們並不必定非要進行複雜的刪除操做。咱們只是將須要刪除的數據記錄,而且僞裝它以經被刪除了。直到數組沒有更多空間存儲數據時,咱們再觸發一次真正的刪除操做便可。數據結構
這其實就和生活中的垃圾桶相似,垃圾並無消失,只是被「 標記」成了垃圾,而直到垃圾桶塞滿時,纔會清理垃圾桶。
在 C 語言中,只要不是訪問受限的內存,全部的內存空間都是能夠自由訪問的。若是疏忽會形成嚴重的後果。固然,Java會自動檢測。函數
public class Node{ int data; Node Next; }
public class Method { //打印單鏈表 public static void PrintNode (Node list){ for(Node x=list;x!=null;x=x.Next) System.out.print(x.data+" "); System.out.println(); }
public static Node insert(Node first,int index,Node a){ Node ret = new Node(); ret.Next=first;//建立一個虛擬頭節點 Node p=ret; while((index--)!=0) p=p.Next; //完成節點的插入操做 a.Next=p.Next; p.Next=a; //返回真正的鏈表頭節點地址 return ret.Next;//函數返回鏈表的頭節點 }
public static int GetLength(Node first){ int n=0; for(Node x=first;x!=null;x=x.Next){ ++n; } return n; }
public static void PrintLength(Node first){ System.out.println("Length : "+GetLength(first)); }
public static Node Delete(Node first,int index){ if(index<0||index>=GetLength(first)) return first; else{ Node ret=new Node(); ret.Next=first; Node p=ret; while((index--)!=0) p=p.Next; //完成節點的刪除操做 p.Next=p.Next.Next; return ret.Next; } }
public static boolean Find(Node first,int key){ for(Node x=first;x!=null;x=x.Next){ if(x.data==key) return true; } return false; }
public static void RemoveAfter(Node first,int index){ Node ret=new Node(); ret.Next=first; Node p=ret; while((index--)!=0) p=p.Next; p.Next.Next=null; }
public static Node reverse(Node list){ Node curr=list,pre=null; while(curr!=null){ Node next=curr.Next; curr.Next=pre; pre=curr; curr=next; } return pre; }
public static Node reverseRecursively(Node head){ if(head==null||head.Next==null) return head;//遞歸的終止條件,返回反轉後鏈表的頭節點 Node reversedListHead=reverseRecursively(head.Next); head.Next.Next=head;//改變這兩個結點之間的指向順序 head.Next=null; return reversedListHead;//返回反轉後的鏈表頭節點 }
public static boolean checkCircle(Node list){ if(list==null) return false; Node fast=list.Next; Node slow=list; while(fast!=null&&fast.Next!=null){ fast=fast.Next.Next; slow=slow.Next; if(slow==fast) return true; } return false; }
public static Node deleteLastKth(Node list,int k){ //利用兩個指針,fast和slow,它們之間差k個位置,判斷若是fast.Nest=null,也就表明着slow這個位置就是倒數第k個結點 Node fast=list; int i=1; while(fast!=null&&i<k){ fast=fast.Next; ++i; } if(fast==null) return list; Node slow=list; Node prev=null; while(fast.Next!=null){ fast=fast.Next; prev=slow; slow=slow.Next; } if(prev==null){ list=list.Next; }else{ prev.Next=prev.Next.Next; } return list; }
public static Node findMiddleNode(Node list){ if(list==null) return null; Node fast=list; Node slow=list; while(fast!=null&&fast.Next!=null){ fast=fast.Next.Next; slow=slow.Next; } return slow; }
public static Node mergeTwoLists(Node l1,Node l2){ Node soldier=new Node(); Node p=soldier; while(l1!=null&&l2!=null){ if(l1.data<l2.data){ p.Next=l1; l1=l2.Next; } else{ p.Next=l2; l2=l2.Next; } p=p.Next; } if(l1!=null){ p.Next=l1;} if(l2!=null){ p.Next=l2;} return soldier.Next; }
package Stack; //基於數組實現的順序棧 public class ArrayStack { private int[] items; private int count;//棧中的元素個數 private int n;//棧的大小 //初始化數組,申請一個大小爲n的數組空間 public ArrayStack(int n){ this.items=new int[n]; this.n=n; this.count=0; } //入棧操做 public boolean push(int item){ //數組空間不足,直接返回false,入棧失敗 if(count==n) return false; //將data放在下標爲count的位置,而且count加一 items[count]=item; ++count; return true; } //出棧操做 public int pop(){ //棧爲空,直接返回-1; if(count==0) return -1; //返回下標爲count-1的數組元素,而且棧中元素個數count減一 int tmp=items[count-1]; --count; return tmp; } public void PrintStack(){ for(int i=count-1;i>=0;--i){ System.out.print(items[i]+" "); } System.out.println(); } }
package Stack; public class LinkedListStack { private Node top;//棧頂(最近添加的元素) private int N;//元素數量 private class Node{ //定義告終點的嵌套類 int data; Node Next; } public boolean isEmpty(){ return top==null; } public int size(){ return N; } public void push(int data){ /*Node newNode=new Node(); //判斷是否爲空棧 //if(top==null) newNode=top; top.data=data; top.Next=newNode; N++;*/ Node newNode=top; top=new Node(); top.data=data; top.Next=newNode; ++N; } public int pop(){ //從棧頂刪除元素 if(top==null) return -1;//這裏用-1表示棧中沒有數據 int data=top.data; top=top.Next; N--; return data; } public void PrintStack(){ for(Node x=top;x!=null;x=x.Next){ System.out.print(x.data+" "); } System.out.println(); } }
package Queue; //用數組實現隊列 public class ArrayQueue { //數組:items,數組大小:n private int[] items; private int n=0; //head表示隊頭下標,tail表示隊尾下標 private int head=0; private int tail=0; //申請一個大小爲capacity的數組 public ArrayQueue(int capacity){ items=new int[capacity]; n=capacity; } //入隊(一),基礎版 public boolean enqueue(int item){ //若是tail==n,表示隊列末尾已經沒有空間了 if(tail==n) return false; items[tail]=item; ++tail; return true; } //入隊(二),改進版 public boolean enqueue1(int item){ //若是tail==n,表示隊列末尾已經沒有空間了 if(tail==n){ //tail==n&&head==0,表示整個隊列都佔滿了 if(head==0) return false; //數據搬移 for(int i=head;i<tail;++i){ items[i-head]=items[i]; } //搬移完成後從新更新head和tail tail=tail-head; head=0; } items[tail]=item; ++tail; return true; } //出隊 public int dequeue(){ //若是head==tail,表示隊列爲空 if(head==tail) return -1;//這裏用-1表示隊列爲空 int ret=items[head]; ++head; return ret; } //打印隊列 public void PrintQueue(){ for(int i=head;i<tail;++i){ System.out.print(items[i]+" "); } System.out.println(); } }
package Queue; //基於鏈表實現的隊列 public class LinkedListQueue { private Node head;//指向最先添加的結點的連接 private Node tail;//指向最近添加的結點的連接 private int N;//隊列中的元素數量 private class Node{ //定義告終點的嵌套類 int data; Node Next; } public boolean isEmpty(){ return head==null; } public int size(){ return N;} //向表尾添加元素,即入隊 public void enqueue(int data){ Node newNode=tail; tail=new Node(); tail.data=data; tail.Next=null; if(isEmpty()) head=tail; else newNode.Next=tail; ++N; } public int dequeue(){ //從表頭刪除元素 int data=head.data; head=head.Next; if(isEmpty()) tail=null; N--; return data; } //打印輸出隊列元素 public void PrintQueue(){ for(Node x=head;x!=null;x=x.Next){ System.out.print(x.data+" "); } System.out.println(); } }
package Queue; public class CircularQueue { //數組items,數組大小n private int[] items; private int n=0; //head表示隊頭下標,tail表示隊尾下標 private int head=0; private int tail=0; //申請一個大小爲capacity的數組 public CircularQueue(int capacity){ items = new int[capacity]; n=capacity; } //入隊 public boolean enqueue(int item){ //隊列滿了 if((tail+1)%n==head) return false; items[tail]=item; tail=(tail+1)%n;//實現計數的循環 return true; } //出隊 public int dequeue(){ //若是head==tail,表示隊列爲空 if(head==tail) return -1;//以-1表示隊列爲空 int ret=items[head]; head=(head+1)%n; return ret; } //打印隊列 public void PrintQueue(){ if(n==0) return; for(int i=head;i%n!=tail;i=(i+1)%n){ System.out.print(items[i]+" "); } System.out.println(); } }
文章代碼太多,我原本是但願分紅幾篇文章寫的,可是因爲一些緣由,最終放在了一塊兒,略顯臃腫。代碼都是通過測試用例測試過的,應該不會有錯誤。測試
若是體驗不太好,能夠移步個人Github,裏面觀感較好。this
題外話:對於算法初學者,推薦一本十分 nice 的書籍 《算法第四版》,裏面各類配圖十分詳細。若是你須要電子版文件,後臺回覆算法4便可得到下載連接。後臺回覆 算法01 送你一份 算法與數據結構思惟導圖。最後,但願咱們一塊兒進步,一塊兒成長!指針