首页 > 其他分享 >3、动态数组

3、动态数组

时间:2023-04-10 13:55:10浏览次数:43  
标签:addLast 数组 基本操作 new 动态 public resize size

在这里,我们新创建一个数组类,对 Java 语言中的原始数组进行封装,使得它可以动态的扩容和缩容
Java 语言中也有类似的实现,叫 ArrayList,我们创建的数据类是它的简化版本,下面是代码实现

public class Array<E> {
    
    private E[] data;
    private int size;

    public Array(int capacity) {
        data = (E[]) new Object[capacity];
        size = 0;
    }

    public Array() {
        this(10);
    }

    public Array(E[] arr) {
        data = Arrays.copyOf(arr, arr.length);
        size = arr.length;
    }

    public int getSize() {
        return size;
    }
    
    public int getCapacity() {
        return data.length;
    }
    
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 添加
     */
    public void add(int index, E e) {
        if (index < 0 || index > size) throw new RuntimeException("need 0 <= index <= size");
        if (size == data.length) resize(data.length * 2);
        
        System.arraycopy(data, index, data, index + 1, size - index);
        data[index] = e;
        size++;
    }
    
    public void addFirst(E e) {
        add(0, e);
    }
    
    public void addLast(E e) {
        add(size, e);
    }

    /**
     * 删除
     */
    public E remove(int index) {
        if (index < 0 || index >= size) throw new RuntimeException("need 0 <= index < size");
        
        E ret = data[index];
        System.arraycopy(data, index + 1, data, index, size - index - 1);
        size--;
        data[size] = null;
        
        if (size == data.length / 4 && data.length / 2 != 0) resize(data.length / 2);
        return ret;
    }
    
    public E removeFirst() {
        return remove(0);
    }
    
    public E removeLast() {
        return remove(size - 1);
    }
    
    public void removeElement(E e) {
        int index = find(e);
        if (index != -1) remove(index);
    }

    /**
     * 修改
     */
    public void set(int index, E e) {
        if (index < 0 || index > size) throw new RuntimeException("need 0 <= index <= size");
        data[index] = e;
    }

    /**
     * 查看
     */
    public E get(int index) {
        if (index < 0 || index >= size) throw new RuntimeException("need 0 <= index < size");
        return data[index];
    }
    
    public E getFirst() {
        return get(0);
    }
    
    public E getLast() {
        return get(size - 1);
    }
    
    public boolean contains(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) return true;
        }
        return false;
    }
    
    public int find(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) return i;
        }
        return -1;
    }

    /**
     * 动态数组
     */
    private void resize(int newCapacity) {
        E[] newData = (E[]) new Object[newCapacity];
        System.arraycopy(data, 0, newData, 0, size);
        data = newData;
    }

    public void swap(int a, int b) {
        if (a < 0 || a >= size || b < 0 || b >= size) {
            throw new IllegalArgumentException("Swap failed, require 0 <= index < size");
        }
        E k = data[a];
        data[a] = data[b];
        data[b] = k;
    }

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

值得注意的是 resize 函数,resize 函数新创建了一个数组,并把原先数组里的元素挨个搬进新数组
乍一看 resize 函数的复杂度为 O(n),添加函数 add 和删除函数 remove 都会调用它,你可能会觉得我们的数据类性能极其低下
但事实上,添加函数 add 和删除函数 remove 并不是每次都会调用 resize 函数,我们来举一个列子
假设当前 capacity = 8,并且每一次添加操作都使用 addLast
我们进行 9 次 addLast 操作,只有在最后一次 addLast 操作时才会触发 resize(对前 8 次数据进行复制),总共进行了 8 + 1 + 8 = 17 次基本操作
9 次 addLast 操作,触发 resize,总共进行了 17 次基本操作,平均每次 addLast 操作,进行 2 次基本操作
假设 capacity = n,n + 1 次 addLast,触发 resize,总共进行 2n + 1 次基本操作,平均每次 addLast 操作,进行 2 次基本操作
这样均摊计算,时间复杂度是O(1)的!
在这个例子里,这样均摊计算,比计算最坏情况有意义

标签:addLast,数组,基本操作,new,动态,public,resize,size
From: https://www.cnblogs.com/n139949/p/17302701.html

相关文章

  • 用 Go 剑指 Offer 42. 连续子数组的最大和
    输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。 示例1:输入:nums=[-2,1,-3,4,-1,2,1,-5,4]输出:6解释: 连续子数组 [4,-1,2,1]的和最大,为 6。 提示:1<= arr.length<=10^5-100<=arr[i]<=100......
  • PYTHON 字节数组
    字节数组字节数组是可变类型,采用bytearray内置函数构造。在REPL中,输入help(bytearray)可以获得相关信息。字节数组的来源可以是:可迭代的整数序列,整数范围为0~255;字符串;字节或者另外的字节数组对象;任意实现了缓冲区API的对象。>>>×=bytearray('\×12\×34\×56\×78')>......
  • 动态权限批量申请
    @RequiresApi(api=Build.VERSION_CODES.M)@OverrideprotectedvoidonCreate(BundlesavedInstanceState){  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main)  PackageManagerpackageManager=this.getPackageManager();  P......
  • 【LeeCode】523.连续的子数组和
    【题目描述】给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:子数组大小 至少为2 ,且子数组元素总和为 k 的倍数。如果存在,返回 true ;否则,返回 false 。如果存在一个整数 n ,令整数 x 符合 x=n*k ,则称 x......
  • 数组排序
    1#include<stdio.h>2voidsort1(ints[])3{4inti,j,t;5for(i=0;i<9;i++)6{7for(j=0;j<10;j++)8{9if(s[j]>s[j+1])10{11t=s[j];s[j]=s[j+1];s[j+1]=t;1......
  • 线性表之静态链表实现(数组cur实现)
    main.cpp#include"StaticList.h"intmain(){StaticListSL;InitSList(SL);for(inti=0;i<5;++i){Insert(SL,'A'+i);}ShowSList(SL);DeleteSList(SL);ShowSList(SL);return0;}Stati......
  • gis经纬度坐标转换多格式兼容:支持字符串/数组/GeoJSON
    格式let coordinatesStrReg = /((-*[1][0-9]{0,2}|0)(\.[0-9]{1,6})*),\s{0,2}((-*[1-9][0-9]{0,1}|0)(\.[0-9]{1,6})*)/gstr.replace(coordinatesStrReg, (str, $1, $2, $3, $4, $5) => {  // lat=$1 lng lat=$4  console.log($1, $4)})代码,https://w......
  • C-指针数组与数组指针
    指针数组用于存放指针的数组inta=1,b=2,c=3;int*arr[3]={&a,&b,&c};//arr[0]==&a//*arr[0]==aint**p=arr;//*p==arr[0]==&a//p[0]==arr[0]==&a//*(p+1)==arr[1]==&b//**p==*arr[0]==a//*p[0]==*ar......
  • NOI / 1.8编程基础之多维数组 04:错误探测
    描述给定n*n由0和1组成的矩阵,如果矩阵的每一行和每一列的1的数量都是偶数,则认为符合条件。你的任务就是检测矩阵是否符合条件,或者在仅改变一个矩阵元素的情况下能否符合条件。"改变矩阵元素"的操作定义为0变成1或者1变成0。输入输入n+1行,第1行为矩阵的大小n(0<n<100),以......
  • 字符数组指针巩固学习
    1、字符数组的数组名存的就是字符数组的起始地址,类型是字符指针2、str系列字符串函数主要包括strlen,strcpy,strcmp,strcatstrlen:用于统计字符串长度strcpy:用于将某个字符串复制到字符数组中strcmp:用于比较两个字符串的大小,比较对应字符的ASCII码值strcat:用于将两个字符......