java手撸数据结构--数组(无序、有序、稀疏)
java手撸数据结构–数组(无序、有序、稀疏)
数组是java语言内置的数据类型,他是一个线性的序列,所以可以快速访问其他的元素,数组和其他语言不同,当你创建了一个数组时,他的容量是不变的,而且生命周期也是不能改变的,还有JAVA数组会做边界检查,如果发现有越界现象,会报RuntimeException异常错误,当然检查边界会以效率为代价。
数组的局限性分析
- 插入快:对于无序数组,即元素没有按照一定顺序排列,只是按照插入的顺序排列。无序数组增加一个元素很简单,只需要在数组末尾添加元素即可,但有序数组却不一定了,它需要在指定的位置插入。
- 查找慢:当然通过下标查找是很快的。但是通常我们都是根据元素值来查找的,给定一个元素值,对于无序数组,我们需要从数组的第一个元素还是遍历,直到找到那个元素。有序数组通过特定算法查找的速度会比无需数组快。
- 删除慢:根据元素值删除,我们要先找到该元素所在位置,然后将元素后端的值整体向前移动一个位置。也需要比较多的时间。
- 数组一旦创建,大小固定:如果初始化一个很大的数组大小,那会白白浪费内存空间,如果给小了,后面的数据个数增加了又添加不进去了。
很显然,数组虽然插入快,但是查找和删除比较慢,而且扩展性差,所以我们一般不会用数组来存储数据。
无序数组
无序数组,顾名思义,就是没有顺序的数组,即元素没有按照一定顺序排列,只是按照插入的顺序排列。
创建一个类来实现无序数组
class MyArray{ //存储具体数据的数组 int[] array; //当前数组存放数据数量 int size; //构造函数,初始化无序数组 public MyArray(int maxPage) { array = new int[maxPage]; size = 0; }}
1. 插入
/** * 插入 */ public void insert(int value) { if (size < array.length) { //数组未满,则插入 array[size++] = value; } }
2. 查找
/** * 查找返回下标 */ public int find(int value) { int i; for (i = 0; i < array.length; i++) { if (array[i] == value) { break; } } if (i == size) { System.out.println("数组中不存在当前数据"); return -1; } else { return i; } }
3. 删除
/** * 删除 */ public void delete(int value) { int j; if((j=this.find(value))>-1){ for (int i = j; i < size-1; i++) { array[i]=array[i+1]; } //删除完把记录-1 size--; } }
4. 遍历
/** * 遍历 */ public void forEach(){ for (int i = 0; i < size; i++) { System.out.print(array[i]+" "); } System.out.println(); }
5.测试
public static void main(String[] args) { MyArray myArray = new MyArray(10); myArray.insert(12); myArray.insert(5); myArray.insert(1); myArray.forEach(); myArray.delete(5); myArray.forEach(); }
值:
12 5 1 12 1
有序数组
有序数组优缺点分析
- 优点:
采用二分查找效率高,比无序数组效率高。 - 缺点:
插入的时候,要移动元素,比无序数组效率低。
创建一个类来实现有序数组
/** * 有序数组 */class MySequenceArray { //存储有序数组的集合 private int[] array; //元素数量 private int size; public MySequenceArray(int size) { array = new int[size]; size = 0; }}
查找
/** * 查找返回下标(二分查找) */ public int find(int value) { if (size == 0) { return -1; } int index; //当前比对的最大下标 int maxIndex = size - 1; // 当前比对的最小下标 int minIndex = 0; //当前下标 int currentIndex; while (true) { if (minIndex > maxIndex) { return -1; } currentIndex = (maxIndex + maxIndex) / 2; if (value == array[currentIndex]) { return currentIndex; } else if (value > array[currentIndex]) { minIndex = currentIndex + 1; } else { maxIndex = currentIndex - 1; } } }
插入
/** * 插入 */ public void insert(int value) { if (array.length > size) { int index; for (index = 0; index < size; index++) { if (value < array[index]) { //找到了 break; } } if (index < size) { //数组中存在比value大的数,则index以后的数向后移动一位 for (int i = size; i > index; i--) { array[i] = array[i - 1]; } //将value插入index处 array[index] = value; } else { //最后找不到比value大的数 array[index] = value; } size++; } }
删除
/** * 删除 */ public void delete(int value) { int index; if ((index = find(value)) > -1) { for (int i = index; i < size - 1; i++) { array[i] = array[i + 1]; } size--; } }
遍历
/** * 遍历 */ public void forEach() { for (int i = 0; i < size; i++) { System.out.print(array[i] + " "); } System.out.println(); }
测试
public static void main(String[] args) { MySequenceArray mySequenceArray = new MySequenceArray(10); mySequenceArray.insert(10); mySequenceArray.insert(1); mySequenceArray.insert(55); mySequenceArray.insert(3); mySequenceArray.forEach(); mySequenceArray.delete(3); mySequenceArray.delete(2); mySequenceArray.forEach(); }
1 3 10 55 1 10 55
稀疏数组
所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。
因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。
稀疏数组实现方式
如下:
- 方式一:二维数组存储,用空间换取时间,占用空间大,查询效率高
int[][] array = new int[7][9]; //占用63 array[1][1] = 3; array[3][0] = 1; array[3][1] = 4; array[4][2] = 7; array[5][5] = 5;
遍历
for (int i = 0; i < array.length; i++) { for (int j = 0; j < array[i].length; j++) { System.out.print(array[i][j] + " "); } System.out.println(); }
遍历值如下:
0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 4 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0
- 方式二:使用压缩方式,执行效率较低,占用空间小
创建一个类来实现稀疏数组
/** * 稀疏数组实现 */class MySparseArray{ //稀疏数组的行数 private int row; //稀疏数组的列数 private int col; //稀疏数组当前行当前列的值 private int val; //通过构造函数实例化 public MySparseArray(int row, int col, int val) { this.row = row; this.col = col; this.val = val; } public int getRow() { return row; } public int getCol() { return col; } public int getVal() { return val; }}
稀疏数组的使用
//定义五个节点的稀疏数组,这里的6不包含第一行记录 MySparseArray[] mySparseArrays = new MySparseArray[6]; //第一行为记录行数、列数、节点数,下标为0 //7行、9列 mySparseArrays[0] = new MySparseArray(7, 9, 6); mySparseArrays[1] = new MySparseArray(1, 1, 3); mySparseArrays[2] = new MySparseArray(3, 0, 1); mySparseArrays[3] = new MySparseArray(3, 1, 4); mySparseArrays[4] = new MySparseArray(4, 2, 7); mySparseArrays[5] = new MySparseArray(5, 5, 5); // 遍历 for (int i = 0; i < mySparseArrays[0].getRow(); i++) { for (int j = 0; j < mySparseArrays[0].getCol(); j++) { int k;//这个字段用来记录有值的下标 //第一行记录为0,要跳过第一行 for (k = 1; k < mySparseArrays.length; k++) { if (mySparseArrays[k].getRow() == i && mySparseArrays[k].getCol() == j) { break; } } if (k < mySparseArrays.length) { System.out.print(mySparseArrays[k].getVal() + " "); } else { System.out.print(0 + " "); } } //换行 System.out.println(); }
值为:
0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 4 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0