經過使用數組,能夠存儲一連串的數據java
在java中,能夠存儲全部的基本類型以及對象類型。node
可是若是在代碼中,須要頻繁對數組中的元素進行添加和刪除,特別是從數組的頭部進行添加和刪除,就會有以下的問題:數組
//初始化一個數組
int[] a=new int[10];
a[0]=0;
a[1]=1;
a[2]=2;
//爲了方便,使用currentSize來表示數組實際使用了多少
index=3;
//從頭部插入一個元素-1,會使用以下方法
if(currentSize<10){
for(int i=currentSize;i>0;i--){
a[i]=a[i-1];
}
a[0]=-1;
}
//以上操做就是先把原先存在的數據日後移動,而後再插入頭部
//當從頭部刪除一個元素時,使用方法以下
if(currentSize>0){
for(int i=0;i<currentSize;i++){
a[i]=a[i+1];
}
}
//以上操做就是把後面的元素往前移動
複製代碼
從代碼能夠看出,對數組的插入和刪除操做麻煩,若是數組的容量很是大的話,那麼循環次數將很是多。編輯器
還有一個問題就是,當數組已存儲的元素個數達到初始化的容量,若要繼續添加元素,就須要對數組進行擴容。以下代碼工具
int[] a=new int[2];
a[0]=0;
a[1]=1;
//此時數組已經達到最大數量,須要進行擴容。
int[] b=new int[a.length*2];
for(int i=0;i<a.length;i++){
b[i]=a[i];
}
a=b;
//此時數組a的容量就擴大到原來的兩倍
複製代碼
爲了不使用數組帶來的插入和刪除的開銷,須要保證元素能夠不在內存地址上進行連續存儲,不然添加或刪除一個元素就可能須要總體移動。這是咱們就以使用鏈表來存儲數據。this
鏈表由一系列節點組成,這些節點在內存中不必定相連。在最簡單的鏈表中,每個節點均包含數據元素和該數據元素的後繼的指針,將其稱之爲next。最後一個元素的next指向null。spa
如圖: debug
代碼實現://鏈表節點實現
class Node {
//使用Object類型,讓節點可以保存任意類型的數據
private Object data;
private Node next;
public Node(Object data) {
this.data = data;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
//鏈表使用
public class Test {
public static void main(String[] args) {
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(null);
//這樣的鏈表就和數組 int[] a=new int[]{1,2,3}差很少,因爲node3的後繼不存在,因此node3指向null
}
}
複製代碼
咱們能夠經過intellij編輯器的斷點進行查看: 3d
關係就是node1->node2->node3->null指針
通常的,咱們會爲鏈表設置一個表頭,它不存儲數據,可是指向第一個元素
package list; class Node { //使用Object類型,讓節點可以保存任意類型的數據 private Object data; private Node next; public Node() { } public Node(Object data) { this.data = data; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } } public class Test { public static void main(String[] args) { //聲明表頭 Node head=new Node(); Node node1 = new Node(1); Node node2 = new Node(2); Node node3 = new Node(3); //直接指向node1,裏面沒有存儲數據 head.setNext(node1); node1.setNext(node2); node2.setNext(node3); node3.setNext(null); } } 複製代碼
鏈表的插入很簡單,好比要想n節點插入到s節點的後面,首先對鏈表進行遍歷,找到s節點後,先讓n.next=s.next,而後讓s.next=n
如圖,插入新節點A4,就是先讓A4指向A3,再讓A2指向A4public class Test {
public static void main(String[] args) {
Node head = new Node();
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
head.setNext(node1);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(null);
//聲明一個node4
Node node4 = new Node(4);
//要想獲得某個指定的節點,就得對鏈表進行遍歷,若是到了某個節點,其next指向爲null,說明整個鏈表都遍歷完畢,不存在指定的節點元素,全部可使用while循環進行遍歷
Node node = head;
while ((node = node.getNext()) != null) {
//等於2的時候,就是找到了節點node2
if (node.getData().equals(2)) {
//先讓新節點node4指向node2的下一節點,也就是node3
node4.setNext(node2.getNext());
//而後讓node2指向新節點node4
node2.setNext(node4);
//跳出循環
break;
}
}
}
}
複製代碼
使用debug工具進行查看:
刪除和插入相似,好比要想刪除節點n,首先對鏈表進行遍歷,找到s節點,知足s.next=n,而後讓s.next=n.next ,n.ndex=null,節點n會因爲虛擬機的垃圾回收機制被自動回收
public class Test {
public static void main(String[] args) {
Node head = new Node();
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
head.setNext(node1);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(null);
//要想獲得某個指定的節點,就得對鏈表進行遍歷,若是到了某個節點,其next指向爲null,說明整個鏈表都遍歷完畢,不存在指定的節點元素,全部可使用while循環進行遍歷
Node node = head;
while ((node = node.getNext()) != null) {
//節點的next.data等於2的時候,就找到了須要被刪除節點的前驅
if (node.getNext().getData().equals(2)) {
Node deleteNode = node.getNext();
//先讓前驅指向後繼
node.setNext(deleteNode.getNext());
//而後把刪除節點的後繼指向null
deleteNode.setNext(null);
//跳出循環
break;
}
}
}
}
複製代碼
debug查看
能夠看到,該鏈表中再也不包含2
總的來講,數組和鏈表使用頻率都大,下面總結下各自的優勢和缺點
查詢快,由於有下標
缺點
由於鏈表中的節點不是連續的,因此想要獲取某個元素的時候須要對鏈表進行遍歷和判斷
須要常常添加和刪除元素時,用鏈表。元素不會常常變更,或者查詢頻率較高,用數組