<数据结构系列1>封装自己的数组——手写动态泛型数组(简化版ArrayList)
哈哈,距离上一次写博客已经快过去半个月了,这这这,好像有点慢啊,话不多说,开始我们的手写动态泛型数组
首先是我们自己写一个自己的动态数组类,代码如下所示:
public class Array<E> {
//成员变量:数据,大小
private E[] data;
private int size;
//构造函数,传入数组的容量capacity
public Array(int capacity) {
data=(E[])new Object[capacity];
size=0;
}
//无参构造函数,默认capacity=10
public Array() {
this(10);
}
//获取数组的容量
public int getCapacity() {
return data.length;
}
//获取数组中的元素个数
public int getSize() {
return this.size;
}
//返回数组是否为空
public boolean isEmpty() {
return size==0;
}
//在index索引的位置插入一个新元素e
public void add(int index,E e) {
if(index<0||index>size)
throw new IllegalArgumentException("Add faild.Require index >=0 and index <=size");
//IllegalArgumentException 非法数据异常
if(size==data.length)
resize(data.length*2);//动态扩大数组容量
for(int i=size-1;i>=index;i--) {
data[i+1]=data[i]; //插入的位置后的元素都应该向后移位
}
data[index]=e;
size++;
}
//向所有元素后添加一个新元素e
public void addLast(E e) {
add(size,e);
}
//在所有元素前添加一个新元素e
public void addFirst(E e) {
add(0,e);
}
//获取index索引位置的元素
public E get(int index) {
if(index<0||index>=size)
throw new IllegalArgumentException("Get faild.Index is illegal.");
return data[index];
}
//修改index索引位置的元素为e
public void set(int index,E e) {
if(index<0||index>=size)
throw new IllegalArgumentException("Set faild.Index is illegal.");
data[index]=e;
}
//查找数组中是否有元素e
public boolean contain(E e) {
for(int i=0;i<size;i++) {
if(data[i].equals(e))
return true;
}
return false;
}
//查找数组中元素e所在的索引,如果不存在元素e则返回-1
public int find(E e) {
for(int i=0;i<size;i++) {
if(data[i].equals(e))
return i;
}
return -1;
}
//从数组中删除index位置的元素,返回删除的元素
public E remove(int index) {
if(index<0||index>=size)
throw new IllegalArgumentException("Remove failed.Index is illegal.");
E ret =data[index]; //保存返回值
for(int i=index+1;i<size;i++) {
data[i-1]=data[i]; //将删除元素后的每个元素向前移动,覆盖住要被删除的元素
}
size--;
data[size]=null; //将最后的引用设为null,否则空间无法回收
if(size==data.length/4&&data.length/2!=0)//这里是当元素数量等于容量的1/4时,进行缩容操作
resize(data.length/2);
return ret;
}
//从数组中删除第一个元素,返回删除的元素
public E removeFirst() {
return remove(0);
}
//从数组中删除最后一个元素,返回删除的元素
public E removeLast() {
return remove(size-1);
}
//从数组中删除元素e
public void removeElement(E e) {
int index=this.find(e);
if(index!=-1)
remove(index);
}
//将数组空间的容量变为newCapacity
private void resize(int newCapacity) {
E[] newData= (E[])new Object[newCapacity];
for(int i=0;i<size;i++) {
newData[i]=data[i];
}
data=newData; //data指向newData
}
//重写tostring方法
@Override
public String toString() {
StringBuffer res=new StringBuffer();
res.append('[');
for(int i=0;i<size;i++) {
res.append(data[i]);
if(i!=size-1)
res.append(", ");
}
res.append(']');
return res.toString();
}
}
接着在写一个测试方法:
public class Main {
public static void main(String[] args) {
Array<Integer> arr=new Array<>();
for(int i=0;i<10;i++)
arr.addLast(i); //向数组尾部添加10个元素
System.out.println(arr);//打印
System.out.println("---------------------------");
arr.add(1, 100); //向下标为1的位置添加元素100
System.out.println(arr);
System.out.println("---------------------------");
arr.addFirst(-1); //向数组头部添加
System.out.println(arr);
System.out.println("---------------------------");
arr.remove(2); //删除下标2的元素
System.out.println(arr);
System.out.println("---------------------------");
arr.removeElement(4); //删除元素4
System.out.println(arr);
System.out.println("---------------------------");
arr.removeFirst(); //删除第一个元素
System.out.println(arr);
System.out.println("---------------------------");
for(int i = 0 ; i < 4 ; i ++){
arr.removeFirst();
System.out.println(arr);
}
}
}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
---------------------------
[0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
---------------------------
[-1, 0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
---------------------------
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
---------------------------
[-1, 0, 1, 2, 3, 5, 6, 7, 8, 9]
---------------------------
[0, 1, 2, 3, 5, 6, 7, 8, 9]
---------------------------
[1, 2, 3, 5, 6, 7, 8, 9]
[2, 3, 5, 6, 7, 8, 9]
[3, 5, 6, 7, 8, 9]
[5, 6, 7, 8, 9]
ok,这就完成了自己的动态泛型数组。
接下来分析一下时间复杂度:
//添加操作
addLast(e) O(1)
addFirst(e) O(n)
add(index,e) O(n/2)=O(n)
//删除操作
removeLast(e) O(1)
removeFirst(e) O(n)
remove(index,e) O(n/2)=O(n)
//修改操作
set(index,e) O(1)
//查找操作
get(index) O(1)
contains(e) O(n)
find(e) O(n) //总结
增:O(n) 存在resize O(n)
删:O(n) 存在resize O(n)
改:已知索引O(1);未知索引O(n)
查:已知索引O(1);未知索引O(n)
ok,今天的数据结构第一篇:封装自己的动态数组就写到这了,希望可以多多关注我接下来的博文哦
有啥问题可以直接在下方评论区留言,我已经开通了微信提醒,会第一时间回复的。
对于学习,四个字概括:至死方休!
<数据结构系列1>封装自己的数组——手写动态泛型数组(简化版ArrayList)的更多相关文章
- 三 基于Java动态数组手写队列
手写队列: package dataStucture2.stackandqueue; import com.lt.datastructure.MaxHeap.Queue; import dataStu ...
- 二 基于java动态数组手写栈
package dataStucture2.stack; import dataStucture2.array.MyDynamicArray; /** * 基于动态数组手写栈 * 设计时,栈中仅栈顶对 ...
- 三 基于Java数组手写循环队列
Code: package dataStucture2.stackandqueue; /** * 手写循环队列 * * @param <E> */ public class MyLoopQ ...
- 教你如何使用Java手写一个基于数组实现的队列
一.概述 队列,又称为伫列(queue),是先进先出(FIFO, First-In-First-Out)的线性表.在具体应用中通常用链表或者数组来实现.队列只允许在后端(称为rear)进行插入操作,在 ...
- 前端面试手写代码——JS数组去重
目录 1 测试用例 2 JS 数组去重4大类型 2.1 元素比较型 2.1.1 双层 for 循环逐一比较(es5常用) 2.1.2 排序相邻比较 2.2 查找元素位置型 2.2.1 indexOf ...
- 教你如何使用Java手写一个基于链表的队列
在上一篇博客[教你如何使用Java手写一个基于数组的队列]中已经介绍了队列,以及Java语言中对队列的实现,对队列不是很了解的可以我上一篇文章.那么,现在就直接进入主题吧. 这篇博客主要讲解的是如何使 ...
- No_1 手写Proxy
手写动态代理主要原理: userDAO=(UserDAO)Proxy.newProxyinstance(classloader,interfaces[],new MyInvocationHandler ...
- springmvc 动态代理 JDK实现与模拟JDK纯手写实现。
首先明白 动态代理和静态代理的区别: 静态代理:①持有被代理类的引用 ② 代理类一开始就被加载到内存中了(非常重要) 动态代理:JDK中的动态代理中的代理类是动态生成的.并且生成的动态代理类为$Pr ...
- 05-02 Java 一维数组、内存分配、数组操作
数组的定义 动态初始化 /* 数组:存储同一种数据类型的多个元素的容器. 定义格式: A:数据类型[] 数组名; B:数据类型 数组名[]; 举例: A:int[] a; 定义一个int类型的数组a变 ...
随机推荐
- 利用Intellij IDEA开发Spark程序
网上例子大多是基于scala的,并且配置基于sbt.scala的eclipse环境超级麻烦,所以下载IDEA. 准备:jdk,IDEA安装(可以不用事先安装sbt和Scala,这在IDEA里都可以pl ...
- 整合Yolov3到游戏引擎
这篇其实是前文 CUDA版Grabcut的实现 的后续,和上文一样,先放视频. (博客园好像不支持视频,gif文件太大,视频链接) 在上文用CUDA实现opencv下的grabcut后,当时问题主要是 ...
- 下拉控件jQuery插件
由于后端开发需要一个下拉控件,能输入,能选择,于是自己写了一个 ;(function($,window,document,undefined){ function Select(el,opt){ th ...
- Spring源码分析(一)基本介绍
摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 前言 作为一名开发人员,阅读源码是一个很好的学习方式.本文将结合< ...
- 1350: To Add Which? (优先队列+贪心 或者 数组模拟)
1350: To Add Which? Submit Page Summary Time Limit: 1 Sec Memory Limit: 128 Mb Submitt ...
- SEGGER RTT STOP/SLEEP 模式下使用
1.问题详述, M3/M4内核在sleep 或者 STOP模式 下,内核是不工作的,因此需要 以下 几步操作 第一步: 开启 低功耗模式下,debug 的连接 DBGMCU_Config(DBGMCU ...
- 提取win10默认锁屏壁纸
win10锁屏设置为windows聚焦时锁屏会有好看的图片出现.想让一张好看的图片一直使用,就去提取出来然后设置一下. 找到C盘:用户目录下 找到你的主机名文件夹: 在查看的选项栏中将隐藏文件夹显示: ...
- SharePoint自动初始化网站列表
1,由于目前的SharePoint网站需要部署到多个服务器上,每个网站的内容都不一样,所以使用备份还原是不可以的.常用的方式便是将列表导出为列表模版,然后将列表模版复制到服务器上,根据列表模版创建列表 ...
- expdp导出时报错ora-16000
一.问题现象:在对数据库进行expdp导出时发生报错ora-16000,脚本如下: nohup expdp "'/ as sysdba'" schemas=shp DIRECTOR ...
- win7-x64上MySql的初次安装
1.官网:https://dev.mysql.com/downloads/mysql/下载对应的zip包 2.将包解压缩到本地,如:F:\mysql\mysql-8.0.15-winx64 3.配置环 ...