[数据结构] - 数组

1、Java数组介绍

  在Java中,数组是用来存放同一种数据类型的集合,注意只能存放同一种数据类型(Object类型数组除外)。

  • 在内存中,数组是一块连续的区域。 拿上面的看电影来说,这几个人在电影院必须坐在一起。

  • 数组需要预留空间,在使用前要先申请占内存的大小,可能会浪费内存空间。 比如看电影时,为了保证10个人能坐在一起,必须提前订好10个连续的位置。这样的好处就是能保证10个人可以在一起。但是这样的缺点是,如果来的人不够10个,那么剩下的位置就浪费了。如果临时有多来了个人,那么10个就不够用了,这时可能需要将第11个位置上的人挪走,或者是他们11个人重新去找一个11连坐的位置,效率都很低。如果没有找到符合要求的作为,那么就没法坐了。

  • 插入数据和删除数据效率低,插入数据时,这个位置后面的数据在内存中都要向后移。删除数据时,这个数据后面的数据都要往前移动。 比如原来去了5个人,然后后来又去了一个人要坐在第三个位置上,那么第三个到第五个都要往后移动一个位子,将第三个位置留给新来的人。 当这个人走了的时候,因为他们要连在一起的,所以他后面几个人要往前移动一个位置,把这个空位补上。

  • 随机读取效率很高。因为数组是连续的,知道每一个数据的内存地址,可以直接找到给地址的数据。

  • 并且不利于扩展,数组定义的空间不够时要重新定义数组。一种解决办法是封装一次数组,数组元素超过75%时候就动态扩容,新申请一个1.5倍的数组,把原来的数组全部拷贝过去。

①、数组的声明

第一种方式:

数据类型 []  数组名称 = new 数据类型[数组长度];

这里 [] 可以放在数组名称的前面,也可以放在数组名称的后面,我们推荐放在数组名称的前面,这样看上去 数据类型 [] 表示的很明显是一个数组类型,而放在数组名称后面,则不是那么直观。

第二种方式:

数据类型 [] 数组名称 = {数组元素1,数组元素2,......}

 这种方式声明数组的同时直接给定了数组的元素,数组的大小由给定的数组元素个数决定。

//声明数组1,声明一个长度为3,只能存放int类型的数据
int [] myArray = new int[3];
//声明数组2,声明一个数组元素为 1,2,3的int类型数组
int [] myArray2 = {1,2,3};

②、访问数组元素以及给数组元素赋值

  数组是存在下标索引的,通过下标可以获取指定位置的元素,数组小标是从0开始的,也就是说下标0对应的就是数组中第1个元素,可以很方便的对数组中的元素进行存取操作。

  前面数组的声明第二种方式,我们在声明数组的同时,也进行了初始化赋值。
  
 

//声明数组,声明一个长度为3,只能存放int类型的数据
int [] myArray = new int[3];
//给myArray第一个元素赋值1
myArray[0] = 1;
//访问myArray的第一个元素
System.out.println(myArray[0]);

上面的myArray 数组,我们只能赋值三个元素,也就是下标从0到2,如果你访问 myArray[3] ,那么会报数组下标越界异常。

③、数组遍历

  数组有个 length 属性,是记录数组的长度的,我们可以利用length属性来遍历数组。
  

//声明数组2,声明一个数组元素为 1,2,3的int类型数组
int [] myArray2 = {1,2,3};
for(int i = 0 ; i < myArray2.length ; i++){
    System.out.println(myArray2[i]);
}

2、简单封装一个动态数组

package me.liangtian.array;
 
public class Array<E> {
	/**
	 * 存放数据的数组
	 */
	private E[] data;
	/**
	 * 数组中现有数据量
	 */
	private int size;
	
	public Array(int capacity) {
		data = (E[])new Object[capacity];
		size = 0;
	}
	/**
	 * 默认数组长度10
	 */
	public Array() {
		new Array<>(10);
	}
	/**
	 * 得到数组长度
	 */
	public int getCapacity() {
		return data.length;
	}
	/**
	 * 已有数组大小
	 */
	public int getSize() {
		return size;
	}
	/**
	 * 判断数组是否为空
	 */
	public boolean isEmpty() {
		return size == 0;
	}
	/**
	 * 索引index处添加一个元素
	 * 1.判断索引是否有效
	 * 2.判断数组是否已经满了,若满了那么扩容
	 * 3.从后往前,index处的元素后移一个位置
	 * 4.index索引处元素赋值
	 * 5.size++
	 */
	public void add(int index, E e) {
		if(index < 0 || index > size) {
			throw new IllegalArgumentException("add failed, index must between 0 and size");
		}
		if(index == size) {
			resize( 2 * data.length);
		}
		for (int i = size -1; i >= index; i--) {
			data[i+1] = data[i];
		}
		data[index] = e;
		size++;
	}
	/**
	 * 在尾部添加新元素
	 */
	public void addLast(E e) {
		add(size, e);
	}
	/**
	 * 在头部添加新元素
	 */
	public void addFirst(E e) {
		add(0, e);
	}
	
	/**
	 * 是否包含否个元素
	 */
	public boolean contains(E e) {
		for (E e1 : data) {
			if(e1.equals(e)) {
				return true;
			}
		}
		return false;
	} 
	
	/**
	 * 动态扩容
	 * 1.新建一个容器,大小为指定大小newCapacity
	 * 2.将之前的容器的元素按原有顺序放到新的容器中
	 * 3.将原指针指向新容器
	 */
	private void resize(int newCapacity) {
		E[] newDate = (E[]) new Object[newCapacity];
		for(int i = 0; i < size; i++) {
			newDate[i] = data[i];
		}
		data = newDate;
	}
	/**
	 * 查找元素E在数组中的索引
	 * 1.遍历所有的数组,若匹配到(equals非==)那么返回索引,否则返回-1
	 */
	private int find(E e) {
		for (int i = 0; i < data.length; i++) {
			if(data[i].equals(e)) {
				return i;
			}
		}
		return -1;
	}
	
	/**
	 * 删除元素并返回删除之前的位置
	 * 若不存在则返回-1
	 */
	public int removeElement(E e) {
		int index = find(e);
		if(index != -1) {
			remove(index);
		}
		return index;
	}
	/**
	 * 根据索引删除元素,并返回删除元素
	 * 1.判断索引是否有效
	 * 2.将索引处的元素保存到单独一个变量,用于返回
	 * 3.将所有元素左移,索引从小到大
	 * 4.将size索引处的元素清空,并且size-1
	 * 5.均摊算法复杂度。为防止算法复杂度振荡,只有size <= data.leng/4 那么重新调整数组大小为原大小二分之一
	 *   注意数组容器大小不能为0
	 */
	private E remove(int index) {
		if(index < 0 || index >= size) {
			throw new IllegalArgumentException("index must between 0 and size -1");
		}
		E removeData = data[index];
		for(int i = index + 1; i < size; i++) {
			data[i-1] = data[i];
		}
		data[index] = null;
		size--;
		if(size <= data.length/4 && data.length /2 != 0) {
			resize(data.length /2);
		}
		return removeData;
	}
}

posted @ 2019-01-14 11:14  梁天  阅读(338)  评论(1编辑  收藏  举报