数组是应用最广泛的数据存储结构,它被植入到大部分编程语言中。由于数组十分易懂,所以它被用来介绍数据结构的起点。 数组分为2种:无序数组有序数组。有序数组就是无序数组经过排序后结果

     关于数组,大部分读者都已经非常熟悉了,不过需要注意的是,在数据结构与算法中,我们在讨论数组的时候,有一些特别要注意的地方

  1. 我们通常假设数组中是没有空洞的
  2. 当删除数组中一个元素时,这个数组中之后所有的元素位置都会前移一个位置
  3. 如果是无序数组的话,添加一个元素时,总是添加到数组的最后位置;
  4. 如果是有序数组的话,添加元素到某个位置时,当前位置的元素与之后的元素都要往后移动一个位置
  5. 数组维护了当前元素的数量

之所以有这些要求,主要是从操作方便的角度考虑,例如我有一个大小为5的数组,其中有3个元素,如下所示:

java哪个数组是有序的_java

1 我们通常假设数组中是没有空元素的

   当我们想在数组查找某个元素时,当所有元素都查过了之后,依然没有查到,就说明数组中不包含此元素。那么我们如何知道所有的元素都已经查过了呢?按照规则1,只要我们保证数组所有非空元素,都排在数组的前面,那么当我们遇到第一个空元素时,就说明所有的元素都查找完了。

2 当删除数组中一个元素时,这个数组中之后所有的元素位置都会前移一个位置

   例如我们删除了第二个元素,在java中,就是移除数组对这个对象的引用,只要将对应位置设为null即可,但是在这里我们却不能这样做,因为根据规则1,我们查找的时候,遇到第一个为null的元素的时候,就认为所有的元素都查找完了,例如现在查找5,那么就会查不到,因此删除必须将后面所有的元素都前移一个位置

3 如果是无序数组的话,添加一个元素时,总是添加到数组的最后位置;

   插入操作同样要满足,插入后,数组中依然不能存在空洞,否则查找依然会出现问题,例如现在还有2个位置可以插入,如果我们插入在最后一个位置上,根据规则1,之后在查找的时候又找不到这个元素了。

4、我们通常假设数组中没有相同的元素

在查找的时候,如果有相同的元素,那么可能会有多个匹配值,那么到底返回哪个呢?还是全部都返回?为了方便,我们通常假设数组中没有相同的元素,因此只需要返回第一个匹配上的值即可。

下面的代码是按照上述要求实现的数组

1. public class Array<V> {

2.     private Object[] elements;
3.     private int size=0;//数组中元素的数量
4.     private int capacity;//数组的容量
5.  
6.     /**
7.      * 数组的容量
8.      * @param capacity
9.      */
10.     public Array(int capacity) {

11.         this.capacity = capacity;
12.         if(capacity<=0){

13.             throw new IllegalArgumentException("capacity must > 0");
14.         }
15.         elements=new Object[capacity];
16.     }
17.  
18.     public void insert(V v){

19.         if(size==capacity-1){//达到容量限制
20.             throw new IndexOutOfBoundsException();
21.         }
22.         elements[size++]=v;//插入元素
23.     }
24.  
25.     public boolean remove(V v){

26.         for (int i = 0; i < size; i++) {

27.             if(elements[i].equals(v)){

28.                 elements[i]=null;//删除
29.                 moveUp(i,size);//将后面的所有数据项都前移一个位置
30.                 size--;//元素数量-1
31.                 return true;//找到第一个要删除的项,返回true
32.             }
33.         }
34.         return false;//所有元素都查找过了,依然没有找到要删除的项,犯规false
35.     }
36.  
37.     public V find(V v){

38.         for (int i = 0; i < size; i++) {

39.             if(elements[i].equals(v)){

40.               return (V) elements[i];
41.             }
42.         }
43.         return null;
44.     }
45.  
46.     private void moveUp(int i, int size) {

47.         while (i<size-1){

48.             elements[i]=elements[++i];
49.         }
50.         elements[size-1]=null;//最后一个元素置位null
51.     }
52.  
53.     /**
54.      * 返回指定下标的元素
55.      * @param index
56.      * @return
57.      */
58.     public V get(int index){

59.         if(index>capacity-1){

60.             throw new IndexOutOfBoundsException();
61.         }
62.         return (V) elements[index];
63.     }
64.  
65.     /**
66.      * 返回数组中元素的数量
67.      * @return
68.      */
69.     public int size(){

70.         return size;
71.     }
72.     /**
73.      * 显示所有元素
74.      */
75.     public void display(String prefix){

76.         System.out.print(prefix);
77.         for (int i = 0; i < elements.length; i++) {

78.             if(i<size){

79.                 System.out.print(elements[i]+"    ");
80.             }else{

81.                 System.out.print("null"+"    ");
82.             }
83.         }
84.         System.out.println();
85.     }
86.  
87.     public static void main(String[] args) {

88.         Array<Integer> array=new Array<Integer>(5);
89.         array.insert(1);
90.         array.insert(5);
91.         array.insert(3);
92.         array.display("初始 1、5、3 : ");
93.         array.insert(4);
94.         array.display("添加 4       : ");
95.         array.remove(3);
96.         array.display("删除 3       : ");
97.        System.out.println("查找 4:"+array.find(4) );
98.        System.out.println("查找 3:"+array.find(3) );
99.     }
100. }

运行程序,输出:

初始 1、5、3 : 1    5    3    null    null   

添加 4       : 1    5    3    4    null   

删除 3       : 1    5    4    null    null   

查找 4:4

查找 3:null 

数组的效率

   在数据结构与算法中,衡量算法的效率是通过时间复杂度和空间复杂度来进行的,后面我们会有专门的讲解,下面是一个简单的介绍

操作

时间复杂度

插入

O(1)

删除

O(N)

查找

O(N)

  其中:

  O(1)表示,此操作不受数组元素个数的影响,不论数组中现有多少元素,插入操作总是1步就可以完成

  O(N)表示此操作受到数据元素个数的影响,最直观的感受是,我们可以看到删除和查找操作,里面都有一个for循环来迭代数组中的所有元素,假设数组中有N个元素,我们随机查找或者删除一个数字,运气好的情况下,可能1次就查找了,运气不好,可能所有的N个元素迭代完了,还是没有找到,根据概率,平均可能需要进行N/2次循环,由于时间复杂度是忽略常数的,因此删除和查找操作的平均时间复杂度是O(N)

关于查找的说明

   在数据结构与算法中,查找指的并不是根据数组的下标进行查找(上例中的get方法),根据下标进行查找的时间复杂度总是O(1),而是根据关键字进行查找(上例中的find方法) ,需要迭代数组中的每一个元素进行查找,有一个专门的术语,称之为线性查找

这里我们往数组中存入对象,来说明根据关键字查找的含义


1. public class ArrayQueryTest {

2.     public static class User {

3.         private int id;
4.         private String name;
5.  
6.         public User(int id, String name) {

7.             this.id = id;
8.             this.name = name;
9.         }
10.  
11.         @Override
12.         public String toString() {

13.             return "User{" +
14.                     "id=" + id +
15.                     ", name='" + name + '\'' +
16.                     '}';
17.         }
18.     }
19.  
20.     public static void main(String[] args) {

21.         Array<User> userArray=new Array<User>(5);
22.         userArray.insert(new User(1,"tianshouzhi"));
23.         userArray.insert(new User(2,"wangxiaoxiao"));
24.         userArray.insert(new User(3,"huhuamin"));
25.  
26.         //根据user的id进行查找
27.         int queryKeyWord=2;
28.  
29.         User result=null;//查询结果
30.         for (int i = 0; i < userArray.size(); i++) {

31.             User user=userArray.get(i);
32.             if(queryKeyWord==user.id){

33.                 System.out.println(user);
34.                 break;
35.             }
36.         }
37.     }
38. }