数组是一种比较简单的数据结构,而且在大多数高级程序设计语言中都实现了数组。
一、无序数组
利用面向过程的思想创建数组,实现数组元素的插入、查找和删除工作:
public class Box{ public static void main(String[] args){ //create a array long[] arr=new long[50]; //record index int index=0; //record move number int count=0; //insert 10 items arr[0]=20; arr[1]=55; arr[2]=32; arr[3]=22; arr[4]=18; arr[5]=66; arr[6]=58; arr[7]=23; arr[8]=29; arr[9]=3; //show number for(int i=0;i<10;i++){ System.out.print(arr[i]+" "); } //find index with value 18 for(int i=0;i<10;i++){ if(arr[i]==18){ index=i; break; } } System.out.println(); System.out.print("18---"+index); //delete index with value 32 for(int i=0;i<10;i++){ if(arr[i]==32){ index=i; break; } } for(int i=index;i<9;i++){ arr[i]=arr[i+1]; count++; } //show number System.out.println(); for(int i=0;i<9;i++){ System.out.print(arr[i]+" "); } System.out.println(); System.out.print("move number:"+count); } }
我们从这段程序中可以看到,虽然可以完成所要的操作,但是程序结构不直观,功能也不甚清晰。下面我们采用面向对象的思想创建一个具有同样功能的类:
public class MyArray{ private static long[] arr; private static int index=0; private static int count=0; //create a array public static void makeArray(int num){ arr=new long[num]; } //show array public static void showMyArray(int size){ for(int i=0;i<size;i++){ System.out.print(arr[i]+" "); } System.out.println(); } //insert items public static void insertItems(int key,long value){ arr[key]=value; } //find a item public static int findItem(long value){ for(int i=0;i<arr.length;i++){ if(arr[i]==value){ index = i; break; } count++; } if(count==arr.length){ return -1; }else{ return index; } } //delete items public static boolean deleteItem(long value){ count=0; for(int i=0;i<arr.length;i++){ if(arr[i]==value){ index = i; break; } count++; } if(count==arr.length){ return false; }else{ //delete count=0; for(int i=index;i<arr.length-1;i++){ arr[i]=arr[i+1]; count++; } return true; } } public static void main(String[] args){ //create makeArray(10); //insert insertItems(0,22); insertItems(1,21); insertItems(2,18); insertItems(3,33); insertItems(4,59); insertItems(5,47); insertItems(6,35); insertItems(7,12); insertItems(8,9); insertItems(9,66); //show number showMyArray(arr.length); //find int key = findItem(12); if(key!=-1){ System.out.print("12----"+key); System.out.println(); }else{ System.out.print("can not find "); System.out.println(); } //delete boolean flag=deleteItem(18); if(flag==true){ System.out.print("success!"); System.out.println(); System.out.print("move number:"+count); }else{ System.out.print("can not find "); } //show number System.out.println(); showMyArray(arr.length-1); } }
这里为了呈现方便,将main方法也放在了数组类MyArray中,若放在其他类中,那么MyArray就是一个完整的操作数组的类,它具有自己的私有成员和公共成员方法。这样就可以做到各司其职,用户只需要知道接口而并不需要了解如何处理数组就可以达到自己的目的。如果成功的将一个对数组的操作封装到一个类中,用户在使用时甚至都不会察觉自己使用的是一个数组,因为类的完美封装已经隐藏了自己的几乎一切,这一点在有序数组的例子中可以发现。
二、有序数组
有序数组,其中的数据是按关键字升序(或降序)排列的。这种排列使快速查找数据项成为可能,即可以使用二分查找。但是在插入和删除方面会比一般数组要慢一些,因为需要进行一道排序工作。就好比图书馆中书的摆放一样,随便摆肯定会快,但是找的时候就不容易,而按照一定顺序摆比较麻烦(涉及到比较),但是找起来很容易。
class OrderArray{ private long[] arr; private int length; //create a array public OrderArray(int num){ arr=new long[num]; length=0; } //get array length public int size(){ return length; } //show array public void show(){ for(int i=0;i<length;i++){ System.out.print(arr[i]+" "); } System.out.println(); } //insert items public void insert(long value){ if(length+1<=arr.length){ boolean flag=true; int index=0; for(int i=0;i<length;i++){ if(arr[i]<value){ flag=true; }else{ flag=false; index=i; break; } } if(flag){ arr[length]=value; }else{ for(int i=length;i>index;i--){ arr[i]=arr[i-1]; } arr[index]=value; } length++; }else{ //throw Exception System.out.println("Sorry,this array is full!"); } } //find a index of value public int find(long value){ //binary search int head=0; int end=length-1; int index=0; //*******important*********// while(true){ index=(head+end)/2; if(arr[index]!=value){ if(head<=end){ if(arr[index]>value){ end=index-1; }else{ head=index+1; } }else{ System.out.println("Sorry,can`t find!"); return -1; } }else{ //find it System.out.println(value+"----"+index); return index; } } } //delete items public boolean delete(long value){ int info=find(value); if(info!=-1){ for(int i=info;i<length;i++){ arr[i]=arr[i+1]; } System.out.println("Delete success!"); length--; return true; }else{ //value not exist System.out.println("Delete fail!"); return false; } } } public class MyArray{ public static void main(String[] args){ OrderArray array=new OrderArray(10); //insert value array.insert(5); array.insert(1); array.insert(20); array.insert(19); array.insert(30); array.insert(22); array.insert(28); //show value array.show(); System.out.println("--------------------"); //find value array.find(5); array.find(1); array.find(20); array.find(19); array.find(30); array.find(99); System.out.println("--------------------"); //delete value array.delete(19); array.delete(89); //show value array.show(); System.out.println("--------------------"); System.out.println("insert 10 and 6:"); array.insert(10); array.insert(6); //show value array.show(); } }
本程序在进行数据插入时就进行了由小到大的排序,最终形成了一个有序数组,我们接着利用有序数组的这个特性进行了二分查找,这种查找方式相比较一般查找会快很多,因为在找的过程中会不断缩小一般的范围。如果在一个较小的数据集中不会有太明显的效果,但是在大数据集中进行查找会有明显的效果。据《Java数据结构与算法》一书中的数据可知,如果有1000000条记录,一般的查找需要500000步,而二分查找只需要20步。
----------------------------------------------------------
上述代码操作的都是一般类型,在Java中数组是可以操作引用类型的,比如创建一个存放Person对象的数组
Person [] p=new Person[MAX];
此类数组在使用过程中和基本数据类型的数组是一样的。
三、总结
现实中我们会用一些方法来比较事物的大小,在计算机算法中,我们采用“大O”来表示算法的效率。但是算法的效率不能简单说哪个算法就比哪个快多少倍,因为其还与数据项的多少有关,就比如二分查找和一般查找,当数据项很少时基本上效率差不多,但是到达一定数量也许就是很多倍的差距。下面总结一下数组中的一些效率问题。
- 无序数组的插入(常数K)是我们现在为止所见过的算法中唯一一个与数组中的数据项个数无关的算法,因为其总是将数据插入到数据项后边有空的地方,所以对于每一个数据来说都是一样的。(如果想测试插入一条数据需要多长时间,不防循环个几千次,再用总时间除以循环次数,不然很能计算出来,因为计算机对于这种操作运行是非常快的)
- 线性查找(与N成正比),在数组数据项的线性查找中,我们已经发现寻找特定数据项所需的比较次数平均为数据项总数的一半,T=K *N,这里的K指运行一次执行的时间。
- 二分查找(与log(N)成正比),即T=K*log(N)。
上面带有K的是一种时间表示法,大O表示法省去了K,也就是忽视了未处理芯片或编译器的时间,其主要表示对应不同的N,T是如何变化的,一般大O表示有如下几个级:O(1)是优秀,O(logN)是良好,O(N)是还可以,O(N*N)是较差。
总体来说数组是一种使用简单、易理解的数据结构,但是由于其自身的缺点,如:固定大小,无序数组删除、查找较慢,有序数组插入、删除较慢,这些都影响了它的应用范围。