順序表和鏈表之間的對比(含代碼)

順序表

  • 數據保存在連續的內存空間上
  • 支持隨機訪問
  • 擅長尾插和尾刪(O(1),如若觸發擴容邏輯 - > O(N)
  • 不擅長中間位置插入/刪除 O(N) ,效率低
public class SeqList {
    private int[] datas = new int[100]; //一個叫datas的內存有 100 的空間
    private int size = 0;  //把存在datas裏的叫size,期初是空的 ,所以 = 0

    public int getSize() {
        return size; 
        //這裏的size只能get,不能set,因爲size是通過之後順序表的增刪來修改的,所以這裏不能亂動
        //這個getSize的原因就是:上面的size是private,而下面這個代碼(display)我要使用它,
        // 因爲它是私有的所以我不能直接使用它,所以得用get這個方法
    }

    public void display() {
        //打印順序表
        //依次打印出來,打印就相當於數組裏的數組轉爲字符串
        //形如:[1,2,3,4,5]
        String ret = "[";
        for (int i = 0; i < size; i++) {
            ret += datas[i];
            if(i < size - 1){
                ret += ",";
            }
        }
        ret += "]";
        System.out.println(ret);
    }
    //這個方法呢就是爲了我之後寫的這些方法寫好之後,我要對他進行測試看他O不OK,方便把數組打印出來


    //在pos位置add data(此data,不是內存datas)
    //pos是我要插入的這個數的位置,也就是下標;
    //data是插入的這個數的值
    public void add(int pos, int data) {
        //首先要關注pos的有效性
        if(pos < 0 || pos > size){
            return;
        }

		//這個時候就需要擴容了
        if(size >= datas.length){  
            int[] newDatas = new int[datas.length * 2];   
            //一般擴容都是在原基礎上 * 2
            for (int i = 0; i < datas.length ; i++) {
                newDatas[i] = datas[i];
            }
            datas = newDatas;     
            //擴容後任然叫回原來的名字
        }
        
        //現在開始正式的add
        //1.尾插的情況
        if(pos == size){
            datas[pos] = data;
            size++;
            return;
        }
        //2.普通位置的插入
        //插入到pos後,pos後的數據依次向後移
        for (int i = size - 1;i >= pos;i--) {  
        //注意此處for循環的內部,順序表的後移,是從最後一個數開始的,記得畫圖
            datas[i + 1] = datas[i];
        }
        datas[pos] = data;
        size++;
    }
    public boolean contains(int toFind) {
        // 循環訪問每個元素並進行比較.
        // 如果發現某個元素和 toFind 相等, 就找到了, 返回 true
        // 如果所有元素都找完了, 也沒找到相等的, 就返回 false
        for (int i = 0; i < size; i++) {
            if (datas[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    public int search(int toFind) {  //某個元素的下標
        for (int i = 0; i < size; i++) {
            if(datas[i] == toFind){
                return i;
            }
        }
        return -1;
    }

    public int getPos(int pos) {  //某下標下的數的值
        return datas[pos];
    }


    public void setPos(int pos, int value) {   
    //給某下標的值賦一個值
        datas[pos] = value;
    }

    public void remove(int toRemove) {   
    //刪除第一次出現的值(也就是toRemove)
        int pos = search(toRemove);   //先找到要刪的這個值的下標
        if(pos == -1) {    //也就是沒找到,這點要是看不明白就返回search方法看
            return;
        }

        if(pos == size - 1){   //刪尾
            size--;
            return;
        }

        //普通刪去
        for(int i = pos;i < size - 1; i++) {  //從要刪的那個的後一個開始一個一個往前移
            datas[i] = datas[i + 1];
        }
        size--;
    }

    public void clear() {
        size = 0;
    }


}

鏈表

  • 元素之間不是在連續的內存空間上,給每個數據節點引入了一個next引用,通過這個引用就能找到當前節點的下一個節點
  • 不支持隨機訪問
  • 擅長中間插入元素/刪除元素 O(1),效率高
  • 存儲相同數量的數據時,鏈表佔用的內存空間比順序表大(因爲鏈表的每個節點還得維護一個next)
//一個節點
class Node {
    public int data;  //數據
    public Node next = null; //下一個節點的位置

    public Node(int data) {
        this.data = data;
    }
}

public class LinkedList {
    private Node head = null;  //頭節點,初始爲null,且這個鏈表沒有傀儡節點

    public void display() {
        for(Node cur = head; cur != null; cur = cur.next) {
            System.out.print(cur.data + " ");
        }
        System.out.println();
    }

    public void addFirst(int data) {
        //頭插法
        //1.根據data值,構建一個鏈表的節點(Node對象)
        //2.如果他是個空鏈表
        //3.不是空鏈表
        
        //1.
        Node node = new Node(data);
        //2.
        if (head == null) {
            head = node;
            return;
        }
        //3.
        node.next = head;
        head = node;
    }

    public void addLast(int data) {
        //尾插法
        Node node = new Node(data);
        if(head == null) {
            head = node;
            return;
        }
        //不是空鏈表的時候,先找出最後一個節點
        Node tail = head;
        while(tail.next != null) {
            tail = tail.next;
        }//循環結束就是最後一個節點
        tail.next = node;
        node.next = null;
    }
    private int getSize() {
        int size = 0;
        for (Node cur = head; cur != null; cur = cur.next){
            size++;
        }
        return size;
    }

    public boolean addIndex(int index,int data) {
        //index相當於順序表裏的pos,
        //index就相當於下標
        //1.先判斷index的有效性
        int size = getSize();
        if (index < 0 || index > size) {
            return false;
        }
        if (index == 0) {
            addFirst(data);
            return true;
        }
        if (index == size) {
            addLast(data);
            return true;
        }
        Node node = new Node(data);
        Node prev = getPos(index - 1);
        node.next = prev.next;
        prev.next = node; //這個地方順序不能錯了
        return true;

    }
    private Node getPos(int index) {//給定下標index,找到節點
        Node cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;//這步操作的提前必須得保證cur是非null
        }
        return cur;
    }
     public boolean contain(int key) {
        for (Node cur = head; cur != null;cur = cur.next) {
            if (cur.data == key) {
                return true;
            }
        }
        return false;
     }

     public void remove(int key) {
        //1.頭節點
         if (head.data == key) {
             head = head.next;
             return;
         }
         //2.不是頭節點,那就得找到該節點的前一個節點
         Node prev = searchPrev(key);
         Node toDelete = prev.next;
         prev.next = toDelete.next;
     }

     private Node searchPrev(int key) {//找key前一個節點
        for (Node cur = head; cur != null
                && cur.next != null;cur = cur.next) {
            if (cur.next.data == key) {
                return cur;
            }
        }
        return null;
     }

     public void removeAll(int key) {
        //1.先刪除非頭節點情況,需要找到key的前一個節點
         //2.刪除是頭節點的情況
         //1.
         Node prev = head;
         Node cur = head.next;
         while (cur != null) {
             if (cur.data == key) {
                 prev.next = cur.next;
                 cur = prev.next;
             }else {
                 //prev和cur同時往後移
                 prev = cur;
                 cur = cur.next;
             }
         }
         //2.頭結點情況
         if (head.data == key) {
             head = head.next;
         }
     }

     public void clear() {
        head = null;
     }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章