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

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

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. PHP设计模式系列 - 装饰器

    什么是装饰器 装饰器模式,对已有对象的部分内容或者功能进行调整,但是不需要修改原始对象结构,可以使用装饰器设 应用场景 设计一个UserInfo类,里面有UserInfo数组,用于存储用户名信息 通过 ...

  2. CR与LF

    CR与LF CR(carriage return),中文名称"回车":LF(line feed),中文名称"换行".无论是初学编程的小白还是入行十年的资深,总会 ...

  3. PHP常用符号和函数

    (转)最近在写PHP程序的时候发现了一些特殊的PHP符号,例如连续小于符号,三个小于符号,eot,eod,echo示例,print示例等,突然间 发现用这么久的PHP了,竟然连PHP的基本符号都没有认 ...

  4. 使用MS的ScriptDom来拆解TSQL脚本

    此处提供9.1.40413.0版本的DLL一共4个:Microsoft.Data.Schema.dll.Microsoft.Data.Schema.ScriptDom.dll.Microsoft.Da ...

  5. 使用 kubeadm 安装部署 kubernetes 1.9-部署heapster插件

    1.先到外网下载好镜像倒进各个节点 2.下载yaml文件和创建应用 mkdir -p ~/k8s/heapster cd ~/k8s/heapster wget https://raw.githubu ...

  6. python 爬虫 发送每天天气

    #!/usr/bin/python# -*- coding: UTF-8 -*-import requests,bs4,smtplib,sysimport smtplib, sysfrom email ...

  7. C#中的结构体与类的区别 (转载)

    经常听到有朋友在讨论C#中的结构与类有什么区别.正好这几日闲来无事,自己总结一下,希望大家指点. 1. 首先是语法定义上的区别啦,这个就不用多说了.定义类使用关键字class 定义结构使用关键字str ...

  8. 如何编写编译Robocup3D代码

    目录 开始编写球队代码 void NaoBehavior::beam() SkillType NaoBehavior::PlayOnSkill() 其他阶段函数 修复make异常 开始编写球队代码 装 ...

  9. vue实现首页导航切换不同路由的方式

    vue实现切换首页路由导航 ,根据切换的不同导航跳转不同的路由,以及当前选中的导航添加选中样式.  html代码: <nav> <!-- 导航栏 --> <div cla ...

  10. WPF实现斜纹圆角进度条样式

    原文:WPF实现斜纹圆角进度条样式 运行效果: 进度条样式: <!--进度条样式--> <LinearGradientBrush x:Key="ProgressBar.Pr ...