Java 單向鏈表學習
鏈表等同於動態的數組;可以不同設定固定的空間,根據需要的內容動態的改變鏈表的占用空間和動態的數組同一形式;鏈表的使用可以更加便於操作。
鏈表的基本結構包括:鏈表工具類和節點類,節點類是工具類的內部類,這樣可以便於Link和Node類之間的屬性調用和方法使用,也有效的封裝了Node類不被外部所使用;
Link類主要負責處理外部類和Node類之間的關系以及鏈表內容的存儲;Node類負責具體的鏈表結構的操作,比如:添加鏈表時需要將新的鏈表放在上一個鏈表的后面則需要Link調用Node類進行鏈表結構的定義,同理:大多鏈表結構的操作都有Node負責具體的操作和定義,而Link類主要負責外部類和Node類的關系。
鏈表結構中:root負責記錄鏈表首結構的地址,next負責記錄當前鏈表節點的下一個鏈表節點的地址,data則是記錄具體的數據類型的數據信息。
class Link { //鏈表類(外部可調用的一個工具類) class Node { //節點類,定義該內部類,只可服務於Link類 private String data ; //節點數據 private Node next ; //引用關系(順序) public Node(String data) { this.data = data ; } public void addNode(Node newNode){ if ( this.next == null){ //下一個節點為空則設置下一個節點 this.next = newNode ; } else { //若節點存在,則向后移 this.next.addNode(newNode) ; } } public boolean containsNode(String data) { //(如果比較的數據是對象,則定義一個對象比較的方法。) if ( data.equals(this.data)) { //對比data return true ; } else { if ( this.next != null ) { // 對比下一個data return this.next.containsNode(data) ; } else { return false ; } } } public String getNode(int index) { //索引查找 // 1 比較index和foot的值是否相等 // 2 將foot的內容自增 1 if ( Link.this.foot ++ == index) { //對比當前節點的foot return this.data ; } else { //下一個節點 return this.next.getNode(index) ; } } public void setNode(int index , String data) { if ( Link.this.foot ++ == index ) { this.data = data ; //內容修改(替換 ) } else { if ( this.next != null ) { this.next.setNode(index,data) ; } } } // 要傳遞上一個節點以要刪除的數據 public void removeNode( Node previous , String data ) { if ( data.equals(this.data)){//數據滿足刪除條件 previous.next = this.next ; //上一個節點的next指向當前的next(空出當前節點) } else { // 繼續匹配查詢刪除 if(this.next != null) { this.next.removeNode(this , data) ;//this表示當前對象,將this給previous // 因為previous接收的是上一個對象。 } } } public void toArrayNode() { Link.this.retArray[Link.this.foot ++] = this.data ; if ( this.next != null ) { this.next.toArrayNode() ; } } } /* ========================================================================== */ private Node root ; //根節點 private int count = 0 ; //保存元素的個數 private int foot = 0 ; //保存鏈表的索引編號 private String [] retArray ; //對象數組 public void add(String data) { //數據添加 Node newNode = new Node(data) ; if ( this.root == null ){//無根節點,保存根節點 this.root = newNode ; } else { //向Node調用 this.root.addNode(newNode) ; } this.count ++ ; //每一個保存后數據量自加 1 } public int size() { //判斷返回鏈表數據數量 return this.count ; } public boolean isEmpty() { //判斷鏈表是否為空 return this.count == 0 ; // 根據鏈表數量判斷 } public boolean contains(String data) { //查詢數據是否存在 if ( data == null || this.root == null ) { //查找數據為空則false return false ; } return this.root.containsNode(data) ; //不為空則調用Node查找數據; } public String get(int index) { //設置索引目標 index if ( index > this.count ) { return null ; } this.foot = 0 ; //索引歸零,表示從左往右查找 return this.root.getNode(index) ; //調用getNode()查找 } public void set(int index , String data) {//修改鏈表數據內容 if ( data == null || this.root == null ) { return ; } this.foot = 0 ; // 重置foot,便於查找內容 this.root.setNode(index,data) ; //調用Node修改 } /* 如果要刪除的是根節點:root指向下一個節點即可 如果刪除的不是根節點:刪除的前一個節點,下一個節點指向刪除的下一個節點 刪除數據的形式:當前節點的上一個節點next = 當前節點的next 需要設置一個方法專門處理非根節點的刪除(removeNode()方法) */ public void remove(String data) { if ( this.contains(data)) {//contains() 判斷數據是否存在 // 判斷刪除的數據是不是根節點數據 // root是Node類的對象,此處直接訪問了Node對象的私有屬性 data if ( data.equals(this.root.data)) { this.root = this.root.next ; //空出當前節點(改變根節點) } else { this.root.next.removeNode(this.root , data) ; } this.count -- ; //鏈表個數減一 } } // 首先開辟一個數組空間,空間 == count public String [] toArray() { //將鏈表以對象數組形式返回 if (this.root == null ) { return null ; } this.foot = 0 ; //下標控制 this.retArray = new String [this.count] ; //開辟一個數組 this.root.toArrayNode() ; //Node處理 return retArray ; } } public class LinkDemo { //基本程序框架 public static void main(String args[]) { // 測試數據 Link all = new Link(); // 添加數據 all.add("Hello") ; all.add("World") ; all.add("Mirror") ; all.add("2019/4/17") ; all.add( "null" ) ; // 獲得鏈表長度(數據量) System.out.println(all.size()) ; // 判斷鏈表是否為NULL System.out.println(all.isEmpty()) ; // 根據內容查找數據是否存在 System.out.println(all.contains("Hello")) ; System.out.println(all.contains("yang")) ; // 根據索引foot輸出鏈表內容(索引foot是動態的) //某種程度上鏈表就是動態的數組 System.out.println(all.get(1)) ; //System.out.println(all.get(5)) ; // 修改鏈表內容 all.set(1,"yang"); System.out.println(all.get(1)) ; //數據刪除 all.remove("yang") ; System.out.println(all.contains("yang")) ; System.out.println("====================") ; //對象數組轉換 String [] data = all.toArray() ; for ( int x = 0 ; x <= data.length-1 ; x++ ) { System.out.print("\t" + data[x]) ; } } }
鏈表最好的使用就是橫向替代對象數組;可以將存入的數據按照鏈表存儲(順序方法)。

class Book { private String title ; private double price ; public Book(String title , double price) { this.title = title ; this.price = price ; } public String getInfo() { return "圖書名稱:" + this.title + ", 價格:" + this.price ; } public boolean compare(Book book) { if ( this == book ) { return true ; } if ( book == null ) { return false ; } if ( this.title.equals(book.title) && this.price == book.price ) { return true ; } return false ; } } class Link { class Node { private Book data ; private Node next ; public Node( Book data ) { this.data = data ; } public void addNode( Node newNode ) { if ( this.next == null ) { this.next = newNode ; } else { this.next.addNode(newNode) ; } } public boolean containsNode( Book data ) { if ( data.compare(this.data) ) { return true ; } else { if ( this.next != null) { return this.next.containsNode(data) ; } else { return false ; } } } public Book getNode(int index) { if ( Link.this.foot ++ == index ) { return this.data ; } else { return this.next.getNode(index) ; } } public void setNode(int index , Book data) { if ( Link.this.foot ++ == index ) { this.data = data ; } else { if ( this.next != null) { this.next.setNode(index,data) ; } } } public void removeNode(Node previous,Book data) { if ( data.compare(this.data)) { previous.next = this.next ; } else { if ( this.next != null) { this.next.removeNode(this,data) ; } } } public void toArrayNode() { Link.this.retArray[Link.this.foot ++] = this.data ; if (this.next != null){ this.next.toArrayNode() ; } } } private Node root ; private int count = 0 ; private int foot = 0 ; private Book [] retArray ; public void add(Book data) { Node newNode = new Node(data) ; if ( root == null ) { root = newNode ; } else { this.root.addNode(newNode) ; } this.count ++ ; } public int size() { return count ; } public boolean isEmpty() { return this.count == 0 ; } public boolean contains( Book data ) { if ( data.compare(root.data) ) { return true ; } else { return this.root.containsNode(data) ; } } public Book get(int index) { if (index > count) { return null; } this.foot = 0 ; return this.root.getNode(index) ; } public void set(int index,Book data) { if ( index > count ) { return ; } this.foot = 0 ; this.root.setNode(index,data) ; } public void remove(Book data) { if ( data.compare(root.data) ) { root = root.next ; } else { this.root.removeNode(this.root,data) ; } count -- ; } public Book [] toArray() { this.foot = 0 ; this.retArray = new Book [this.count] ; this.root.toArrayNode() ; return retArray ; } } public class LinkBook { public static void main(String [] args) { Link all = new Link() ; all.add(new Book("Java開發",89.9)) ; all.add(new Book("JSP開發",78.9)) ; all.add(new Book("Web開發",68.9)) ; System.out.println(all.size()); System.out.println(all.contains(new Book("Java開發",89.9))); Book [] books = all.toArray() ; for ( int x = 0 ; x < books.length ; x ++ ) { System.out.println(books[x].getInfo()) ; } } }

class Province { //每一個類就相當於數據庫中的一個表; private int pid ; private String name ; private Link cities = new Link() ; //一對多 //setter getter 無參構造 略~ public Province(int pid , String name) { this.pid = pid ; this.name = name ; } public Link getCities() { return this.cities ; } public String getInfo() { return "省份編號:" + this.pid + ", 名稱:" + this.name ; } } class City { private int cid ; private String name ; private Province province ; //省份對象元素 public City(int cid , String name) { this.cid = cid ; this.name = name ; } public boolean compare(City data) { if ( this == data ) { return true ; } if ( data == null) { return false ; } if ( this.cid == data.cid && this.name.equals(data.name)) { return true ; } return false ; } public void setProvince(Province province) { this.province = province ; } public Province getProvince() { return this.province; } public String getInfo() { return "城市編號:" + this.cid + ", 名稱:" + this.name ; } } /* 每一個實例化的對象都是單獨的個體的存在,占用的是獨立的內存空間 所以每一個實例對象的操作不影響其它實例對象或者類的數據 */ class Link { class Node { private City data ; private Node next ; public Node(City data) { this.data = data; } public void addNode(Node newNode) { if ( this.next == null ) { this.next = newNode ; } else { this.next.addNode(newNode) ; } } public boolean containsNode(City data) { if ( data.compare(this.data)) { return true ; } else { if ( this.next != null ){ return this.next.containsNode(data) ; } else { return false ; } } } public City getNode(int index) { if ( Link.this.foot ++ == index ) { return this.data ; } else { return this.next.getNode(index) ; } } public void setNode(int index , City data) { if ( Link.this.foot ++ == index ) { this.data = data ; } else { this.next.setNode(index , data) ; } } public void removeNode(Node previous , City data) { if ( data.compare(this.data)){ previous.next = this.next ; //空掉當前(this)的節點 } else { if ( this.next != null ) { this.next.removeNode(this,data) ; } } } public void toArrayNode() { Link.this.cityArray[Link.this.foot ++ ] = this.data ; if ( this.next != null ) { this.next.toArrayNode() ; } } } private Node root ; private int count = 0 ; private int foot = 0 ; private City [] cityArray ; public void add(City data) { Node newNode = new Node(data) ; if ( this.root == null ) { this.root = newNode ; } else { this.root.addNode(newNode) ; } this.count ++ ; } public int size() { return this.count ; } public boolean isEmpty() { return count == 0 ; } public boolean contains(City data) { if ( data.compare(this.root.data) ) { //**-- return true ; } else { return this.root.containsNode(data) ; } } public City get(int index) { if ( index > count ){ return null; } this.foot = 0 ; return this.root.getNode(index) ; } public void set(int index , City data) { if ( index > count ){ return ; } this.foot = 0 ; this.root.setNode(index , data) ; } public void remove(City data) { if ( data.compare(this.root.data) ) { this.root = this.root.next ; } this.root.removeNode(this.root , data) ; this.count -- ; } public City [] toArray() { if ( this.root == null ) { return null ; } this.foot = 0 ; this.cityArray= new City[this.count] ; this.root.toArrayNode() ; return cityArray ; } } public class LinkPC { public static void main(String args[]) { // 設置關系數據 Province pro = new Province(1,"江蘇省") ; // 聲明Province類對象 City c1 = new City(1001,"南京市") ; City c2 = new City(1002,"蘇州市") ; City c3 = new City(1003,"宿遷市") ; // 什么多個City類對象 //設置關系 c1.setProvince(pro) ; // 利用City實例對象c1調用setProvince()方法並將pro對象傳遞 c2.setProvince(pro) ; // 這就是所謂的 "引用傳遞" c3.setProvince(pro) ; pro.getCities().add(c1) ; pro.getCities().add(c2) ; pro.getCities().add(c3) ; System.out.println(pro.getInfo()); System.out.println(pro.getCities().size()) ; City [] ci = pro.getCities().toArray() ; for ( int x = 0 ; x < ci.length ; x ++ ) { System.out.println(ci[x].getInfo()) ; } } }