数据结构之动态数组(集合)

我看了看慕课网上的视频,对于视频的东西进行一个整理,最开始我们先从最基础的数组开始.

我们知道Java中的数组是只能存储基本类型,我们在这里可以制作一个可以存储对象的数组,其实也就是集合,我们就是自己去写一个集合。
首先,我们要定义我们的集合的底层,我们这个集合的底层就是数组,为了规范我们将底层和数组的大小里面存储的书=数的数量设置为private形式,用户不需要去能够使用到底层的知识,他们也不需要去更改,他们使用的时候只需要去调用我们写好的代码就可以了。
	private E[]data;
	private int size;
在这里我们需要强调两个概念,size和capacity

size是指的是数组中元素的个数而capacity指的是数组的容量,这个需要好好地区分开,我们在数组里面存储元素,数组不一定会被装满,而capacity一旦被装满了我们就需要去扩容了,这个问题我们稍后再说

然后就是构造方法,我们作为一个需要有他的构造方法,不仅仅是一个无参构造就可以完成了,还可以去写有参数的构造,(就像HashMap他其实是有四个构造函数的,具体的源码可以看我的博客,我稍微的介绍了HasMap中的一些知识)可以去穿指定大小的数组,到后面数组的扩容一定会浪费资源,如果我们最开始就完成了数组的建立,不用扩容我们就会很节省资源。
//有参构造
	public Array(int capacity) {
		data=(E[])new Object[capacity];
		size=0;
	}
	
	//无参构造,默认size为0 
	public Array() {
		this(10);
	}
后面是一些基本的方法,例如说获得元素的个数,获得数组的容量,判断数组的是否为空,是否包含某个元素,寻找某个元素的位置,打印对象。
/**
	 *获得元素的个数 
	 * @return
	 */
	public int getSize() {
		return size;
	}
	
	/**
	 * 获得数组的容量
	 * @return
	 */
	public int getCapacity() {
		return data.length; 
	}
	
	/**
	 * 判断数组是否为空
	 * @return
	 */
	public boolean isEmpty() {
		return size==0;
	}
	
	/**
	 * 如果有则返回true
	 * 没有则返回false
	 * @param e
	 * @return
	 */
	public boolean contains(E e) {
		for (int i = 0; i < size; i++) {
			if(data[i].equals(e)) {
				return true;
			}
			
		}
		return false;
	}
	
	
	/**
	 * 判断元素在里面是第几个如果有则显示位置,没有则返回-1
	 * @param e
	 * @return
	 */
	public int find(E e) {
		for (int i = 0; i < size; i++) {
			if(data[i].equals(e)) {
				return i;
			}
			
		}
		return -1;
	}
		@Override
	public String  toString() {
		
		StringBuilder res=new StringBuilder();
		res.append(String.format("Array: size= %d , capacity= %d\n",size,data.length));
		res.append('[');
		for (int i = 0; i < size; i ++) {
			res.append(data[i]);
			if(i !=size-1) {
				res.append(", ");
			}
		}
			res.append(']');
			return res.toString();
	}

数组的增删改查,这个我们手写的关键

数组的增加

首先是在某个位置增加某个元素,逻辑是先判断size的合法性,如果是大小等于数组的大小,则扩容,不合法报错,合法的话遍历找到位置,在制定位置往后移,指定位置插入元素,size++。
/**
	 * 在index的位置上添加一个元素e
	 * @param index
	 * @param e
	 */
	public void add(int index ,E e) {
		if(size==data.length) {
			resize(2*data.length);
		}
		if(index<0 ||index>size) {
			throw new IllegalArgumentException(">0");
		}
		for (int i = size-1; i >=index; i--) {
			data[i+1]=data[i];
		}
		data[index]=e;
		size++;
	}
可以在后面添加一些添加的便捷方法
/**
	 *加在最后 
	 * @param e
	 */
	public void addList(E e) {
//		if(size==data.length) {
//			throw new IllegalArgumentException("已经满了");
//		}
//		data[size]=e;
//		size++;
		add(size, e);
	}
	
	/**
	 * 添加都头部位置
	 * @param e
	 */
	public void addfirst(E e) {
		add(0, e);
	}

数组的获取和修改

数组获取的逻辑判断给定的个数是否在合法的范围,加上便捷的方法。
	/**
	 * 拿到第n个元素
	 * @param index
	 * @return
	 */
	public E  get(int index) {
		if(index<0||index>=size) {
			throw new IllegalArgumentException("index要大于零");
		}
		return data[index];
	}
	
	public E  getFirst() {
		return  get(0);
	}
	
	
	public E  getLast() {
		return get(size-1);
	}
	

数组中指定位置的修改
	public void set(int index,E e) {
		if(index<0||index>=size) {
			throw new IllegalArgumentException("index要大于零");
		}
		data[index]=e;
	}

数组中数据的删除

数组中数据移除的逻辑,因为是数组如果一个元素被移除,则元素后面元素要向前移一个,size–.
/**
	 * 实现原理找到index的位置
	 * 然后将后一个一个一个向前一个替换,不暴露size个位置那样的话不需要去处理最后一个元素
	 * 因为访问不到
	 * 最开始的时候因为是基本类型但是以为里面是泛型所以size指向的其实是引用,所以要为了节省空间将其删除
	 * @return
	 */
	public E  remove(int index) {
		if(index<0||index>=size) {
			throw new IllegalArgumentException("index要大于零");
		}
		E num=data[index];
		for (int i = index+1; i < size; i++) {
			data[i-1]=data[i];
		}
		size--;
		
		data[size]=null;
		//loitering objects!=memory leak	
		//闲散游散元素不动于内存泄漏,只是为了优化而优化
		//缩减的时候要注意后面吗还有没有元素,如果有元素就不能就行缩减
		if(size==data.length/4&&data.length/2!=0) {
			//记上了&&为了避免空
			
			resize(data.length/2);
			
			}
		return num;
	}
	
	/**
	 *移除最前 
	 * @return
	 */
	public E removeFirst() {
		// TODO Auto-generated method stub
		return remove(0);
	}
	
	public E removeLast() {
		// TODO Auto-generated method stub
		return remove(size-1);
	}
	
	/**
	 *单纯只是为了删除其中的一个元素,没有考虑删除多个,也没有考虑删除以后的回复,单独就是一个删除操作
	 *本身的想法也只是为了删除其中的一个元素而已 
	 */
	public void removeElement(E e) {
		int find = find(e);
		if(find!=-1) {
			remove(find);
		}
		
	}

数组的扩容

数组的扩容这就牵扯到一个是时间复杂度的问题了,假如说数组的数量为10,超过10这个数字我们就要开始扩容,如果刚刚到10就开始扩容那么,万一一个数据就是在10的时候进行插入,插入以后到达临界点,继续插入下一条数据时,数组扩容原来的两倍,这时因为扩容操作空间复杂度是O(n),然后如果下一个操作是删除连续两次,数组进行缩容,数组变小了,然后还是一次缩容,空间复杂度是O(n),这个操作因为一步就要进行空间复杂度很大的操作,所以我们采用集合里面的做法,使用加载因子,当数组到达数组容量的时候我们再开始扩容,当数组的大小到达数组的大小的四分之一的时候才会开始缩容,这样的话我们就可以降低我们的空间复杂度,具体的例子就像是下面的
/**
	 * 实现原理找到index的位置
	 * 然后将后一个一个一个向前一个替换,不暴露size个位置那样的话不需要去处理最后一个元素
	 * 因为访问不到
	 * 最开始的时候因为是基本类型但是以为里面是泛型所以size指向的其实是引用,所以要为了节省空间将其删除
	 * @return
	 */
	public E  remove(int index) {
		if(index<0||index>=size) {
			throw new IllegalArgumentException("index要大于零");
		}
		E num=data[index];
		for (int i = index+1; i < size; i++) {
			data[i-1]=data[i];
		}
		size--;
		
		data[size]=null;
		//loitering objects!=memory leak	
		//闲散游散元素不动于内存泄漏,只是为了优化而优化
		//缩减的时候要注意后面吗还有没有元素,如果有元素就不能就行缩减
		if(size==data.length/4&&data.length/2!=0) {
			//记上了&&为了避免空
			
			resize(data.length/2);
			
			}
		return num;
	}

上面这段代码出现过,但是我的意思是告诉大家这是我们对自己的数组的一种优化,这个代码使我们学数据结构的基础,以后的出现的数据结构我会好好的整理的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

又是重名了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值