<数据结构系列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变 ...
随机推荐
- ansible.md
ansible 测试环境配置 注意:192.168.100.201这台机器是主控机,剩下的192.168.100.202.192.168.100.203.192.168.100.210均为测试主机. ...
- eclipse异常关闭,无法启动tomcat解决办法
如果eclipse异常关闭,会出现以下 此时需要关闭javaw.exe即可,重新启动tomcat了. 关闭javaw.exe需要打开任务关闭器,选择详细信息,然后结束javaw.exe即可
- 【openjudge】【字符串】P6374文字排版
[描述] 给一段英文短文,单词之间以空格分隔(每个单词包括其前后紧邻的标点符号).请将短文重新排版,要求如下: 每行不超过80个字符:每个单词居于同一行上:在同一行的单词之间以一个空格分隔:行首和行尾 ...
- [BJWC2008]雷涛的小猫
嘟嘟嘟 dp. 刚开始我想的是dp[i][j]表示在第 i 棵树上,高度为h能吃到的最多的果子,如此能得到转移方程: dp[i][j] = max(dp[i][j + 1], dp[k][j + de ...
- Js 面向对象之封装,继承,原型,原型链
封装 ,继承 ,原型, 原型链 封装 ? 面向对象有三大特性,封装.继承和多态.对于ES5来说,没有class(类)的概念,并且由于JS的函数级作用域(函数内部的变量在函数外访问不到),所以我们就可以 ...
- python list 使用技巧
格式:list[start:stop:step] 示例:a =list(range(0,10))print(a[1:8:2]) #[1, 3, 5, 7]print(a[:8:2]) #[0, 2, ...
- 内部元素一一相应的集合的算法优化,从list到hashmap
说是算法优化,基本上是在吹牛,仅仅只是算是记录下,我写代码时候的思路.毕竟还是小菜鸟. 我要开一个party,与会者都是情侣,可是情侣并非一起过来的,而是有先有后,可是每位与会者来的时候都拿着一束鲜花 ...
- 观察者模式及c++实现
观察者模式概念:定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,全部依赖于它的对象都得到通知并自己主动更新."Define a one-to-many dependenc ...
- 安装MySQL56时,停止在start service这一步
问题: 在安装MySQL56时,安装程序执行到start service这一步就不能完成,系统一直提示“安装时间比预期的的长,是否停止安装这一步(configuration of mysql seve ...
- postmark使用
一.Postmark原理 Postmark是由着名的NAS提供商NetApp开发,用来测试其产品的后端存储性能. Postmark主要用于测试文件系统在邮件系统或电子商务系统中性能,这类应用的特点是: ...