數據結構與算法 | 線性表 —— 順序表

pexels-photo-577585

原文鏈接:wangwei.one/posts/java-…html

線性表

定義

將具備線性關係的數據存儲到計算機中所使用的存儲結構稱爲線性表。java

線性,是指數據在邏輯結構上具備線性關係。git

分類

邏輯結構上相鄰的數據在物理結構存儲分兩種形式:github

  • 數據在內存中集中存儲,採用順序表示結構,稱爲"順序存儲";
  • 數據在內存中分散存儲,採用鏈式表示結構,稱爲"鏈式存儲";

順序表

定義

邏輯上具備線性關係的數據按照先後的次序所有存儲在一整塊連續的內存空間中,之間不存在空隙,這樣的存儲結構稱爲順序存儲結構。算法

使用線性表的順序存儲結構生成的表,稱爲順序表。數組

實現

順序表的存放數據的特色和數組同樣,因此咱們這裏採用數組來實現,這裏咱們來用數組來簡單實現Java中經常使用的ArrayList。緩存

接口定義:數據結構

package one.wangwei.algorithms.datastructures.list;

/** * List Interface * * @param <T> * @author https://wangwei.one/ * @date 2018/04/27 */
public interface IList<T> {

    /** * add element * * @param element * @return */
    public boolean add(T element);

    /** * add element at index * * @param index * @param element * @return */
    public boolean add(int index, T element);

    /** * remove element * * @param element * @return */
    public boolean remove(T element);

    /** * remove element by index * * @param index * @return */
    public T remove(int index);

    /** * set element by index * * @param index * @param element * @return old element */
    public T set(int index, T element);

    /** * get element by index * * @param index * @return */
    public T get(int index);

    /** * clear list */
    public void clear();

    /** * contain certain element * * @param element * @return */
    public boolean contains(T element);

    /** * get list size * * @return */
    public int size();

}

複製代碼

源代碼ide

接口實現:post

package one.wangwei.algorithms.datastructures.list.impl;

import one.wangwei.algorithms.datastructures.list.IList;

import java.util.Arrays;

/** * Array List * * @param <T> * @author https://wangwei.one * @date 2018/04/27 */
public class MyArrayList<T> implements IList<T> {

    /** * default array size */
    private final int DEFAULT_SIZE = 10;

    /** * array size */
    private int size = 0;

    /** * array */
    private T[] array = (T[]) new Object[DEFAULT_SIZE];

    /** * add element * * @param element * @return */
    @Override
    public boolean add(T element) {
        return add(size, element);
    }

    /** * add element at index * * @param index * @param element * @return */
    @Override
    public boolean add(int index, T element) {
        if (index < 0 || index > size) {
            throw new ArrayIndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        // need grow
        if (size >= array.length) {
            grow();
        }
        // copy array element
        if (index < size) {
            System.arraycopy(array, index, array, index + 1, size - index);
        }
        array[index] = element;
        size++;
        return true;
    }

    /** * grow 50% */
    private void grow() {
        int growSize = size + (size >> 1);
        array = Arrays.copyOf(array, growSize);
    }

    /** * remove element * * @param element * @return */
    @Override
    public boolean remove(T element) {
        for (int i = 0; i < size; i++) {
            if (element == null) {
                if (array[i] == null) {
                    remove(i);
                    return true;
                }
            } else {
                if (array[i].equals(element)) {
                    remove(i);
                    return true;
                }
            }
        }
        return false;
    }

    /** * remove element by index * * @param index * @return */
    @Override
    public T remove(int index) {
        checkPositionIndex(index);
        T oldElement = array[index];
        // need copy element
        if (index != (size - 1)) {
            System.arraycopy(array, index + 1, array, index, size - index - 1);
        }
        --size;
        array[size] = null;
        // shrink 25%
        int shrinkSize = size - (size >> 2);
        if (shrinkSize >= DEFAULT_SIZE && shrinkSize > size) {
            shrink();
        }
        return oldElement;
    }

    /** * shrink 25% */
    private void shrink() {
        int shrinkSize = size - (size >> 2);
        array = Arrays.copyOf(array, shrinkSize);
    }

    /** * set element by index * * @param index * @param element * @return */
    @Override
    public T set(int index, T element) {
        checkPositionIndex(index);
        T oldElement = array[index];
        array[index] = element;
        return oldElement;
    }

    /** * get element by index * * @param index * @return */
    @Override
    public T get(int index) {
        checkPositionIndex(index);
        return array[index];
    }

    /** * check index * * @param index */
    private void checkPositionIndex(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
    }

    /** * clear list */
    @Override
    public void clear() {
        for (int i = 0; i < size; i++) {
            array[i] = null;
        }
        size = 0;
    }

    /** * contain certain element * * @param element */
    @Override
    public boolean contains(T element) {
        for (int i = 0; i < size; i++) {
            if (element == null) {
                if (array[i] == null) {
                    return true;
                }
            } else {
                if (array[i].equals(element)) {
                    return true;
                }
            }
        }
        return false;
    }

    /** * get list size * * @return */
    @Override
    public int size() {
        return size;
    }
}

複製代碼

源代碼

主要注意如下幾點:

  • 添加元素時 ,判斷是否須要對Array進行擴容;
  • 刪除元素時,判斷是否須要對Array進行收縮;
  • remove與contains接口,注意element爲null的狀況;

特色

  • 對數據進行遍歷的時候,數據在連續的物理空間中進行存放,CPU的內部緩存結構會緩存連續的內存片斷,能夠大幅下降讀取內存的性能開銷,因此查詢比較快;
  • 刪除線性表中的元素的時候,後面的元素會總體向前移動,因此刪除的效率較低,插入相似,時間複雜度爲O(n);

參考資料

相關文章
相關標籤/搜索