長度不固定,能夠任意增刪。java
存儲密度小,由於每一個數據元素,都須要額外存儲一個指向下一元素的指針(雙鏈表則須要兩個指針)。node
要訪問特定元素,只能從鏈表頭開始,遍歷到該元素,時間複雜度爲 $O(n)$。在特定的數據元素以後插入或刪除元素,不涉及到其餘元素的移動,所以時間複雜度爲 $O(1)$。雙鏈表還容許在特定的數據元素以前插入或刪除元素。算法
插入算法是單鏈表的核心算法,掌握了這個,後面的頭插法,尾插法都是so easy編程
下圖就是顯示瞭如何將p結點插入到q的後面ide
刪除算法其實很簡單spa
下圖是刪除某個結點的後繼的圖示指針
頭插法和尾插法code
使用頭插法建立出的單鏈表是逆序的, 使用尾插法建立出的單鏈表則是順序的,通常都是採用此尾插法來創建單鏈表
blog
頭插法簡單來講,就是每次插入的結點都是在頭結點的後繼rem
尾插法則是每次插入的結點都是在鏈表的末尾結點的後繼
查找算法的關鍵在於結束條件
下列代碼中的t!=null則是結束的條件
Lnode t = h.next; while(t!=null){ if(t.data==x){ System.out.println("找到"); return t; } t = t.next; } return null;
import java.util.Scanner; public class LinkedList implements ListIntf{ Lnode h =null; public static String toucha = "頭插法"; public static String weicha = "尾插法"; public LinkedList(String s){ //若是參數是頭插法則使用頭插法建立單鏈表,不是則使用尾插法 if(s.equals(toucha)){ h=new Lnode(); h.data = 'f'; h.next = null; Lnode p; Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); for(int i=0;i<str.length();i++){ p = new Lnode(); p.data = str.charAt(i); p.next = h.next; h.next = p; } scanner.close(); }else{ h=new Lnode(); h.data = 'f'; h.next = null; Lnode p,t; t=h; //t用來代替頭結點,同時,也就是 Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); for(int i=0;i<str.length();i++){ p = new Lnode(); p.data = str.charAt(i); //接收String中的char p.next = t.next;//此條語句與p.next =null 等同 t.next = p; t = p; // t結點一直指向鏈表的末尾 } scanner.close(); } } public void display(){ Lnode p = h.next; while(p!=null){ System.out.println(p.data); p = p.next; } } /** * 設置頭結點 * @param _h */ public void setH(Lnode _h){ h=_h; } /** * * @param p 結點 * @param x 某個結點的值爲x * 將值爲x的結點插入到p結點的後面 */ public void insertElementAfter(Lnode p,char x){ Lnode t = new Lnode(x); t.next = p.next; //這裏容易忘記 p.next=t; } /** * * @param x * @return 查找到值爲x的結點 */ public Lnode search(char x){ Lnode t = h.next; while(t!=null){ if(t.data==x){ System.out.println("找到"); return t; } t = t.next; } return null; } @Override public int size() { int i =0; Lnode t = h.next; while(t!=null){ i++; t = t.next; } return i; } @Override public void clear() { h.next = null; } @Override public boolean isEmpty() { if(h.next==null){ return false; }else{ return true; } } /** * * @param i 須要找到的第i個結點 * @return 第i個結點 */ public Lnode getLnode(int i){ Lnode t = h; //從頭結點算起,j就是從0開始 int j =0; while(j<i){ t = t.next; j++; } if(t==null){ return null; }else{ return t; } } @Override public String get(int i) { //取得第i個結點的值 Lnode t = h; //從頭結點算起,j就是從0開始 int j =0; while(j<i){ t = t.next; j++; } //或者從第一個結點開始 /*Lnode t = h.next; int j =1; while(j<i){ t = t.next; j++; }*/ //這裏須要加一個溢出處理 if(t==null){ return null; }else{ return String.valueOf(t.data); } } @Override public int indexOf(String s) { //單鏈表不須要複寫此方法 return 0; } @Override public String getPre(String s) { //單鏈表不須要複寫此方法 return null; } @Override public String getNext(String s) { // TODO Auto-generated method stub return null; } @Override public void insertElementAt(String s, int i) { // TODO Auto-generated method stub } @Override public String remove(int i) { //先找到第i個結點,以後再將其移出,斌返回其的數值 Lnode t = getLnode(i); Lnode q = getLnode(i-1); //q爲t的前趨 q.next = t.next; return String.valueOf(t.data); } @Override public String remove(String s) { // TODO Auto-generated method stub return null; } }
在Java實現字符窗口的輸入時,不少人更喜歡選擇使用掃描器Scanner,它操做起來比較簡單。在編程的過程當中,我發現用Scanner實現字符串的輸入有兩種方法,一種是next(),另外一種是nextLine(),這兩種有如下區別:
next()必定要讀取到有效字符後才能夠結束輸入,對輸入有效字符以前遇到的空格鍵、Tab鍵或Enter鍵等結束符,next()方法會自動將其去掉,只有在輸入有效字符以後,next()方法纔將其後輸入的空格鍵、Tab鍵或Enter鍵等視爲分隔符或結束符。
簡單地說,next()查找並返回來自此掃描器的下一個完整標記。完整標記的先後是與分隔模式匹配的輸入信息,因此next方法不能獲得帶空格的字符串。
nextLine()方法的結束符只是Enter鍵,即nextLine()方法返回的是Enter鍵以前的全部字符,它是能夠獲得帶空格的字符串的。