一:定义
数组:把一些数据码成一排进行存放
Java中提供的数组具有一定的局限:索引可以是有语意,也可以是没有语意的。比如像上文我们提供数组,是按成绩最后一个位当作索引来存还是随机存放在数组中呢?当然,并非所有有语意的索引都适应与数组。例如身份证号:11010319852166666,若我们要存放在数组中,这个数字很大又很浪费,不知道要以什么索引来存放。这一篇文章主要处理没有索引语意的情况。
那么,接下来我们就制作属于我们的自己的数组。需要解决如下几个问题:
索引没有语意,如何表示没有元素?
如何添加元素,如何删除元素?如何修改,插入元素等等。
二:制作属于自己的数组
2.1 向数组中添加元素,相当于在数组末添加元素
2.2 向指定位置添加元素
2.3 向指定位置删除元素
删除索引为1的元素
最后指向size这个位置的数组没必要删掉,因为我们设置了size,所以访问不到
2.4 实现代码~
1 public class Array { 2 private int []data; 3 private int size; 4 //构造函数,传入数组的实际容量capacity构造函数Array 5 public Array(int capacity) 6 { 7 data = new int[capacity]; 8 size = 0; 9 } 10 //构造无参函数,采取默认数组的容量capacity 11 public Array() 12 { 13 data = new int[10]; 14 size = 0; 15 } 16 //获取数组的容量(长度) 17 public int getCapacity() 18 { 19 return data.length; 20 } 21 //获取数组的元素个数 22 public int getSize() 23 { 24 return size; 25 } 26 //返回数组是否为空 27 public boolean isEmpty() 28 { 29 return size == 0; 30 } 31 //在index索引的位置插入一个新元素e 32 public void add(int index , int e) 33 { 34 //判断当前数组是否为满 35 if(size == data.length) 36 { 37 throw new IllegalArgumentException("Add failded. Array is full "); 38 } 39 //判断插入位置是否合法 40 if(index < 0 || index > size ) 41 { 42 throw new IllegalArgumentException("Add failded . Require index >= 0 and index <= size."); 43 } 44 for(int i = size - 1 ;i>=index;i--) 45 { 46 data[ i + 1] = data[i]; 47 } 48 data[index] = e; 49 size++; 50 } 51 //在向所有元素后添加一个新元素 52 public void addLast(int e) 53 { 54 add(size,e); 55 } 56 //在所有元素前添加一个元素 57 public void addFirst(int e ) 58 { 59 add(0,e); 60 } 61 //获取index索引位置的元素 62 public int get(int index) 63 { 64 if(index < 0 || index >= size) 65 { 66 throw new IllegalArgumentException("Add failded. Index is illegal. "); 67 } 68 return data[index]; 69 } 70 //修改index索引位置的元素为e 71 public void set(int index,int e) 72 { 73 if(index < 0 || index >= size) 74 { 75 throw new IllegalArgumentException("Add failded. Index is illegal. "); 76 } 77 data[index] = e; 78 } 79 //查找数组中是否有元素e 80 public boolean contains(int e) 81 { 82 for(int i = 0;i<size;i++) 83 { 84 if(data[i] == e) 85 { 86 return true; 87 } 88 } 89 return false; 90 } 91 //查找数组中元素e所在的索引,如果不存在元素e,则返回-1 92 public int find(int e) 93 { 94 for(int i = 0;i<size;i++) 95 { 96 if(data[i] == e) 97 { 98 return i; 99 } 100 } 101 return -1; 102 } 103 //从数组中删除index位置的元素,返回删除的元素 104 public int remove(int index) 105 { 106 if(index < 0 || index >=size) 107 { 108 throw new IllegalArgumentException("Remove failed. Index is illegal."); 109 } 110 int temp = data[index]; 111 for(int i = index;i<size;i++) 112 { 113 data[i] = data[i+1]; 114 } 115 size--; 116 return temp; 117 } 118 //从数组中删除第一个元素,返回删除的元素 119 public int removeFirst() 120 { 121 return remove(0); 122 } 123 //从数组中删除最后一个元素,返回删除的元素 124 public int removeLast() 125 { 126 return remove(size - 1 ); 127 } 128 //从数组中删除元素e 129 public void removeElement(int e) 130 { 131 int index = find(e); 132 if(index!=-1) 133 { 134 remove(index); 135 } 136 137 } 138 //打印Array格式 139 @Override 140 public String toString() 141 { 142 StringBuilder res = new StringBuilder(); 143 res.append(String.format("Array size = %d , capacity = %d\n",size,data.length)); 144 res.append('['); 145 for(int i = 0;i<size;i++) 146 { 147 res.append(data[i]); 148 if(i!=size-1) 149 { 150 res.append(","); 151 } 152 } 153 res.append(']'); 154 return res.toString(); 155 } 156 }
三:改进版的动态数组
上面我们创建的数组是静态数组,也就是长度是固定的~当我们的数组长度不够怎么办或者我们不知道要创建多大的数组怎么办?那么我们就要创建一个动态数组
思路:
1、当data数组不够用的时候,那么我们创建一个比当前数组newData大一倍的数组
2、将当前数组的元素全部复制一份到newData
3、把data指向newData,完成~
这里存在1个疑问:
1、为什么要创建一个比我们原先的数组大一倍,而直接在原来的基础上增加100 or 1000的长度呢?
因为有时候我们创建100或者1000,可能不需要这么大的空间,而且还有一个可能就是我们创建太小的话,可能需要多次从原来的数组复制到另外一个数组上,这样的频率会比较高,很浪费空间。
2、当我们正在删除元素的时候,发现删除之后数组的空间利用率比较小的时候,我们可以尝试把容积变小
if(size == data.length / 2) { resize(data.length/2); } return ret;
3、实现代码:
1 public class Array { 2 3 private int[] data; 4 private int size; 5 6 // 构造函数,传入数组的容量capacity构造Array 7 public Array(int capacity){ 8 data = new int[capacity]; 9 size = 0; 10 } 11 12 // 无参数的构造函数,默认数组的容量capacity=10 13 public Array(){ 14 this(10); 15 } 16 17 // 获取数组的容量 18 public int getCapacity(){ 19 return data.length; 20 } 21 22 // 获取数组中的元素个数 23 public int getSize(){ 24 return size; 25 } 26 27 // 返回数组是否为空 28 public boolean isEmpty(){ 29 return size == 0; 30 } 31 32 // 在index索引的位置插入一个新元素e 33 public void add(int index, int e){ 34 35 if(index < 0 || index > size) 36 throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size."); 37 38 if(size == data.length) 39 resize(2 * data.length); 40 41 for(int i = size - 1; i >= index ; i --) 42 data[i + 1] = data[i]; 43 44 data[index] = e; 45 46 size ++; 47 } 48 49 // 向所有元素后添加一个新元素 50 public void addLast(int e){ 51 add(size, e); 52 } 53 54 // 在所有元素前添加一个新元素 55 public void addFirst(int e){ 56 add(0, e); 57 } 58 59 // 获取index索引位置的元素 60 public int get(int index){ 61 if(index < 0 || index >= size) 62 throw new IllegalArgumentException("Get failed. Index is illegal."); 63 return data[index]; 64 } 65 66 // 修改index索引位置的元素为e 67 public void set(int index, int e){ 68 if(index < 0 || index >= size) 69 throw new IllegalArgumentException("Set failed. Index is illegal."); 70 data[index] = e; 71 } 72 73 // 查找数组中是否有元素e 74 public boolean contains(int e){ 75 for(int i = 0 ; i < size ; i ++){ 76 if(data[i] == e) 77 return true; 78 } 79 return false; 80 } 81 82 // 查找数组中元素e所在的索引,如果不存在元素e,则返回-1 83 public int find(int e){ 84 for(int i = 0 ; i < size ; i ++){ 85 if(data[i] == e) 86 return i; 87 } 88 return -1; 89 } 90 91 // 从数组中删除index位置的元素, 返回删除的元素 92 public int remove(int index){ 93 if(index < 0 || index >= size) 94 throw new IllegalArgumentException("Remove failed. Index is illegal."); 95 96 int ret = data[index]; 97 for(int i = index + 1 ; i < size ; i ++) 98 data[i - 1] = data[i]; 99 size --; 100 if(size == data.length / 2) 101 resize(data.length / 2); 102 return ret; 103 } 104 105 // 从数组中删除第一个元素, 返回删除的元素 106 public int removeFirst(){ 107 return remove(0); 108 } 109 110 // 从数组中删除最后一个元素, 返回删除的元素 111 public int removeLast(){ 112 return remove(size - 1); 113 } 114 115 // 从数组中删除元素e 116 public void removeElement(int e){ 117 int index = find(e); 118 if(index != -1) 119 remove(index); 120 } 121 122 @Override 123 public String toString(){ 124 125 StringBuilder res = new StringBuilder(); 126 res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length)); 127 res.append('['); 128 for(int i = 0 ; i < size ; i ++){ 129 res.append(data[i]); 130 if(i != size - 1) 131 res.append(", "); 132 } 133 res.append(']'); 134 return res.toString(); 135 } 136 137 // 将数组空间的容量变成newCapacity大小 138 private void resize(int newCapacity){ 139 140 int[] newData = new int[newCapacity]; 141 for(int i = 0 ; i < size ; i ++) 142 newData[i] = data[i]; 143 data = newData; 144 } 145 }
这二段代码其实本质没发生多大变化,只是修改个别东西!
四、总结
数组最大的优点:快速查询,最好应用于“索引有语意”的情况。
增、删 的时间复杂度为:O(n)。
改、查 在未知索引的情况下时间复杂度为:O(n), 在已知索引的情况下时间复杂度为:O(1)。