如今在進行面試的時候,不少公司都會要求你編寫數組排序,鏈表,二叉樹等,因此對於數據結構的掌握成爲面試的基本功,數據結構主要的核心組成:引用+遞歸。node
若是要想保存多個對象,咱們如今能想到的概念就只有對象數組,也就是說,若是該數組能夠保存任意對象,那麼又能夠想到Object型的數組:面試
Object data[]=new Object[3];設計模式
但在實際開發中,咱們就要面臨一些問題,數組的不足是長度固定的線性結構,雖然以上的代碼能夠存放多個內容,可是一旦咱們的內容不足或者是內容過多就會產生內存的浪費,若是此時要解決此類問題最好的辦法就是不定義一個長度固定的數組 有多少數據就保存多少數據,應該採用火車車箱的設計模式,動態的進行車箱的掛載,那麼假設每截車箱只保留一個數據,那麼如今假設能夠不受內存的限制,就能夠證實解決了數組長度的問題數組
1 class Node{ //由於只有Node類才能夠保存數據的同時設置數據的前後關係 2 private Object data;//真正保存的數據 3 private Node next;//定義下一個節點 4 public Node(Object data){//車箱裏面必定要去保存有數字 5 this.data=data; 6 } 7 public void setData(Object data){ 8 this.data=data; 9 } 10 public Object getData(){ 11 return this.data; 12 } 13 public void setNext(Node next){ 14 this.next=next; 15 } 16 public Node getNext(){ 17 return this.next; 18 } 19 } 20 public class Newbegin{ 21 public static void main(String args[]) throws Exception{ 22 //1.封裝幾個節點 23 Node root=new Node("火車頭");//如今假設存放的數是String 24 Node n1=new Node("車箱A"); 25 Node n2=new Node("車箱B"); 26 Node n3=new Node("車箱C"); 27 //2.須要設置節點關係 28 root.setNext(n1); 29 n1.setNext(n2); 30 n2.setNext(n3); 31 //3.輸出節點 32 print(root); 33 } 34 public static void print(Node node){ 35 if(node!=null){//表示當前存在有節點 36 System.out.println(node.getData()); 37 print(node.getNext()); 38 } 39 } 40 }
若是你要定義一個火車車箱你確定不可能保留一個數據,由於只須要另外一個指向,指向下一個節點,數據結構
在整個鏈表的實現過程之中Node類的核心做用:保存數據,鏈接節點關係,可是以上的代碼麻煩,發現客戶端(主方法)須要本身來進行節點的建立,所謂的鏈表就是須要一個單獨的類,假設:Link經過這個類實現Node類的數據保存以及關係處理。this
若是按照以上的方式來進行鏈表的實現,那咱們對開發者是很是痛苦,由於全部的使用者必須本身來處理數據的關係,因此爲了更好的處理應該追加一個程序類來完成,假設這個類叫作Link類spa
可是若是如今對於程序的初期結構採用以下的方式定義那麼也會出現問題。設計
1 class Link{ //負責鏈表的操做 2 //將Node定義爲內部類,表示Node類只爲Link類 3 private class Node{ //負責數據與節點關係的匹配 4 5 } 6 } 7 public class Newbegin{ 8 public static void main(String args[]) throws Exception{ 9 10 } 11 }
使用私有的內部類才能夠保證只有link類纔有權操做 Node類,並且使用了內部類以後還有一個最明顯的特色,內部類和外部類之間能夠方便的進行私有屬性的訪問,也就避免了seter和geter方法調用的尷尬, code
1 class Link{ //負責鏈表的操做 2 //將Node定義爲內部類,表示Node類只爲Link類 3 private class Node{ //負責數據與節點關係的匹配 4 private Object data;//保存節點的數據 5 private Node next;//保存下一個節點 6 public Node(Object data){ 7 this.data=data; 8 } 9 } 10 //----------------如下爲link類------------// 11 12 } 13 public class Newbegin{ 14 public static void main(String args[]) throws Exception{ 15 16 } 17 }
按照以上的模式能夠編寫代碼,可是對於鏈表的核心功能:增長,修改,刪除。判斷某一數據是否存在。對象
若是要想在鏈表之中實現一個數據的增長操做,則應該首先在鏈表裏面提供有一個 追加方法,而這個追加方法上的參數是Object類型,
1 public void add(Object data){ 2 if(data==null){//人爲的追加了規定,不容許存放空值 3 return ;//方法結束調用 4 } 5 }
2.那麼該如何進行數據的保存呢?應該首先定義一個根節點,才能夠添加後面的子節點,這個根節點的類型必定是Node。則應該在Link類裏面追加有一個Node類的屬性,
private Node root;//屬於根節點,沒有根節點就沒法進行數據的保存
1 class Link{ //負責鏈表的操做 2 //將Node定義爲內部類,表示Node類只爲Link類 3 private class Node{ //負責數據與節點關係的匹配 4 private Object data;//保存節點的數據 5 private Node next;//保存下一個節點 6 public Node(Object data){ 7 this.data=data; 8 } 9 //第1次調用:this=Link.root 10 //第2次調用:this=Link.root.next; 11 //第3次調用:this=Link.root.next; 12 public void addNode(Node newNode){//處理節點關係 13 if(this.next==null){//當前節點下一個爲空 14 this.next=newNode; 15 }else{//如今當前節點的下一個不爲空 16 this.next.addNode(newNode); 17 } 18 } 19 } 20 //----------------如下爲link類------------// 21 private Node root;//屬於根節點,沒有根節點就沒法進行數據的保存 22 public void add(Object data){ 23 if(data==null){//人爲的追加了規定,不容許存放空值 24 return ;//方法結束調用 25 } 26 //若是要想進行數據的保存,那麼就必須將數據封裝在Node節點類裏面 27 //若是沒有封裝,則沒法確認好節點的前後順序 28 Node newNode=new Node(data); 29 if(this.root==null){ //當前並無根節點 30 this.root=newNode;//第一個節點設置爲根節點 31 }else{ //根節點已經存在了 32 //應該把此時的節點順序的處理交給Node類本身完成 33 this.root.addNode(newNode); 34 } 35 } 36 } 37 public class Newbegin{ 38 public static void main(String args[]) throws Exception{ 39 Link all=new Link(); 40 all.add("hello"); 41 all.add("world"); 42 all.add("gl"); 43 } 44 }
Node的數據保存和節點關係的匹配
一個鏈表之中能夠保存多個元素數據,那麼爲了操做方便,就須要知道其一共保存的數據個數,全部須要有一個計數的統計操做
1.在Link類中追加一個統計個數的屬性
private int count=0;//當前的保存個數
2.隨後在每次進行數據追加的時候都應該進行一個個數的累加
1 public void add(Object data){ 2 if(data==null){//人爲的追加了規定,不容許存放空值 3 return ;//方法結束調用 4 } 5 //若是要想進行數據的保存,那麼就必須將數據封裝在Node節點類裏面 6 //若是沒有封裝,則沒法確認好節點的前後順序 7 Node newNode=new Node(data); 8 if(this.root==null){ //當前並無根節點 9 this.root=newNode;//第一個節點設置爲根節點 10 }else{ //根節點已經存在了 11 //應該把此時的節點順序的處理交給Node類本身完成 12 this.root.addNode(newNode); 13 } 14 count++; 15 }
3.能夠直接取得元素的個數
如今若是根元素爲null或者保存的元素個數爲0,則認爲鏈表是一個空的鏈表。則isEmpty()返回的就應該是true;
1 public boolean isEmpty(){ 2 return this.root==null&&this.count==0; 3 }
爲空判斷與個數能夠結合在一塊兒完成,不須要過多的複雜的操做邏輯,
首先鏈表是一個動態對象數組,那麼既然是動態對象數組,返回的內容也必定就應該是一個對象數組,可是若是要想進行數組的返回,首先必需要開闢一個數組(數組長度就是count屬性內容),同時這個的數組內容的填充應該依次將節點中的數據取出,才能夠正常完成,
1.在Link類中必定會存在有一個toArray()的方法,該方法的返回值必定是Object[]
2.全部在返回的對象數組中的數據都在Node類裏面,那麼就證實這些數據應該Node類中利用遞歸來依次取出那麼在外部類中Link中定義一個返回類型的屬性,
3.在Node類中處理節點數據
4.數據的存儲和返回是鏈表開發中使用最多的功能
1 class Link{ //負責鏈表的操做 2 //將Node定義爲內部類,表示Node類只爲Link類 3 private class Node{ //負責數據與節點關係的匹配 4 private Object data;//保存節點的數據 5 private Node next;//保存下一個節點 6 public Node(Object data){ 7 this.data=data; 8 } 9 //第1次調用:this=Link.root 10 //第2次調用:this=Link.root.next; 11 //第3次調用:this=Link.root.next; 12 public void addNode(Node newNode){//處理節點關係 13 if(this.next==null){//當前節點下一個爲空 14 this.next=newNode; 15 }else{//如今當前節點的下一個不爲空 16 this.next.addNode(newNode); 17 } 18 } 19 //第一次調用:this=Link.root 20 //第一次調用:this=Link.root.next 21 public void toArrayNode(){ 22 Link.this.retData[Link.this.foot++]=this.data; 23 if(this.next!=null){//如今還有下一個節點 24 this.next.toArrayNode(); 25 } 26 } 27 } 28 //----------------如下爲link類------------// 29 private Object[] retData;//返回類型 30 private int foot=0;//操做腳標 31 private int count=0;//當前的保存個數 32 private Node root;//屬於根節點,沒有根節點就沒法進行數據的保存 33 public void add(Object data){ 34 if(data==null){//人爲的追加了規定,不容許存放空值 35 return ;//方法結束調用 36 } 37 //若是要想進行數據的保存,那麼就必須將數據封裝在Node節點類裏面 38 //若是沒有封裝,則沒法確認好節點的前後順序 39 Node newNode=new Node(data); 40 if(this.root==null){ //當前並無根節點 41 this.root=newNode;//第一個節點設置爲根節點 42 }else{ //根節點已經存在了 43 //應該把此時的節點順序的處理交給Node類本身完成 44 this.root.addNode(newNode); 45 } 46 count++; 47 } 48 public int size(){//取得元素個數 49 return this.count; 50 } 51 public boolean isEmpty(){ 52 return this.root==null&&this.count==0; 53 } 54 public Object[] toArray(){ 55 if(this.count==0){ 56 return null; 57 } 58 //如今鏈表中存在有數據,則開闢指定長度的數組 59 //該數組必定要交給Node類進行處理 60 this.retData=new Object[this.count]; 61 this.foot=0;//進行清零的處理,須要進行腳標操做 62 this.root.toArrayNode();//將數據的取出處理交給Node類完成 63 return this.retData; 64 } 65 } 66 public class Newbegin{ 67 public static void main(String args[]) throws Exception{ 68 Link all=new Link(); 69 all.add("hello") ; 70 all.add("world"); 71 all.add("gl"); 72 Object result[]=all.toArray(); 73 for(int x=0;x<result.length;x++){ 74 System.out.println(result[x]); 75 } 76 } 77 }
在鏈表中存在不少數據,判斷數據是否存在鏈表之中,能夠利用contains()方法進行完成,
判斷的過程
1.判斷鏈表是否有數據,若是沒有數據不須要進行後續迭代
2.當咱們鏈表之中存在有數據以後,進行的數據的依次遞歸判斷,考慮到標準化問題,這個操做須要equals()方法支持。
1.在Node類裏面追加有一個containsNode()方法,用於數據查找遞歸
這個方法必定是由root這個對象首先調用
1 public boolean contains(Object search){ 2 //沒有要查詢的內容以及鏈表爲空 3 if(search==null||this.root==null){ 4 return false; 5 } 6 return this.root.containsNode(search); 7 }
查找操做須要使用equals()方法 若是是一個自定義的類則必定要覆寫equals()方法
取得指定索引數據:public Object get(int index)
鏈表屬於動態數組,數組應該有索引取得內容的形式
1.在Node內裏面追加一個新的方法,用於索引查找
1 public Object get(int index){ 2 if(index>=this.count){//超過了保存的個數 3 return null; 4 } 5 this.foot=0; 6 return this.root.getNode(index); 7 }
修改指定索引數據 public void set(int index,Object newData)
如今若是發現某些數據的保存有問題,則能夠根據索引進行修改處理操做,
1.Node 類裏面追加一個方法:setNode();
1 public void setNode(int index,Object newData){ 2 if(Link.this.foot++==index){//索引相同 3 this.data=newData; 4 return ;//結束 5 }else{ 6 if(this.next!=null){ 7 this.next.setNode(index,newData); 8 } 9 } 10 }
若是要想進行數據的刪除處理,則須要考慮兩種狀況,
狀況一:要刪除的是根節點
若是要刪除的是根節點,則意味着Link中的根節點的保存須要發生變化;
狀況二:刪除的不是根節點
全部的處理的操做應該交給Node來進行處理。
1 class Link{ //負責鏈表的操做 2 //將Node定義爲內部類,表示Node類只爲Link類 3 private class Node{ //負責數據與節點關係的匹配 4 private Object data;//保存節點的數據 5 private Node next;//保存下一個節點 6 public Node(Object data){ 7 this.data=data; 8 } 9 //第1次調用:this=Link.root 10 //第2次調用:this=Link.root.next; 11 //第3次調用:this=Link.root.next; 12 public void addNode(Node newNode){//處理節點關係 13 if(this.next==null){//當前節點下一個爲空 14 this.next=newNode; 15 }else{//如今當前節點的下一個不爲空 16 this.next.addNode(newNode); 17 } 18 } 19 //第一次調用:this=Link.root 20 //第一次調用:this=Link.root.next 21 public void toArrayNode(){ 22 Link.this.retData[Link.this.foot++]=this.data; 23 if(this.next!=null){//如今還有下一個節點 24 this.next.toArrayNode(); 25 } 26 } 27 //第一次調用:this=Link.root 28 //第一次調用:this=Link.root.next 29 public boolean containsNode(Object search){ 30 if(search.equals(this.data)){//找到了 31 return true; 32 }else{ 33 if(this.next!=null){//當前節點以後 34 return this.next.containsNode(search); 35 }else{//沒有節點 36 return false; 37 } 38 } 39 } 40 //第一次調用:this=Link.root 41 //第一次調用:this=Link.root.next 42 public Object getNode(int index){ 43 if(Link.this.foot++==index){ 44 return this.data; 45 }else{ 46 this.next.getNode(index); 47 } 48 return null; 49 } 50 public void setNode(int index,Object newData){ 51 if(Link.this.foot++==index){//索引相同 52 this.data=newData; 53 return ;//結束 54 }else{ 55 if(this.next!=null){ 56 this.next.setNode(index,newData); 57 } 58 } 59 } 60 //第一次調用:this=Link.root.next,previous=Link.root; 61 //第二次調用:this=Link.root.next.next,previous=Link.root.next; 62 public void removeNode(Node previous,Object data){ 63 if(this.data.equals(data)){//當前節點爲要刪除節點 64 previous.next=this.next;//刪除當前了 65 }else{ 66 this.next.removeNode(this,data); 67 } 68 } 69 } 70 //----------------如下爲link類------------// 71 private Object[] retData;//返回類型 72 private int foot=0;//操做腳標 73 private int count=0;//當前的保存個數 74 private Node root;//屬於根節點,沒有根節點就沒法進行數據的保存 75 public void add(Object data){ 76 if(data==null){//人爲的追加了規定,不容許存放空值 77 return ;//方法結束調用 78 } 79 //若是要想進行數據的保存,那麼就必須將數據封裝在Node節點類裏面 80 //若是沒有封裝,則沒法確認好節點的前後順序 81 Node newNode=new Node(data); 82 if(this.root==null){ //當前並無根節點 83 this.root=newNode;//第一個節點設置爲根節點 84 }else{ //根節點已經存在了 85 //應該把此時的節點順序的處理交給Node類本身完成 86 this.root.addNode(newNode); 87 } 88 count++; 89 } 90 public int size(){//取得元素個數 91 return this.count; 92 } 93 public boolean isEmpty(){ 94 return this.root==null&&this.count==0; 95 } 96 public boolean contains(Object search){ 97 //沒有要查詢的內容以及鏈表爲空 98 if(search==null||this.root==null){ 99 return false; 100 } 101 return this.root.containsNode(search); 102 } 103 public Object[] toArray(){ 104 if(this.count==0){ 105 return null; 106 } 107 //如今鏈表中存在有數據,則開闢指定長度的數組 108 //該數組必定要交給Node類進行處理 109 this.retData=new Object[this.count]; 110 this.foot=0;//進行清零的處理,須要進行腳標操做 111 this.root.toArrayNode();//將數據的取出處理交給Node類完成 112 return this.retData; 113 } 114 public void set(int index,Object newData){ 115 if(index>=this.count){//超過了保存的個數 116 return ;//結束方法調用 117 } 118 this.foot=0; 119 this.root.setNode(index,newData); 120 } 121 public Object get(int index){ 122 if(index>=this.count){//超過了保存的個數 123 return null; 124 } 125 this.foot=0; 126 return this.root.getNode(index); 127 } 128 public void remove(Object data){ 129 if(this.contains(data)){//若是該數據存在則進行刪除處理 130 //首先須要判斷要刪除的是否爲根節點數據 131 if(this.root.data.equals(data)){//首先須要判斷 132 this.root=this.root.next;//根節點變爲下一個節點 133 }else{//不是根節點 134 this.root.next.removeNode(this.root,data); 135 } 136 this.count--; 137 } 138 } 139 } 140 141 public class Newbegin{ 142 public static void main(String args[]) throws Exception{ 143 Link all=new Link(); 144 all.add("hello") ; 145 all.add("world"); 146 all.add("gl"); 147 all.set(1,"你好"); 148 all.remove("hello"); 149 all.remove("gl"); 150 Object result[]=all.toArray(); 151 for(int x=0;x<result.length;x++){ 152 System.out.println(result[x]); 153 } 154 // System.out.println("==========="); 155 // System.out.println(all.contains("hello")); 156 // System.out.println( all.contains("xxx")); 157 // System.out.println("==========="); 158 // System.out.println(all.get(0)); 159 // System.out.println(all.get(3)); 160 } 161 }