<数据结构系列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变 ...
随机推荐
- PHP设计模式系列 - 装饰器
什么是装饰器 装饰器模式,对已有对象的部分内容或者功能进行调整,但是不需要修改原始对象结构,可以使用装饰器设 应用场景 设计一个UserInfo类,里面有UserInfo数组,用于存储用户名信息 通过 ...
- CR与LF
CR与LF CR(carriage return),中文名称"回车":LF(line feed),中文名称"换行".无论是初学编程的小白还是入行十年的资深,总会 ...
- PHP常用符号和函数
(转)最近在写PHP程序的时候发现了一些特殊的PHP符号,例如连续小于符号,三个小于符号,eot,eod,echo示例,print示例等,突然间 发现用这么久的PHP了,竟然连PHP的基本符号都没有认 ...
- 使用MS的ScriptDom来拆解TSQL脚本
此处提供9.1.40413.0版本的DLL一共4个:Microsoft.Data.Schema.dll.Microsoft.Data.Schema.ScriptDom.dll.Microsoft.Da ...
- 使用 kubeadm 安装部署 kubernetes 1.9-部署heapster插件
1.先到外网下载好镜像倒进各个节点 2.下载yaml文件和创建应用 mkdir -p ~/k8s/heapster cd ~/k8s/heapster wget https://raw.githubu ...
- python 爬虫 发送每天天气
#!/usr/bin/python# -*- coding: UTF-8 -*-import requests,bs4,smtplib,sysimport smtplib, sysfrom email ...
- C#中的结构体与类的区别 (转载)
经常听到有朋友在讨论C#中的结构与类有什么区别.正好这几日闲来无事,自己总结一下,希望大家指点. 1. 首先是语法定义上的区别啦,这个就不用多说了.定义类使用关键字class 定义结构使用关键字str ...
- 如何编写编译Robocup3D代码
目录 开始编写球队代码 void NaoBehavior::beam() SkillType NaoBehavior::PlayOnSkill() 其他阶段函数 修复make异常 开始编写球队代码 装 ...
- vue实现首页导航切换不同路由的方式
vue实现切换首页路由导航 ,根据切换的不同导航跳转不同的路由,以及当前选中的导航添加选中样式. html代码: <nav> <!-- 导航栏 --> <div cla ...
- WPF实现斜纹圆角进度条样式
原文:WPF实现斜纹圆角进度条样式 运行效果: 进度条样式: <!--进度条样式--> <LinearGradientBrush x:Key="ProgressBar.Pr ...