最近打算将常用的数据结构通过java实现一遍,也是对数据结构学习的巩固,如有错误也请多多指正。
数组的主要操作
数组是一段连续存放数据的一种数据结构,主要是用java实现一个简单的数组的增删改查的操作。
其中需要说明的是动态数组的实现是当增加数组元素后,size值等于数组长度时,自动扩充到原来数组长度的2倍(java中的数组是1.5倍),扩充方法是新建一个长度为2倍的新数组,将原来的数组值复制到新数组中,原来的数组再指向这个新数组;同理当删除元素后,size值等于数组长度的一半时,自动扩充到原来数组长度的一半。平均每次addLast操作执行2次resize,平摊下来o(1),这个叫均摊复杂度。
但是这样会造成震荡复杂度的问题,即如果原始数组中的假如有10个元素当添加一个元素后扩充为容量为20的数组,当再删除一个数组时,又会缩减成容量为10的数组,每进行一次动态更新操作复杂度为o(n)。所以改进方法为,在删除元素时不要着急缩减容量,即可以设置当元素减少到原来数组的1/4时,再将数组减少到原来的一半。
Array.java代码实现:
package com.lxr.array0330;
public class Array<E> {
/**
* 增:o(n)
* 删:o(n)
* (增和删如果只对最后一个元素操作依然是o(n),是因为使用了resize.
* 但是并不是每次都出发resize,平均每次addLast操作执行2次resize,平摊下来o(1),这个叫均摊复杂度。
* 当数组元素已满时,添加一个元素,再删掉这个元素,再添加一个元素。。。数组容积不断扩充缩减,这种叫复杂度震荡。
* 出现原因:当删除最后一个元素时过于着急减少数组容量
* 解决方案:当删除最后一个元素时不要着急减少数组容量,等减少一部分后再进行缩减)
* 改:已知索引o(1),未知索引o(n)
* 查:已知索引o(1),未知索引o(n)
*/
private E[] data;
private int size;
public Array(int capacity) {
data=(E[])new Object[capacity];
size=0;
}
//初始容量为10
public Array() {
this(10);
}
//获取数组元素的个数
public int getsize() {
return size;
}
//获取容量
public int getCapacity() {
return data.length;
}
//是否为空
public boolean isEmpty() {
return size==0;
}
//动态数组实现扩充,将元素复制到新数组,然后在指向这个新数组
private void resize(int newcapacity) {
E[] newdata =(E[])new Object[newcapacity];
for(int i=0;i<size;i++) {
newdata[i]=data[i];
}
data=newdata;
}
/**
* 数组index位置插入元素value。时间复杂度与index的取值有关,每一个index的概率相同取平均o(n/2)=o(n)
* @param index 插入位置
* @param value 插入元素值
*/
public void insertElement(int index,E value) {
// if(size==data.length)
// throw new IllegalArgumentException("数组已满");
if(index<0||index>size)
throw new IllegalArgumentException("越界");
//动态数组,java的arraylist选用的是扩充1.5倍
if(size==data.length)
resize(2*data.length);
for(int i=size;i>index;i--) {
data[i]=data[i-1];
}
data[index]=value;
size++;
}
/**
* 向数组中添加新元素。时间复杂度o(1)
* @param a 插入元素值
*/
public void addElement(E a) {
// if(size==data.length)
// throw new IllegalArgumentException("数组已满");
// data[size]=a;
// size++;
insertElement(size, a);
}
/**
* 数组头插入元素。时间复杂度o(n)
* @param e 插入的头元素
*/
public void addFirst(E e) {
insertElement(0, e);
}
/**
* 获取index位置的值。时间复杂度o(1)
* @param index
* @return
*/
public E get(int index) {
if(index<0||index>=size)
throw new IllegalArgumentException("获取失败");
return data[index];
}
/**
* 数组index位置更新元素value。时间复杂度o(1)
* @param index 更新元素位置
* @param value 更新元素值元素值
*/
public void set(int index,E value) {
if(index<0||index>=size)
throw new IllegalArgumentException("获取失败");
data[index]=value;
}
//查找数组中是否存在元素e。时间复杂度o(n)
public boolean contains(E e) {
for(int i=0;i<size;i++) {
if(data[i].equals(e))
return true;
}
return false;
}
//查找数组中元素e的索引;不存在返回-1。时间复杂度o(n)
public int find(E e) {
for(int i=0;i<size;i++) {
if(data[i].equals(e))
return i;
}
return -1;
}
//查找数组中元素e的所有索引,索引存入数组中,若不存在则数组第一个元素为-1;
public int[] findAll(E e) {
int[] a=new int[size];
if(find(e)==-1) {
a[0]=-1;
}
int in=0;
for(int i=0;i<size;i++) {
if(data[i].equals(e)) {
a[in]=i;
in++;
}
}
return a;
}
//从数组中删除index的元素,返回删除元素。时间复杂度o(n/2)=o(n)
public E delate(int index) {
if(index<0||index>=size)
throw new IllegalArgumentException("删除失败1");
E a=data[index];
for(int i=index;i<size-1;i++) {
data[i]=data[i+1];
}
size--;
data[size]=null;//loitering object !=memory leak (垃圾回收机制,这样可以被回收)
//当数组减少到数组长度的一半时,动态减少数组的长度的一半
//当数组减少到数组长度的1/4时,动态减少数组的长度的一半(防止震荡复杂度)
if(size==data.length/4&&data.length/2!=0) {
resize(data.length/2);
}
return a;
}
//从数组中删除第一个元素,返回删除元素。时间复杂度o(n)
public E delateFrist() {
return delate(0);
}
//从数组中删除最后一个元素,返回删除元素。时间复杂度o(1)
public E delateLast() {
return delate(size-1);
}
//从数组中删除元素e
public void deleteElement(E e) {
int index=find(e);
if(index!=-1)
delate(index);
}
//从数组中删除所有元素e
public void deleteAllElement(E e) {
int []a=findAll(e);
for(int i=a.length-1;i>0;i--) {
if(a[i]!=0) {
System.out.println(a[i]);
delate(a[i]);
}
}
if(a[0]!=-1) {
delate(a[0]);
}
}
public E getFirst() {
return get(0);
}
public E getLast() {
return get(size-1);
}
/**
* 继承的父类,功能是自定义打印输出的格式
*/
@Override
public String toString() {
StringBuilder reStringBuilder =new StringBuilder();
reStringBuilder.append(String.format("Array:size=%d,capacity=%d\n",size,data.length));
reStringBuilder.append('[');
for(int i=0;i<size;i++) {
reStringBuilder.append(data[i]);
if(i!=size-1)
reStringBuilder.append(", ");
}
reStringBuilder.append(']');
return reStringBuilder.toString();
}
}