• 01-java实现动态数组


    01-手撸动态数组

    本篇是恋上数据结构第一季个人总结
    借鉴https://juejin.im/post/6844904001478066183#heading-0
    本人git https://github.com/bigeyes-debug/Algorithm

    一丶 数组

    数组是一种顺序存储的线性表,所有元素的内存地址是连续
    由于数组的内存连续性,数组默认情况下(指静态数组)是不会动态扩容的,而我们常常希望是数组是可以动态扩容的.

    二丶动态数组的设计

    2.1动态数组的属性

    • size是动态数组的大小,我们设置这个属性,可以通过返回动态数组的大小,获取当前动态数组元素的个数
    • elements 存储数据的数组(使用静态数组保存,动态扩充代码后面会提到)
    • DEFAULT_CAPACITY 指定默认的动态数组的默认数组大小
    • ELEMENT_NOT_FOUND 遍历循环查找元素的时候,如果找不到元素,就返回-1
        private int size;
        private E[] elements;
        private static final int DEFAULT_CAPACITY=10;
        private static final int ELEMENT_NOT_FOUND=-1;
    

    2.2 动态数组的接口

    // 元素的数量
    int size(); 
    // 是否为空
    boolean isEmpty();
    // 是否包含某个元素
    boolean contains(E element); 
    // 添加元素到最后面
    void add(E element); 
    // 返回index位置对应的元素
    E get(int index); 
    // 设置index位置的元素
    E set(int index, E element); 
    // 往index位置添加元素
    void add(int index, E element); 
    // 删除index位置对应的元素 
    E remove(int index); 
    // 查看元素的位置
    int indexOf(E element); 
    // 清除所有元素
    void clear(); 
    
    

    根据属性和接口,我们可以直接实现一些接口的方法.

    三丶动态数组的实现

    3.1 数组的数量

    size就是数组中元素的数量,调用size方法,直接返回数组中元素的数量

        public int size() {
            return size;
        }
    

    3.2 数组是否为空

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

    3.3 添加元素

    添加元素实现两个接口

    • public void add(E element) 只添加元素

    • public void add(int index,E element) 指定添加元素的位置)

    代码如下:

    public void add(int index, E element) {
        elements[index] = element;
        size++;
    }
    public void add(E element) {
            add(size,element);
        }
    

    但添加元素存在两种情况
    第一种情况:在最后一个元素的后面添加新元素
    第二种情况:将元素插入到某个位置(非最后面
    第一种情况不需要处理,第二种情况我们需要插入数据的位置后面的元素逐个向前移
    特别需要注意的是一定要从后往前移,如果从前往后,后面的元素会被覆盖

    考虑第二种情况之后,我们的add方法代码如下

        public void add(int index,E element) {
            for(int i=size;i>index;i--) {
                elements[i]=elements[i-1];
            }
            elements[index]=element;
            size++;
        }
    

    3.3.1数组越界

    如果add的index的值大于size,程序就会异常,index也应该大于,所以我们在此之前要加个判断

        private void rangeCheckForAdd(int index) {
            if(index<0||index>size) {
               outOfBounds(index);
            }
        public void add(int index,E element) {
           rngeCheckForAdd(index);
            for(int i=size;i>index;i--) {
                elements[i]=elements[i-1];
            }
            elements[index]=element;
            size++;
        }
    

    3.3.2数组扩容

    • 由于数组elements最大的容量只有10,所以当数组存满元素时,就需要对数组进行扩容。

    • 因为数组是无法动态扩容的,所以需要创建一个新的数组,这个数组的容量要比之前数组的容量大。

    • 然后在将原数组中的元素存放到新数组中,这样就实现了数组的扩容。

    private void ensureCapacity() {
        // 获取数组当前容量
        int oldCapacity = elements.length;
        // 如果 当前存储的元素个数 < 当前数组容量, 直接返回
        if (size < oldCapacity) return;
        // 新数组的容量为原数组容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 创建新数组
        E[] newElements = (E[]) new Object[newCapacity];
        // 原数组中的元素存储到新数组中
        for (int i = 0; i < size; i++) {
        	newElements[i] = elements[i];
        }
        // 引用新数组
        elements = newElements;
    }
         
    

       public void add(int index,E element) {
       // index应该0<index<size
            rangeCheckForAdd(index);
            // 动态扩容
             ensureCapacity(size+1);
             //数组元素前移
            for(int i=size;i>index;i--) {
                elements[i]=elements[i-1];
            }
            //插入元素
            elements[index]=element;
            //数组数量+1
            size++;
        }
    
    

    3.4 清空元素

    在java中,当对象没有指针指向时,就会自动被回收,所以我们只需要将数组的指向元素的指针设置为null,就可以了.

        public void clear() {
            for(int i=0;i<size;i++) {
                elements[i]=null;
            }
           size=0;
        }
    

    3.5删除元素

    删除元素的只需要将后面的元素往前移就可以,这里需要注意的是0<=index<size

        private void  outOfBounds(int index) {
            throw new IndexOutOfBoundsException("Index:"+index+",Size:" + size);
        }
        private void rangeCheck(int index) {
            if(index<0||index>=size) {
                outOfBounds(index);
            }
        }
    
        public E remove(int index) {
            rangeCheck(index);
            E old=elements[index];
            //后面的元素前移
            for(int i=index+1;i<size;i++) {
                elements[i-1]=elements[i];
            }
            //一定要先减再清空
            elements[--size]=null;
            return old;
        }
    

    为什么要--size?
    数组有5个元素.size为5,而第五个元素的下标是4
    所有需要先--然后再设置为null

    3.5修改元素

    只需找到指定下标,替换就可,同样要注意越界

    public E set(int index,E element) {
            rangeCheck(index);
            E old = elements[index];
            elements[index]=element;
            return old;
        }
    

    3.6查找元素

    查询元素,只需要将指定索引的元素返回,注意索引是否越界即可。

    public E get(int index) {
        rangeCheck(index);
        return elements[index];
    }
    
    

    3.7 查找元素位置

    查找元素存在两种情况,
    第一种情况,要查找的元素为null,
    第二种情况,要查找的元素不为null
    null.equals回报空指针异常
    我们分开进行处理,for循环遍历即可

        public int indexOf(E element) {
            if(element == null) {
                for(int i=0;i<size;i++) {
                    if(elements[i]==null) {
                        return i;
                    }
                }
            }
            else {
                for(int i=0;i<size;i++) {
                    if(element.equals(elements[i])) {
                        return i;
                    }
                }
            }  
            return ELEMENT_NOT_FOUND;
    
        }
    
    

    3.8 是否包含元素

        public boolean contains(E element) {
            return indexOf(element)!=ELEMENT_NOT_FOUND;
        }
    
  • 相关阅读:
    上海第八中学 shader
    http://www.riemers.net/
    手写板驱动
    使用dos 作为中介实现cpython 和c# 交互
    判断一个点是不是在三角形中 用面积算法
    Python os.chmod
    Python 的stat 模块
    文件格式说明
    win7 一切软件都安装不上 解决 把他卸掉
    执行力
  • 原文地址:https://www.cnblogs.com/bianzhuo/p/13412927.html
Copyright © 2020-2023  润新知