Array-數組-數據結構


數組

概述

把數據碼成一排進行存放

創建demo

新建項目

基礎講解

索引

索引可以有語意,也可以沒有語意。

簡而言之就是:數組當中的數據是否有語意。

比如:數組專門用來存放一類事物數據。一組成績、一組排名等等。。。

數組優點

查詢非常非常快(就是因為索引的存在)

二次封裝實現數組類

基本定義array類

public class Array {

    private int[] data;
    private int size;

    // 構造函數,傳入數組的容量capacity構造Array
    public Array(int capacity){
        data = new int[capacity];
        size = 0;
    }

    // 無參數的構造函數,默認數組的容量capacity=10
    public Array(){
        this(10);
    }

    // 獲取數組的容量
    public int getCapacity(){
        return data.length;
    }

    // 獲取數組中的元素個數
    public int getSize(){
        return size;
    }

    // 返回數組是否為空
    public boolean isEmpty(){
        return size == 0;
    }
}

添加元素

public class Array {

    private int[] data;
    private int size;

    // 構造函數,傳入數組的容量capacity構造Array
    public Array(int capacity){
        data = new int[capacity];
        size = 0;
    }

    // 無參數的構造函數,默認數組的容量capacity=10
    public Array(){
        this(10);
    }

    // 獲取數組的容量
    public int getCapacity(){
        return data.length;
    }

    // 獲取數組中的元素個數
    public int getSize(){
        return size;
    }

    // 返回數組是否為空
    public boolean isEmpty(){
        return size == 0;
    }

    // 向所有元素后添加一個新元素
    public void addLast(int e){

//        if(size == data.length)
//            throw new IllegalArgumentException("AddLast failed. Array is full.");
//
//        data[size] = e;
//        size ++;
        add(size, e);
    }

    // 在所有元素前添加一個新元素
    public void addFirst(int e){
        add(0, e);
    }

    // 在index索引的位置插入一個新元素e
    public void add(int index, int e){

        if(size == data.length)
            throw new IllegalArgumentException("Add failed. Array is full.");

        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

}

解讀:

// 在哪個位置插入數后,往后的數都要往后移動一位。
    // 在index索引的位置插入一個新元素e
    public void add(int index, int e){
       
        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

代碼 功能
int i = size - 1; 最后一個數的索引開始,往index索引的位置開始計算
i >= index ; 總共要循環 size-1-index 次
i -- 每次循環(size-1)-1
data[i + 1] = data[i]; 每個數都往后挪一位data[size] = data[size-1];
size ++; 維護size++

查詢元素和修改元素

public class Array {

    private int[] data;
    private int size;

    // 構造函數,傳入數組的容量capacity構造Array
    public Array(int capacity){
        data = new int[capacity];
        size = 0;
    }

    // 無參數的構造函數,默認數組的容量capacity=10
    public Array(){
        this(10);
    }

    // 獲取數組的容量
    public int getCapacity(){
        return data.length;
    }

    // 獲取數組中的元素個數
    public int getSize(){
        return size;
    }

    // 返回數組是否為空
    public boolean isEmpty(){
        return size == 0;
    }

    // 向所有元素后添加一個新元素
    public void addLast(int e){
        add(size, e);
    }

    // 在所有元素前添加一個新元素
    public void addFirst(int e){
        add(0, e);
    }

    // 在index索引的位置插入一個新元素e
    public void add(int index, int e){

        if(size == data.length)
            throw new IllegalArgumentException("Add failed. Array is full.");

        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

    // 獲取index索引位置的元素
    public int get(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Get failed. Index is illegal.");
        return data[index];
    }

    // 修改index索引位置的元素為e
    public void set(int index, int e){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Set failed. Index is illegal.");
        data[index] = e;
    }

    @Override
    public String toString(){

        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
        res.append('[');
        for(int i = 0 ; i < size ; i ++){
            res.append(data[i]);
            if(i != size - 1)
                res.append(", ");
        }
        res.append(']');
        return res.toString();
    }
}

查詢有什么元素:

重寫toString方法

    @Override
    public String toString(){

        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
        res.append('[');
        for(int i = 0 ; i < size ; i ++){
            res.append(data[i]);
            if(i != size - 1)
                res.append(", ");
        }
        res.append(']');
        return res.toString();
    }

獲取元素和修改元素:

    // 獲取index索引位置的元素
    public int get(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Get failed. Index is illegal.");
        return data[index];
    }

    // 修改index索引位置的元素為e
    public void set(int index, int e){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Set failed. Index is illegal.");
        data[index] = e;
    }

包含,搜索和刪除元素

public class Array {

    private int[] data;
    private int size;

    // 構造函數,傳入數組的容量capacity構造Array
    public Array(int capacity){
        data = new int[capacity];
        size = 0;
    }

    // 無參數的構造函數,默認數組的容量capacity=10
    public Array(){
        this(10);
    }

    // 獲取數組的容量
    public int getCapacity(){
        return data.length;
    }

    // 獲取數組中的元素個數
    public int getSize(){
        return size;
    }

    // 返回數組是否為空
    public boolean isEmpty(){
        return size == 0;
    }

    // 向所有元素后添加一個新元素
    public void addLast(int e){
        add(size, e);
    }

    // 在所有元素前添加一個新元素
    public void addFirst(int e){
        add(0, e);
    }

    // 在index索引的位置插入一個新元素e
    public void add(int index, int e){

        if(size == data.length)
            throw new IllegalArgumentException("Add failed. Array is full.");

        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

    // 獲取index索引位置的元素
    public int get(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Get failed. Index is illegal.");
        return data[index];
    }

    // 修改index索引位置的元素為e
    public void set(int index, int e){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Set failed. Index is illegal.");
        data[index] = e;
    }

    // 查找數組中是否有元素e
    public boolean contains(int e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i] == e)
                return true;
        }
        return false;
    }

    // 查找數組中元素e所在的索引,如果不存在元素e,則返回-1
    public int find(int e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i] == e)
                return i;
        }
        return -1;
    }

    // 從數組中刪除index位置的元素, 返回刪除的元素
    public int remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        int ret = data[index];
        for(int i = index + 1 ; i < size ; i ++)
            data[i - 1] = data[i];
        size --;
        return ret;
    }

    // 從數組中刪除第一個元素, 返回刪除的元素
    public int removeFirst(){
        return remove(0);
    }

    // 從數組中刪除最后一個元素, 返回刪除的元素
    public int removeLast(){
        return remove(size - 1);
    }

    // 從數組中刪除元素e
    public void removeElement(int e){
        int index = find(e);
        if(index != -1)
            remove(index);
    }

    @Override
    public String toString(){

        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
        res.append('[');
        for(int i = 0 ; i < size ; i ++){
            res.append(data[i]);
            if(i != size - 1)
                res.append(", ");
        }
        res.append(']');
        return res.toString();
    }
}

查看是否包含元素:

    // 查找數組中是否有元素e
    public boolean contains(int e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i] == e)
                return true;
        }
        return false;
    }

搜索元素:

    // 查找數組中元素e所在的索引,如果不存在元素e,則返回-1
    public int find(int e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i] == e)
                return i;
        }
        return -1;
    }

刪除元素:

    // 從數組中刪除index位置的元素, 返回刪除的元素
    public int remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        int ret = data[index];
        for(int i = index + 1 ; i < size ; i ++)
            data[i - 1] = data[i];
        size --;
        return ret;
    }

解讀:

代碼 功能
int ret = data[index]; java自帶數組取出index的值
int i = index + 1 ;i < size ; 88到100區間都要往前移動一位
i < size ; size = 5;
i ++ (index+1)+1
data[i - 1] = data[i]; index+1的數賦值給index
size --; 循環完以后size--

使用泛型

讓我們的數據結構可以放置“任何”數據類型

不可以是基本數據類型(8種),只能是類對象。可以放置爆裝備。

public class Array<E> {

    private E[] data;
    private int size;

    // 構造函數,傳入數組的容量capacity構造Array
    public Array(int capacity){
        data = (E[])new Object[capacity];
        size = 0;
    }

    // 無參數的構造函數,默認數組的容量capacity=10
    public Array(){
        this(10);
    }

    // 獲取數組的容量
    public int getCapacity(){
        return data.length;
    }

    // 獲取數組中的元素個數
    public int getSize(){
        return size;
    }

    // 返回數組是否為空
    public boolean isEmpty(){
        return size == 0;
    }

    // 在index索引的位置插入一個新元素e
    public void add(int index, E e){

        if(size == data.length)
            throw new IllegalArgumentException("Add failed. Array is full.");

        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

    // 向所有元素后添加一個新元素
    public void addLast(E e){
        add(size, e);
    }

    // 在所有元素前添加一個新元素
    public void addFirst(E e){
        add(0, e);
    }

    // 獲取index索引位置的元素
    public E get(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Get failed. Index is illegal.");
        return data[index];
    }

    // 修改index索引位置的元素為e
    public void set(int index, E e){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Set failed. Index is illegal.");
        data[index] = e;
    }

    // 查找數組中是否有元素e
    public boolean contains(E e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i].equals(e))
                return true;
        }
        return false;
    }

    // 查找數組中元素e所在的索引,如果不存在元素e,則返回-1
    public int find(E e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i].equals(e))
                return i;
        }
        return -1;
    }

    // 從數組中刪除index位置的元素, 返回刪除的元素
    public E remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        E ret = data[index];
        for(int i = index + 1 ; i < size ; i ++)
            data[i - 1] = data[i];
        size --;
        data[size] = null; // loitering objects != memory leak
        return ret;
    }

    // 從數組中刪除第一個元素, 返回刪除的元素
    public E removeFirst(){
        return remove(0);
    }

    // 從數組中刪除最后一個元素, 返回刪除的元素
    public E removeLast(){
        return remove(size - 1);
    }

    // 從數組中刪除元素e
    public void removeElement(E e){
        int index = find(e);
        if(index != -1)
            remove(index);
    }

    @Override
    public String toString(){

        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
        res.append('[');
        for(int i = 0 ; i < size ; i ++){
            res.append(data[i]);
            if(i != size - 1)
                res.append(", ");
        }
        res.append(']');
        return res.toString();
    }
}

將原先的只支持int數組改成可支持任何數據類型。

泛型的使用:

代碼 功能
Array E的名字可以任意取名,規范就用E,element的意思
data[i].equals(e) 之前是==比較值,因為對象比較用equals

動態數組

數組容量大小一旦確定不可更改。

可以擴容,是創建一個新的數組,把之前數組的數據循環遍歷給新的數組。

指向新的數組

newdata在我們函數執行完成之后就失效了。

public class Array<E> {

    private E[] data;
    private int size;

    // 構造函數,傳入數組的容量capacity構造Array
    public Array(int capacity){
        data = (E[])new Object[capacity];
        size = 0;
    }

    // 無參數的構造函數,默認數組的容量capacity=10
    public Array(){
        this(10);
    }

    // 獲取數組的容量
    public int getCapacity(){
        return data.length;
    }

    // 獲取數組中的元素個數
    public int getSize(){
        return size;
    }

    // 返回數組是否為空
    public boolean isEmpty(){
        return size == 0;
    }

    // 在index索引的位置插入一個新元素e
    public void add(int index, E e){

        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        if(size == data.length)
            resize(2 * data.length);

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

    // 向所有元素后添加一個新元素
    public void addLast(E e){
        add(size, e);
    }

    // 在所有元素前添加一個新元素
    public void addFirst(E e){
        add(0, e);
    }

    // 獲取index索引位置的元素
    public E get(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Get failed. Index is illegal.");
        return data[index];
    }

    // 修改index索引位置的元素為e
    public void set(int index, E e){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Set failed. Index is illegal.");
        data[index] = e;
    }

    // 查找數組中是否有元素e
    public boolean contains(E e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i].equals(e))
                return true;
        }
        return false;
    }

    // 查找數組中元素e所在的索引,如果不存在元素e,則返回-1
    public int find(E e){
        for(int i = 0 ; i < size ; i ++){
            if(data[i].equals(e))
                return i;
        }
        return -1;
    }

    // 從數組中刪除index位置的元素, 返回刪除的元素
    public E remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        E ret = data[index];
        for(int i = index + 1 ; i < size ; i ++)
            data[i - 1] = data[i];
        size --;
        data[size] = null; // loitering objects != memory leak

        if(size == data.length / 2)
            resize(data.length / 2);
        return ret;
    }

    // 從數組中刪除第一個元素, 返回刪除的元素
    public E removeFirst(){
        return remove(0);
    }

    // 從數組中刪除最后一個元素, 返回刪除的元素
    public E removeLast(){
        return remove(size - 1);
    }

    // 從數組中刪除元素e
    public void removeElement(E e){
        int index = find(e);
        if(index != -1)
            remove(index);
    }

    @Override
    public String toString(){

        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
        res.append('[');
        for(int i = 0 ; i < size ; i ++){
            res.append(data[i]);
            if(i != size - 1)
                res.append(", ");
        }
        res.append(']');
        return res.toString();
    }

    // 將數組空間的容量變成newCapacity大小
    private void resize(int newCapacity){

        E[] newData = (E[])new Object[newCapacity];
        for(int i = 0 ; i < size ; i ++)
            newData[i] = data[i];
        data = newData;
    }
}

解讀:

    // 在index索引的位置插入一個新元素e
    public void add(int index, E e){

        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        if(size == data.length)
            resize(2 * data.length);

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }  
    // 從數組中刪除index位置的元素, 返回刪除的元素
    public E remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        E ret = data[index];
        for(int i = index + 1 ; i < size ; i ++)
            data[i - 1] = data[i];
        size --;
        data[size] = null; // loitering objects != memory leak

        if(size == data.length / 2)
            resize(data.length / 2);
        return ret;
    }

// 將數組空間的容量變成newCapacity大小
    private void resize(int newCapacity){

        E[] newData = (E[])new Object[newCapacity];
        for(int i = 0 ; i < size ; i ++)
            newData[i] = data[i];
        data = newData;
    }
代碼 功能
newData[i] = data[i]; 將data[]里的內容轉給newData[]
data = newData; 將data指向newData

簡單的時間復雜度分析

用來分析性能。

想深入理解涉及很多數學中的概念。

算法(函數)和n成線性關系。正比例關系。

忽略常數:

實際時間:T = c1*n + c2

c1、c2都是常數。

c1 :函數中變量被各種操作的頻數,相當於走的路程。

O1 復雜度:在常數時間內直接可以完成的。

同理可得:

總結:

因為resize的存在,動態擴容。所以也是O(n)

resize的復雜度分析

需要擴容(縮容)是因為容量不夠(夠)了。

從這意義上講resize的復雜度是O(n)級別的。

但是很多時候是不需要擴容(縮容)的。反而變成了O(1)級別的。

通過以上的理解:最壞的情況不是每次都會出現。所以出現均攤復雜度。

均攤復雜度

最壞的情況不是每次都會出現

是一個好的思想。

但是如果壞的情況頻繁出現(照樣還是O(n)級別的。)。就會引發復雜度震盪的問題

復雜度震盪

最壞的情況頻繁出現

出現的原因:removeLast時resize過於着急(Eager:着急)

解決方案:

使用更加懶惰的一種方式:Lazy

當我們需要縮容的時候,不要讓他立刻就縮容。而是等到容器達到4/1(自定義的值)的時候再進行縮容。

代碼修改:

    // 從數組中刪除index位置的元素, 返回刪除的元素
    public E remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        E ret = data[index];
        for(int i = index + 1 ; i < size ; i ++)
            data[i - 1] = data[i];
        size --;
        data[size] = null; // loitering objects != memory leak

        if(size == data.length / 4 && data.length / 2 != 0)
            resize(data.length / 2);
        return ret;
    }
代碼 功能
if(size == data.length / 4 && data.length / 2 != 0) 條件限制,防止出現數組縮到0的時候。數組大小不可為0
resize(data.length / 2); 到達指定值的時候進行縮容


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM