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;
}

01-java实现动态数组的更多相关文章

  1. 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解

    数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...

  2. [java笔记]动态数组

    private int count;//计数器 private int ary[] = new int [3]; if(count >= ary.length){ //数组动态扩展 int ne ...

  3. 常用数据结构-线性表及Java 动态数组 深究

    [Java心得总结六]Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式 1.动态数组 In compu ...

  4. Java动态数组

    其中java动态数组: Java动态数组是一种可以任意伸缩数组长度的对象,在Java中比较常用的是ArrayList,ArrayList是javaAPI中自带的java.util.ArrayList. ...

  5. JAVA数据结构--ArrayList动态数组

    在计算机科学中,动态数组,可扩展数组,可调整数组,动态表,可变数组或数组列表是一种随机存取可变大小列表数据结构,允许添加或删除元素.它提供许多现代主流编程语言的标准库.动态数组克服了静态数组的限制,静 ...

  6. java动态数组笔记

    动态数组: 在java.lang.reflect包下提供了Array类,包括一系列static方法,通过这些方法可动态的创建数组.给元素赋值.取出元素值等等 //理解数组引用——下面定义的objs数组 ...

  7. java——时间复杂度、动态数组

    O(n)不一定小于O(n^2),要具体来看,而我们说的这种时间复杂度其实是渐进时间复杂度,描述的是n趋近于无穷的情况. 动态数组的时间复杂度: 添加操作:O(n) addLast()的均摊复杂度为O( ...

  8. Java-Runoob-高级教程-实例-数组:01. Java 实例 – 数组排序及元素查找

    ylbtech-Java-Runoob-高级教程-实例-数组:01. Java 实例 – 数组排序及元素查找 1.返回顶部 1. Java 实例 - 数组排序及元素查找  Java 实例 以下实例演示 ...

  9. 纯数据结构Java实现(1/11)(动态数组)

    我怕说这部分内容太简单后,突然蹦出来一个大佬把我虐到哭,还是悠着点,踏实写 大致内容有: 增删改查,泛型支持,扩容支持,复杂度分析.(铺垫: Java语言中的数组) 基础铺垫 其实没啥好介绍的,顺序存 ...

  10. 三 基于Java动态数组手写队列

    手写队列: package dataStucture2.stackandqueue; import com.lt.datastructure.MaxHeap.Queue; import dataStu ...

随机推荐

  1. 【Python】抽象工厂模式

    前言 接着上一篇的故事工厂模式继续,手机要出厂,显然光一个手机肯定是不行的,还需要包装盒.充电器等等东西.我们按照上一篇提到的工厂模式,去建立新的工厂是一点都没有问题的.但是思考一下这样子做会带来的问 ...

  2. PHP 反序列化漏洞入门学习笔记

    参考文章: PHP反序列化漏洞入门 easy_serialize_php wp 实战经验丨PHP反序列化漏洞总结 PHP Session 序列化及反序列化处理器设置使用不当带来的安全隐患 利用 pha ...

  3. [Antd-vue] Warning: You cannot set a form field before rendering a field associated with the value.

    在用ant-design-vue的框架中,使用到了这种场景,就是点击编辑按钮,弹出modal模态框,渲染modal模态框中的form表单页面,并给表单赋值,但是在给表单赋值的时候,总是会报错. 错误提 ...

  4. python+requests实现接口自动化

    1. 前言 今年2月调去支持项目接口测试,测试过程中使用过postman.jmeter工具,基本能满足使用,但是部分情况下使用较为麻烦.比如:部分字段存在唯一性校验或字段间有业务性校验,每次请求均需手 ...

  5. web测试中不容忽视的细节

    最近在自动化测试的圈子里,我总是碰到很多人在群里和其他地方问为什么这个会出现错误? 为什么这个运行不了?为什么我百度了还是没用? 其实真正的原因可能是你忽略了下面这些需要注意的小地方: 1.页面分辨率 ...

  6. Elasticsearch源码解析:环境搭建

    在之前学习Redis的过程中,我就是一边通过文档/视频学习,一边阅读源码.我发现两种方法可以相辅相成,互相补充.阅读文档可以帮助我们快速了解某个功能,阅读源码有助于我们更深入的理解这一功能的实现及思想 ...

  7. 使用themeleaf,在JavaScript中使用for循环报错.....

    在for循环前加上/* <![CDATA[ */,在for循环后加/* ]]> */,这样就能正常解析了:如下 /* <![CDATA[ */ for (var i = 0; i & ...

  8. Docker 入门教程(2)——image与container

    image镜像 Definition of: image Docker images are the basis of containers. An Image is an ordered colle ...

  9. Statezhong shiyong redux props

    在构造方法中使用props给state赋值不允许, 原因需要检查

  10. Win10下ImageMagick及php-imageck扩展的安装

    安装ImageMagick https://imagemagick.org/script/download.php 选择符合自己电脑的版本进行安装即可.安装的时候注意勾选下面的选项自动加入环境变量,否 ...