数据结构动态数组

我们对数组进行改造的原理如下:重新建立一个capacity更大的数组,通过for循环让原来数组的数据复制到新的数组里,再让我们原来的数组指向newdate

这样我们的date和newdate指向的同一个空间,我们会把这样一个过程封装在函数里,newdate会在执行完后被回收

package www.zxx;

public class Array<E> {
	private E[] data;
	private int size;

	//带参构造函数
	public Array(int capacity) {
		//不支持new一个泛型数组
		//先建立一个object类再进行强转
		data = (E[])new Object[capacity];
		size = 0;
	}

	//无参构造函数输入的数据实际上是capacity的值
	public Array() {
		this(10);
	}

	//获得数组的size
	public int getSize() {
		return size;
	}

	//获得数组的容量
	public int getCapacity() {
		return data.length;
	}

	//通过已经写好的add函数写一个在开头添加e值的函数
    //好处是add函数已经处理过index数值的溢出问题
	public void addFirst(E e) {
		add(0, e);
	}

	//通过已经写好的add函数写一个在末尾添加e值的函数
	//好处是add函数已经处理过index数值的溢出问题
	public void addLast(E e) {
		add(size, e);
	}

	//在index位置加入e数值的数
	//要进行index数值的输入控制
	public void add(int index, E e) {
		if (index < 0 || index > size) {
			throw new IllegalArgumentException("Add failed,Index beyond brode");
		}
		if (size == data.length) {
			resize(2*data.length);
		}
		for (int i = size - 1; i >= index; i--) {
			data[i + 1] = data[i];
		}
		data[index] = e;
		size++;
	}

	//判断e数值在不在数组内
	public boolean contains(E e) {
		for (int i = 0; i < size; i++) {
			if (data[i].equals(e))
				return true;
		}
		return false;
	}

	//找数组中为e数值的位置,如果没有输出-1
	public int find(E e) {
		for (int i = 0; i < size; i++) {
			//值比较
			if (data[i].equals(e))
				return i;
		}
		return -1;
	}

	@Override
	//重写tostring方法让System.out.println()能直接输出我们指定的类型
	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(',');
			} else {
				res.append(']');
			}
		}
		return res.toString();

	}

	// 获得index位置的数
	E get(int index) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("Get failed.Index beyond brode.");
		return data[index];
	}

	// 设置index位置的数为e
	void set(int index, E e) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("Get failed.Index beyond brode.");
		data[index] = e;
	}

	//删除index位置的元素
	//返回删除的元素
	E remove(int index) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("Get failed.Index beyond brode.");
		E rec = data[index];
		for(int i = index ; i < size ;i++) {
			data[i] = data[i+1];
		}
		//我们的int类型的数组size指向的值不需要被删除,因为我们在后面插入的时候能覆盖
		//在泛型中我们使用的是类对象,我们应该删除它
		size--;
		//loitering objects!=memory leak(内存泄漏)
		data[size]=null;
		return rec;
	}
	
	//删除第一个元素
	public E removeFirst() {
		return remove(0);
	}
	
	//删除最后一个元素
	public E removeLast() {
		return remove(size-1);
	}
	
	//从数组中寻找e数值的值,如果找到删除它
	public void removeElement(E e) {
		int index = find(e);
		if(index != -1) {
			remove(index);
		}
	}
	
	//扩容
	private void resize(int newCapacity) {
		E[] newData = (E[])new Object[newCapacity];
		for(int i = 0; i < size;i++) {
			newData[i] = data[i];
		}
		data = newData;
	}
	
	//主方法
	public static void main(String[] args) {
		Array<Integer> arr = new Array<Integer>();
		
		for (int i = 0; i < 10; i++) {
			arr.addLast(i);
		}
		System.out.println(arr);

		arr.add(1, 100);
		System.out.println(arr);

		arr.addFirst(-1);
		System.out.println(arr);
		
		arr.remove(0);
		System.out.println(arr);
		
		arr.removeElement(0);
		System.out.println(arr);
	}
}

 

在这里我们选择扩容的时候选择的是2*capacity

从结果中我们可以看到在我们add的时候超出了原来的capacity我们在add函数里进入到条件size==data.length进行了两倍扩容操作

上面的是扩容,相应的我们应该有减少容量

package www.zxx;

public class Array<E> {
	private E[] data;
	private int size;

	//带参构造函数
	public Array(int capacity) {
		//不支持new一个泛型数组
		//先建立一个object类再进行强转
		data = (E[])new Object[capacity];
		size = 0;
	}

	//无参构造函数输入的数据实际上是capacity的值
	public Array() {
		this(10);
	}

	//获得数组的size
	public int getSize() {
		return size;
	}

	//获得数组的容量
	public int getCapacity() {
		return data.length;
	}

	//通过已经写好的add函数写一个在开头添加e值的函数
    //好处是add函数已经处理过index数值的溢出问题
	public void addFirst(E e) {
		add(0, e);
	}

	//通过已经写好的add函数写一个在末尾添加e值的函数
	//好处是add函数已经处理过index数值的溢出问题
	public void addLast(E e) {
		add(size, e);
	}

	//在index位置加入e数值的数
	//要进行index数值的输入控制
	public void add(int index, E e) {
		if (index < 0 || index > size) {
			throw new IllegalArgumentException("Add failed,Index beyond brode");
		}
		if (size == data.length) {
			resize(2*data.length);
		}
		for (int i = size - 1; i >= index; i--) {
			data[i + 1] = data[i];
		}
		data[index] = e;
		size++;
	}

	//判断e数值在不在数组内
	public boolean contains(E e) {
		for (int i = 0; i < size; i++) {
			if (data[i].equals(e))
				return true;
		}
		return false;
	}

	//找数组中为e数值的位置,如果没有输出-1
	public int find(E e) {
		for (int i = 0; i < size; i++) {
			//值比较
			if (data[i].equals(e))
				return i;
		}
		return -1;
	}

	@Override
	//重写tostring方法让System.out.println()能直接输出我们指定的类型
	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(',');
			} else {
				res.append(']');
			}
		}
		return res.toString();

	}

	// 获得index位置的数
	E get(int index) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("Get failed.Index beyond brode.");
		return data[index];
	}

	// 设置index位置的数为e
	void set(int index, E e) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("Get failed.Index beyond brode.");
		data[index] = e;
	}

	//删除index位置的元素
	//返回删除的元素
	E remove(int index) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("Get failed.Index beyond brode.");
		E rec = data[index];
		for(int i = index+1 ; i < size ;i++) {
			data[i-1] = data[i];
		}
		//我们的int类型的数组size指向的值不需要被删除,因为我们在后面插入的时候能覆盖
		//在泛型中我们使用的是类对象,我们应该删除它
		size--;
		//loitering objects!=memory leak(内存泄漏)
		data[size]=null;
		
		if(size == data.length / 2)
			resize(data.length/2);
		return rec;
	}
	
	//删除第一个元素
	public E removeFirst() {
		return remove(0);
	}
	
	//删除最后一个元素
	public E removeLast() {
		return remove(size-1);
	}
	
	//从数组中寻找e数值的值,如果找到删除它
	public void removeElement(E e) {
		int index = find(e);
		if(index != -1) {
			remove(index);
		}
	}
	
	//扩容
	private void resize(int newCapacity) {
		E[] newData = (E[])new Object[newCapacity];
		for(int i = 0; i < size;i++) {
			newData[i] = data[i];
		}
		data = newData;
	}
	
	//主方法
	public static void main(String[] args) {
		Array<Integer> arr = new Array<Integer>();
		
		for (int i = 0; i < 10; i++) {
			arr.addLast(i);
		}
		System.out.println(arr);

		arr.add(1, 100);
		System.out.println(arr);

		arr.addFirst(-1);
		System.out.println(arr);
		
		arr.remove(0);
		System.out.println(arr);
		
		arr.removeElement(0);
		System.out.println(arr);
		
		arr.remove(0);
		System.out.println(arr);
		
		arr.removeFirst();
		System.out.println(arr);
		
		arr.removeFirst();
		System.out.println(arr);
		
		arr.removeFirst();
		System.out.println(arr);
		
		arr.removeFirst();
		System.out.println(arr);
		
		arr.removeFirst();
		System.out.println(arr);
		
		
		
	}
}

 

在把容量见效的时候还发现了一个隐形bug- -就是remove函数中的移动元素

之前的循环:

for(int i = index ; i < size ;i++) {
			data[i] = data[i+1];
		}

 

 

修改后的循环:

for(int i = index+1 ; i < size ;i++) {
            data[i-1] = data[i];
        }

 

我看了一下测试的数据- -因为之前在做remove操作的时候都没有超过容量,但其实i+1从index开始的话会到size

错误发生在第二次remove,这时我们的循环到了size出现了数组越界

要体会两种循环的差异

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值