看了也不會系列-鏈表

數組

經過使用數組,能夠存儲一連串的數據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指向A4

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);
        //聲明一個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

總結

總的來講,數組和鏈表使用頻率都大,下面總結下各自的優勢和缺點

數組

優勢

查詢快,由於有下標

缺點
  • 插入和刪除須要移動大量元素
  • 容量固定,當容量不夠的時候,須要進行擴容

鏈表

優勢
  • 容量大,其大小和內存有關,由於節點都是不連續的
  • 插入和刪除方便

缺點

由於鏈表中的節點不是連續的,因此想要獲取某個元素的時候須要對鏈表進行遍歷和判斷

使用

須要常常添加和刪除元素時,用鏈表。元素不會常常變更,或者查詢頻率較高,用數組

相關文章
相關標籤/搜索