數據結構之動態數組列表List

學習了一段時間的Java,我們對Java的基本知識有了一定的瞭解,今天再來聊聊數組。

Java內置數組的特點

  • 數組的長度一旦確定則不可更改

  • 數組只能存儲同一類型的數據

  • 數組中每個存儲空間大小一致且地址連續

  • 數組提供角標的方式訪問元素

我們發現數組又有一些侷限性,於是在使用時又會有一些疑惑,我們可以總結一下
Java內置數組的潛在問題

容量不夠用時,怎麼辦?

指定位置插入或刪除元素,怎麼做?

數組對象只有length屬性,能滿足更多的需求嗎?

動態數組的封裝
有了問題,我們就有想法,嘗試用學過的知識來解決

能否用面向對象的思想,將數組進行再度封裝呢?

可以的,我們可以把數組的相關屬性和相關行爲封裝在類中

類似字符串String類,形成如下的調用形式

String s="HelloWorld";
s.charAt(1);
s.compareTo("Hello");
s.equals("Hello");
s.repalce('l','L');

數組對象.排序()

數組對象.插入(元素)

數組對象.查找(角標)

這樣大大方便了我們對數組的操作

那麼如何封裝動態數組
屬性方面:

  • int size 數組的有效元素個數
  • int capacity 數組的最大容量data.length
  • E[] data 數據的存儲容器

行爲方面:

  • 增()
  • 刪()
  • 改()
  • 查()
  • 其他()

爲什麼要強調動態數組
動態數組是順序存儲結構的具體實現!

1)線性表的定義

零個或多個數據元素的有限序列
在這裏插入圖片描述2)線性表接口List的定義

在這裏插入圖片描述
定義線性表的接口List
List支持泛型E
該List線性表中所存儲的具體數據類型由外界決定

public interface List<E> extends Iterable<E>{
    //獲取線性表中元素的有效個數
    int getSize();
    //判斷線性表是否爲空表
    boolean isEmpty();
    //在線性表指定的index角標處插入元素e
    void add(int index,E e);
    //在線性表的表頭處插入元素e
    void addFirst(E e);
    //在線性表的表位處插入元素e
    void addLast(E e);
    //獲取線性表中指定角標index處的元素
    E get(int index);
    //獲取表頭元素
    E getFirst();
    //獲取表尾元素
    E getLast();
    //修改線性表中指定角標index處的元素爲新元素e
    void set(int index,E e);
    //判斷線性表中是否包含元素e
    boolean contains(E e);
    //查找元素e的角標(從左到又默認第一個出現的元素角標)
    int find(E e);
    //刪除並返回線性表中指定角標index處的元素
    E remove(int index);
    //刪除並返回表頭元素
    E removeFirst();
    //刪除並返回表尾元素
    E removeLast();
    //刪除指定元素e
    void removeElement(E e);
    //清空線性表
    void clear();
}

創建線性表List的順序存儲結構實現類ArrayList

public class ArrayList<E> implements List<E>{
    //創建E類型的一維數組
    private E[] data;
    //維護元素個數
    private int size;
    //默認最大容量爲10
    private static int DEFAULT_CAPACITY=10;
    }

先創建一個順序表 ,重寫函數來獲取元素有效個數與判斷是否爲空

//創建一個默認大小的順序表
    public ArrayList(){
        this(DEFAULT_CAPACITY);
        //data=(E[])(new Object[DEFAULT_CAPACITY]);
    }

    //創建一個容量由用戶指定的順序表
    public ArrayList(int capacity){
        if(capacity<=0) {
            throw new IllegalArgumentException("容量>0:" + capacity);
        }
        data=(E[])(new Object[capacity]);
        size=0;
    }

    //用戶傳入一個數組 將該數組封裝成一個順序表
    public ArrayList(E[] data){
        if(data==null){
            throw new IllegalArgumentException("數組不能爲空");
        }
        this.data=(E[])(new Object[data.length]);
        for (int i = 0; i <data.length ; i++) {
            this.data[i]=data[i];
        }
        size=data.length;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

在指定角標插入元素時,如果數組已滿,則需要擴容

@Override
    public void add(int index, E e) {
        if(index<0||index>size){
            throw new IllegalArgumentException("角標越界");
        }
        if(size==data.length){
            //擴容
            resize(data.length*2);
        }
        for (int i = size; i >index ; i--) {
            data[i]=data[i-1];
        }
        data[index]=e;
        size++;
    }
	private void resize(int newLength) {
        E[] newData=(E[])(new Object[newLength]);
        for (int i = 0; i < size; i++) {
            newData[i]=data[i];
        }
        data=newData;
    }
    @Override
    public void addFirst(E e) {
        add(0,e);
    }

    @Override
    public void addLast(E e) {
        add(size,e);
    }

獲取指定元素位置

    @Override
    public E get(int index) {
        if(isEmpty()){
            throw new IllegalArgumentException("線性表爲空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角標越界");
        }
        return data[index];
    }

    @Override
    public E getFirst() {
        return get(0);
    }

    @Override
    public E getLast() {
        return get(size-1);
    }

修改線性表中指定角標index處的元素爲新元素e

    @Override
    public void set(int index, E e) {
        if(isEmpty()){
            throw new IllegalArgumentException("線性表爲空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角標越界");
        }
        data[index]=e;
    }

查找元素e的角標(從左到又默認第一個出現的元素角標)

    @Override
    public boolean contains(E e) {
        return find(e)!=-1;
    }

在數組中查找是否含有指定元素e

    @Override
    public int find(E e) {
        if(isEmpty()){
            throw new IllegalArgumentException("線性表爲空");
        }
        for (int i = 0; i < size; i++) {
            if(data[i].equals(e)){
                return i;
            }
        }
        return -1;
    }

刪除並返回線性表中指定角標index處的元素

    @Override
    public E remove(int index) {
        if(isEmpty()){
            throw new IllegalArgumentException("線性表爲空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角標越界");
        }
        E ret=data[index];
        for(int i=index+1;i<size;i++){
            data[i-1]=data[i];
        }
        size--;
        if(size<=data.length/4&&data.length/2>=10){
            resize(data.length/2);
        }
        return ret;
    }

    @Override
    public E removeFirst() {
        return remove(0);
    }

    @Override
    public E removeLast() {
        return remove(size-1);
    }

刪除指定元素e

    @Override
    public void removeElement(E e) {
        int index=find(e);
        if(index!=-1){
            remove(index);
        }else{
            throw new IllegalArgumentException("元素不存在");
        }
    }

清空線性表

    @Override
    public void clear() {
        size=0;
        data=(E[])(new Object[DEFAULT_CAPACITY]);
    }

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