<数据结构系列1>封装自己的数组——手写动态泛型数组

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

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

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;i<size;i++) {
            data[i]=data[i+1];            //将删除元素后的每个元素向前移动,覆盖住要被删除的元素
        }
        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,今天的数据结构第一篇:封装自己的动态数组就写到这了,希望可以多多关注我接下来的博文哦

有啥问题可以直接在下方评论区留言,我已经开通了微信提醒,会第一时间回复的。

对于学习,四个字概括:至死方休!

原文地址:https://www.cnblogs.com/LASloner/p/10721407.html

时间: 2024-10-29 05:45:11

<数据结构系列1>封装自己的数组——手写动态泛型数组的相关文章

手写动态代理(抄的)

如图1所示,动态代理的使用 这篇文章讲解动态代理的原理,以及如何手写动态代理. 以下是有关动态代理的使用,这是JDK默认帮我们实现的动态代理. public class Main implements InvocationHandler { static Person person=new PersonImp(); public static void main(String[] args) throws Throwable { Person o = (Person)Proxy.newProxy

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

一.概述 队列,又称为伫列(queue),是先进先出(FIFO, First-In-First-Out)的线性表.在具体应用中通常用链表或者数组来实现.队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作.队列的操作方式和堆栈类似,唯一的区别在于队列只允许新数据在后端进行添加. 在Java中队列又可以分为两个大类,一种是阻塞队列和非阻塞队列. 1.没有实现阻塞接口: 1)实现java.util.Queue的LinkList, 2)实现java.util.Abstra

css手写动态加载中...

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" con

180607-手写定长数组

文章链接:https://liuyueyi.github.io/hexblog/2018/06/07/180607-手写定长数组/ 手写定长数组 有个背景场景如下: 一天划分为1440分钟,每分钟记录一个数据块,然后用一个数据结构存储着1440个数据块,随着时间的推移,每过一分钟,向这个数据结构中添加一块,并移除最前的那个:其次就是我希望根据当前的时间,可以获取往前n分钟的数据块 简单来说,上面的需求解析如下: 一个数组,容量为1440 频繁的新增和删除 随机的访问 后面两个就限制了ArrayL

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

首先明白 动态代理和静态代理的区别: 静态代理:①持有被代理类的引用  ② 代理类一开始就被加载到内存中了(非常重要) 动态代理:JDK中的动态代理中的代理类是动态生成的.并且生成的动态代理类为$Proxy0 静态代理实例1.创建一个接口: package proxy; public interface People { public void zhaoduixiang()throws Throwable; } 2.创建一个实现类,张三,张三能够吃饭,张三可以找对象 package proxy;

java数据结构系列之——数组(2):有序数组

package Array; /** * 排序数组,向数组中添加元素时维护数组的有序性: * @author wl * */ public class MyOrderArray { private long array[]; private int elements;//用于记录数组中实际数据的个数 public MyOrderArray(){ array=new long[50];//数组默认长度为50: } public MyOrderArray(int capacity){//设置数组的默

浅谈数据结构系列 栈和队列

计算机程序离不开算法和数据结构,在数据结构算法应用中,栈和队列应用你比较广泛,因为两者在数据存放和读取方面效率比较高,本章节重点讲解两者的基本概念和实现. 基本概念 栈:是一种先进后出,后进先出的数据结构,本质上是线性表,只是限制仅允许在表的一段进行插入和删除工作.此端为栈顶,这是在栈中应用很关键的概念.所有数据的处理都是在栈顶进行的,进栈时,栈中元素增加,栈顶上移一位,出栈时栈顶下移一位.应用中比如:洗碗,每次洗干净的碗放在上面-进栈,取碗,从顶上取出一个-出栈:装子弹-进栈,开枪-出栈. 队

数据结构系列(三)线性表

线性表是什么 零个或多个数据元素的有序序列 线性存储结构 例如 java中的数组,每次都申请固定长度内存空间,并且长度不可变 而arraylist则是长度可变的数组,这是java在底层对数组进行封装,当长度超过原有长度,则会新建一个新的数组,把原有的数组复制过来.当然新的数组的长度也基于默认的扩展算法,当扩展后的数组长度又不够时,再进行之前的操作.所以当能预估出list长度时,初始化最好能指定长度 线性存储结构的优缺点 简单来说就是,查询和替换的时间复杂度为O(1),插入和删除的复杂度为O(n)

D&amp;F学数据结构系列——二叉堆

二叉堆(binary heap) 二叉堆数据结构是一种数组对象,它可以被视为一棵完全二叉树.同二叉查找树一样,堆也有两个性质,即结构性和堆序性.对于数组中任意位置i上的元素,其左儿子在位置2i上,右儿子在左儿子后的单元2i+1中,它的父亲在[i/2](向下取整)中. 因此,一个数据结构将由一个数组.一个代表最大值的整数.以及当前的堆的大小组成.一个典型的优先队列(priority queue)如下: 1 #ifndef _BinHeap_H 2 struct HeapStruct; 3 type