Java 数据结构篇-模拟实现动态数组

博客主页: 小扳_-CSDN博客
❤感谢大家点赞收藏⭐评论✍
   

Java 数据结构篇-模拟实现动态数组_第1张图片

 

 

本篇目录

        1.0 动态数组说明

        2.0 模拟实现动态数组的核心方法

        2.1 动态数组-插入与扩容

        2.2 动态数组-获取元素

        2.3 动态数组-修改元素

        2.4 动态数组-删除元素

        2.5 动态数组-遍历元素(重点)

        2.5.1 使用 forEach 循环元素

        2.5.2 使用迭代器循环元素

        2.5.3  使用 Stream 流来循环元素

        2.6 补充关于拷贝的方法

        3.0 对以上代码进行汇总整理升级


        1.0 动态数组说明

        在 Java 中,动态数组可以使用 ArrayList 类来实现。ArrayList 类是 Java 集合框架中的一个类,它可以动态地增加或减少元素的大小。与普通数组相比,ArrayList 具有动态增长和缩小的能力,可以根据需要自动调整数组的大小。

        

        2.0 模拟实现动态数组的核心方法

        该动态数组中的成员变量分别为:Object[] myArrayList 数组int size 元素个数int defaultSize 默认大小。在 ArrayList 类中,在未添加元素之前为空,因此,Object[] myArrayList = {}size 默认为0;当第一个元素添加进来的时候,defaultSize 默认为10

具体代码如下:

public class ImitateArray implements Iterable{
    private int defaultSize = 10;
    private Object[] myArraylist= {};
    private int size = 0;

    //无参构造器
    public ImitateArray() {
    }

        2.1 动态数组-插入与扩容

        add(element): 向动态数组的末尾添加一个元素。如果数组已满,则需要扩容。

具体代码如下:

    public boolean add(E e){
        if (size == 0){
            myArraylist = new Object[defaultSize];
        }
        //先判断是否需要扩容
        if (isExpansion()) {
            expansion();
          }
        myArraylist[size] = e;
        size++;
        return true;
    }


    //是否需要扩容
    private boolean isExpansion(){
        return size >= defaultSize;
    }
    //数组扩容
    private boolean expansion(){
        defaultSize = (int) (defaultSize * 1.5);
        Object[] temp = new Object[(int) (defaultSize)];
        //for (int i = 0; i < myArraylist.length; i++) {
        //    temp[i] = myArraylist[i];
        //}
        System.arraycopy(myArraylist,0,temp,0,size);
        myArraylist = temp;
        System.out.println("扩容成功!");
        return true;
    }


        对以上代码进行分析:

        在添加元素前,

        第一,先判断是否首元素插入,如果是首元素,需要创建数组对象,默认大小为10

        第二,判断 size == defaultSize,如果是,就需要扩容了,数组扩容大小为原来的1.5倍defaultSize += defaultSize >>> 1,扩容成功之后,需要将原数组中的元素拷贝回到新数组中,可以用的方法为 System.arraycopy(myArraylist,0,temp,0,size);

        第三,添加完元素之后,需要进行 size++

        2.2 动态数组-获取元素

        get(index): 获取指定索引处的元素。

具体代码如下:

        

    public E get(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        return (E)myArraylist[index];
    }

        对以上代码进行分析:

        获取元素之前,先要判断是否越界访问数组。

        2.3 动态数组-修改元素

        set(index, element): 修改指定索引处的元素。

具体代码如下:

    public E set(int index,E e){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        E temp = (E) myArraylist[index];
        myArraylist[index] = e;
        return temp;
    }

        同理,在修改元素之前先要判断是否为越界访问。

        2.4 动态数组-删除元素

        remove(index): 删除指定索引处的元素。如果删除后数组的空余空间过多,则需要缩容。

具体代码如下:

    //根据索引删除数据
    public boolean remove(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        if (index == size - 1){
            myArraylist[index] = null;
        }else {
            //1,2,3,4,5
            //0,1,2,3,4
            for (int i = index; i < size; i++) {
                myArraylist[i] = myArraylist[i + 1];
            }
        }
        size--;
        return true;
    }

        对以上代码进行分析:
        先判断是否越界访问,再判断若要删除的元素为最后一个,则直接 null,接着 size--。其他情况需要缩容,myArraylist[i] = myArraylist[i + 1];

        2.5 动态数组-遍历元素(重点)

        介绍三种方式来遍历元素:

        第一种,实现使用 forEach 循环元素

        第二种,实现使用迭代器循环元素

        第三种,实现使用 Stream 流来循环元素

        2.5.1 使用 forEach 循环元素

具体代码如下:

public interface Consumer {
    void accept(E e);
}
    //实现forEach
    public void forEach(Consumer consumer) {
        Object[] temp = new Object[size];
        for (int i = 0; i < size; i++) {
            temp[i] = myArraylist[i];
        }
        for (Object o : temp) {
            consumer.accept((E)o);
        }

    }
        imitateArray.forEach(new Consumer() {
            @Override
            public void accept(Integer integer) {
                System.out.print(integer+" ");
            }
        });

        对以上代码进行分析:

        先实现一个接口,然后用 fori 循环,将有效元素都拷贝到新的数组中,接着用 foreach 循环来对每个元素进行操作,具体由用户决定了。 

        2.5.2 使用迭代器循环元素

具体代码如下:

首先需要实现 Iterable 接口;

Java 数据结构篇-模拟实现动态数组_第2张图片

    //重写迭代器
    @Override
    public Iterator iterator() {
        return new Iterator() {
            int i = 0;
            @Override
            public boolean hasNext() {
                return i < size;
            }

            @Override
            public E next() {
                return (E) myArraylist[i++];
            }
        };
    }
for (Integer integer : imitateArray) {
    System.out.print(integer+" ");
}

        补充;大部分的集合都实现该迭代器,因此不是所有类都具有迭代器的。

        2.5.3  使用 Stream 流来循环元素

具体代码如下:

    //用流进行遍历
    public Stream stream(){
        //第一种比较晦涩难懂
        //return Arrays.stream(Arrays.copyOf(myArraylist,size)).map(e->(E) e);
        
        //第二种比较好理解一点
        Stream stream1 = Stream.of(Arrays.copyOf(myArraylist,size));
        return stream1.map(e->(E) e);
    } 
   
      imitateArray.stream().forEach(s-> System.out.print(s+" "));
    

        重点注意:在 stream 方法中,使用 Stream.of((E) myArraylist) 来创建一个流,但是这样会将整个数组对象作为一个元素添加到流中,而不是将数组中的元素逐个添加到流中。

        因此,使用 map 方法来对流中的每个元素进行操作。在这里使用 lambda 表达式 (e -> (E) e) 来将每个元素 (e) 强制转换为 E 类型。这样就可以将流中的元素类型转换为 E 类型。

         2.6 补充关于拷贝的方法

        第一个,System.arraycopy(myArraylist,0,temp,0,size),用于一个或者两个数组,从 myArraylist 数组从第 0 个索引拷贝到 temp 数组中从第 0 个索引开始,一共要拷贝 size 个元素。

        第二个,Arrays.copyof(int[] original, int newlength),用于从原来的数组拷贝到新数组的个数为 newlength 个。

        第三个,Arrays.copyOfRange(int[] original, int from, int to) ,将指定数组的指定范围复制到新数组中。 

        3.0 对以上代码进行汇总整理升级

public interface Consumer {
    void accept(E e);
}

模拟实现 ArrayList 的代码:

import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;

public class ImitateArray implements Iterable{
    private int defaultSize = 10;
    private Object[] myArraylist= {};
    private int size = 0;

    public ImitateArray() {
    }
    //添加元素
    public boolean add(E e){
        if (size == 0){
            myArraylist = new Object[defaultSize];
        }
        //先判断是否需要扩容
        if (isExpansion()) {
            expansion();
          }
        myArraylist[size] = e;
        size++;
        return true;
    }

    //根据索引来查询数据
    public E get(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        return (E)myArraylist[index];
    }

    //根据索引删除数据
    public boolean remove(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        if (index == size - 1){
            myArraylist[index] = null;
        }else {
            //1,2,3,4,5
            //0,1,2,3,4
/*            for (int i = index; i < size; i++) {
                myArraylist[i] = myArraylist[i + 1];
            }*/
            System.arraycopy(myArraylist,index + 1,myArraylist,index,size - index -1);
        }
        size--;
        return true;
    }

    //根据索引来更改数据
    public E set(int index,E e){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        E temp = (E) myArraylist[index];
        myArraylist[index] = e;
        return temp;
    }

    //数组长度
    public int size(){
        return size;
    }

    //实现forEach
    public void forEach(Consumer consumer) {
        Object[] temp = new Object[size];
        for (int i = 0; i < size; i++) {
            temp[i] = myArraylist[i];
        }
        for (Object o : temp) {
            consumer.accept((E)o);
        }

    }

    //根据索引插入元素
    public boolean insert(int index,E e){
        if (index > size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        if (index == size){
            //直接调用 add 方法
            add(e);
        }
        if (isExpansion()){
            expansion();
        }
        //Object[] temp = new Object[defaultSize];
/*        for (int i = 0; i < index; i++) {
            temp[i] = myArraylist[i];
        }
        temp[index] = e;
        for (int i = index; i < size ; i++) {
            temp[i+1] = myArraylist[i];
        }*/
        System.arraycopy(myArraylist,index ,myArraylist,index + 1,size - index);
        myArraylist[index] = e;
        //myArraylist = temp;
        size++;
        return true;
    }

    //是否需要扩容
    private boolean isExpansion(){
        return size >= defaultSize;
    }
    //数组扩容
    private boolean expansion(){
        defaultSize = (int) (defaultSize * 1.5);
        Object[] temp = new Object[(int) (defaultSize)];
/*        for (int i = 0; i < myArraylist.length; i++) {
            temp[i] = myArraylist[i];
        }*/
        System.arraycopy(myArraylist,0,temp,0,size);
        myArraylist = temp;
        System.out.println("扩容成功!");
        return true;
    }
    //重写 toString 方法
    @Override
    public String toString() {
        Object[] temp = new Object[size];
        for (int i = 0; i < size; i++) {
            temp[i] = myArraylist[i];
        }
        return "ImitateArray{" +
                "myArraylist=" + Arrays.toString(temp) +
                '}';
    }

    //重写迭代器
    @Override
    public Iterator iterator() {
        return new Iterator() {
            int i = 0;
            @Override
            public boolean hasNext() {
                return i < size;
            }

            @Override
            public E next() {
                return (E) myArraylist[i++];
            }
        };
    }

    //用流进行遍历
    public Stream stream(){
        //第一种比较晦涩难懂
        //return Arrays.stream(Arrays.copyOf(myArraylist,size)).map(e->(E) e);

        //第二种比较好理解一点
        Stream stream1 = Stream.of(Arrays.copyOf(myArraylist,size));
        return stream1.map(e->(E) e);
    }
} 
   
  

以下为测试类: 

public class Text {
    public static void main(String[] args)  {
        ImitateArray imitateArray = new ImitateArray<>();
        imitateArray.add(1);
        imitateArray.add(2);
        imitateArray.add(3);
        imitateArray.add(4);
        imitateArray.add(5);
        imitateArray.add(6);
        imitateArray.add(7);
        imitateArray.add(8);
        imitateArray.add(9);
        imitateArray.add(10);
        imitateArray.add(11);
        imitateArray.add(12);
        System.out.println(imitateArray);

        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);

/*        ArrayList list = new ArrayList<>();
        list.forEach(new java.util.function.Consumer() {
            @Override
            public void accept(Integer integer) {

            }
        });*/

        imitateArray.forEach(new Consumer() {
            @Override
            public void accept(Integer integer) {
                System.out.print(integer+" ");
            }
        });
        System.out.println();

        for (Integer integer : imitateArray) {
            System.out.print(integer+" ");
        }

        System.out.println();
        imitateArray.stream().forEach(s-> System.out.print(s+" "));
    }
}

                

 

你可能感兴趣的:(java,数据结构,开发语言)