哈哈,距离上一次写博客已经快过去半个月了,这这这,好像有点慢啊,话不多说,开始我们的手写动态泛型数组

首先是我们自己写一个自己的动态数组类,代码如下所示:

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)的更多相关文章

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

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

  2. 二 基于java动态数组手写栈

    package dataStucture2.stack; import dataStucture2.array.MyDynamicArray; /** * 基于动态数组手写栈 * 设计时,栈中仅栈顶对 ...

  3. 三 基于Java数组手写循环队列

    Code: package dataStucture2.stackandqueue; /** * 手写循环队列 * * @param <E> */ public class MyLoopQ ...

  4. 教你如何使用Java手写一个基于数组实现的队列

    一.概述 队列,又称为伫列(queue),是先进先出(FIFO, First-In-First-Out)的线性表.在具体应用中通常用链表或者数组来实现.队列只允许在后端(称为rear)进行插入操作,在 ...

  5. 前端面试手写代码——JS数组去重

    目录 1 测试用例 2 JS 数组去重4大类型 2.1 元素比较型 2.1.1 双层 for 循环逐一比较(es5常用) 2.1.2 排序相邻比较 2.2 查找元素位置型 2.2.1 indexOf ...

  6. 教你如何使用Java手写一个基于链表的队列

    在上一篇博客[教你如何使用Java手写一个基于数组的队列]中已经介绍了队列,以及Java语言中对队列的实现,对队列不是很了解的可以我上一篇文章.那么,现在就直接进入主题吧. 这篇博客主要讲解的是如何使 ...

  7. No_1 手写Proxy

    手写动态代理主要原理: userDAO=(UserDAO)Proxy.newProxyinstance(classloader,interfaces[],new MyInvocationHandler ...

  8. springmvc 动态代理 JDK实现与模拟JDK纯手写实现。

    首先明白 动态代理和静态代理的区别: 静态代理:①持有被代理类的引用  ② 代理类一开始就被加载到内存中了(非常重要) 动态代理:JDK中的动态代理中的代理类是动态生成的.并且生成的动态代理类为$Pr ...

  9. 05-02 Java 一维数组、内存分配、数组操作

    数组的定义 动态初始化 /* 数组:存储同一种数据类型的多个元素的容器. 定义格式: A:数据类型[] 数组名; B:数据类型 数组名[]; 举例: A:int[] a; 定义一个int类型的数组a变 ...

随机推荐

  1. 一劳永逸部署项目:通过tomcat加载环境变量

    一劳永逸部署项目:通过tomcat加载环境变量 转载自:https://blog.csdn.net/u010414666/article/details/46499953 一.说明 项目中经常会用到x ...

  2. Java常用的快捷键

    // // (1)Ctrl+Space // 说明:内容助理.提供对方法,变量,参数,javadoc等得提示, // 应运在多种场合,总之需要提示的时候可先按此快捷键. // 注:避免输入法的切换设置 ...

  3. Python学习之路 (一)开发环境搭建

    前言 python3应该是Python的趋势所在,当然目前争议也比较大,这篇随笔的主要目的是记录在centos6.7下搭建python3环境的过程 以及碰到的问题和解决过程. 另外,如果本机安装了py ...

  4. Java泛型学习二

    通配符的使用 上一篇中知道,Box<Number>和Box<Integer>实际上都是Box类型,现在需要继续探讨一个问题,那么在逻辑上,类似于Box<Number> ...

  5. ios开发网络篇—HTTP协议 - 转

    一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ,通过1个URL,能找到互联网唯一的1个资源 ,URL就是资源的地址,位置,互联网上的每个资 ...

  6. pdf转中文txt

    最近项目需要实现根据关键字搜索pdf内容,实现思路就是提取pdf文本,然后进行索引. 工具上选择: IText 4.16之后采用agpl License,不能用作商用,而且转换中文会有乱码问题, pd ...

  7. spark 基础开发 Tips总结

    本篇博客主要是 sparksql 从初始开发注意的一些基本点以及力所能及的可优化部分的介绍: 所使用spark版本:2.0.0       scala版本:2.11.8 1. SparkSession ...

  8. Oracle Data Provider for .NET – Microsoft .NET Core and Entity Framework Core

    http://www.oracle.com/technetwork/topics/dotnet/tech-info/odpnet-dotnet-ef-core-sod-4395108.pdf Orac ...

  9. JavaWeb基础—JDBC(二)事务与批处理

    一.批处理 这里给出PrepareStatement的示例,优点是可以发送预编译的SQL,缺点是SQL语句无法更换,但参数可以更换 批处理:多条语句的处理 mysql默认是关闭的,要打开需要在url后 ...

  10. Hadoop namenode启动瓶颈分析

    NameNode启动过程详细剖析 NameNode中几个关键的数据结构 FSImage Namenode会将HDFS的文件和目录元数据存储在一个叫fsimage的二进制文件中,每次保存fsimage之 ...