数组
本文是学习笔记,参考资料为:
极客时间:链接
王争老师github:地址
菜鸟教程:添加链接描述
定义
数据(Array)是一种线性表数据结构,它用一组连续的内存空间,来存储一组具有相同类型的数据。
线性表:数据排列地像一条线的数据结构,线性表上的数据只有前和后两个方向。常见的线性表结构有链表,队列,栈。
非线性表:数据不像一条线进行排列,就是数据之间不只有简单的前后的关系。比如二叉树,堆和图。
连续的内存空间:数据在物理存储上是放在一起的,占据的位置是连续的一片。
相同类型:每个内存单元存储的东西是一个类型的。
特性
1、支持随机访问,其实一个数据的访问本质上就是要找到该数据的内存地址,因为知道元素的是放在一块的,所以说对于数组中的数据有以下寻址方式。
a[i]_address = base_address + i * data_type_size
2、删除和插入的操作比较低效,因为删除和插入之后,为了保持内存空间连续的特性,需要进行元素的移动。
最好情况:插入和删除的位置在数组末尾,此时时间复杂度为O(1)
最坏情况:插入和删除的位置在数组头部,此时时间复杂度为O(n)
平均情况:(1+2+3+…+n)/n = O(n)
注意点
- 数组的特性是支持随机访问,并不是支持随机查找,依据下标进行随机访问的时间复杂度为O(1),查找的时间复杂度是不确定的,排好序的数据的复杂度为log n ;
- 插入时,如果不需要保持原有的相对顺序的话,那么可以直接将插入的元素放在末尾,然后跟需要插入的位置的现有元素交换位置就行;
- 数组越界的问题,对于C语言这种需要自己指定内存的语言,警防数组越界造成的问题;
Java中的数组实现
1、一维数组
创建方式1:new
dataType[] arrayRefVar = new dataType[arraySize];
上面这行代码做了两件事儿,第一件是声明了arrayRefVar是一个dataType类型的数组,第二件是创建了一个arraySize大小的数组
创建方式2:直接赋值
dataType[] arrayRefVar = {value0, value1, ..., valuek};
创建方式3:前两者综合
dataType[] arrayRefVar = new dataType[arraySize]{value0,
value1, ..., valuek};
参考菜鸟教程的例子:Java 数组 | 菜鸟教程 (runoob.com)
public class TestArray {
public static void main(String[] args) {
// 数组大小
int size = 10;
// 定义数组
double[] myList = new double[size];
myList[0] = 5.6;
myList[1] = 4.5;
myList[2] = 3.3;
myList[3] = 13.2;
myList[4] = 4.0;
myList[5] = 34.33;
myList[6] = 34.0;
myList[7] = 45.45;
myList[8] = 99.993;
myList[9] = 11123;
}
}
2、多维数组(以二维数组为例)
多维数组可以看作是元素为数组的数组;
创建方式1:new
type[][] typeName = new type[typeLength1][typeLength2];
这种方式直接为每一维分配好了空间大小,type的类型可以是基本数据类型,也可以是引用数据类型
创建方式2:从最高维开始,分别为每一维分配空间
String[][] s = new String[2][];
s[0] = new String[2];
s[1] = new String[3];
s[0][0] = new String("Good");
s[0][1] = new String("Luck");
s[1][0] = new String("to");
s[1][1] = new String("you");
s[1][2] = new String("!");
3、 数组的工具类 Arrays
方法1:填充数组 fill
不指定范围的时候,就是全部填充了。
public static void fill(int[] a,
int fromIndex,
int toIndex,
int val)
方法2: 比较相等 equals
public static boolean equals(Object[] a,
Object[] a2)
如果两个指定的 Objects 数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。如果 (e1null ? e2null : e1.equals(e2)),则认为 e1 和 e2 这两个对象是相等的 。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。此外,如果两个数组引用都为 null,则认为它们是相等的。
方法3:升序排序 sort
public static <T> void sort(T[] a,
int fromIndex,
int toIndex,
Comparator<? super T> c)
参数:
a - 要排序的数组
fromIndex - 要排序的第一个元素的索引(包括)
toIndex - 要排序的最后一个元素的索引(不包括)
c - 确定数组顺序的比较器。null 值指示应该使用元素的自然顺序。
根据指定比较器产生的顺序对指定对象数组的指定范围进行排序。排序的范围从索引 fromIndex(包括)一直到索引 toIndex(不包括)。(如果 fromIndex==toIndex,则排序范围为空。)此范围内的所有元素都必须是通过指定比较器可相互比较的;
注意这种排序方法,对于基本的数据类型,排序的结果是升序,如果需要降序的话,只能自行进行数组的倒置(双指针法)
对于引用数据类型,可以按照自己定义的顺序来进行排列。
基本数组类型
public static void main(String[] args) {
int[] array = new int[]{1, 21, 3, 44, 5, 18};
System.out.print("排序前: ");
System.out.println(Arrays.toString(array));
Arrays.sort(array);
System.out.print("排序后: ");
System.out.println(Arrays.toString(array));
}
// 排序前: [1, 21, 3, 44, 5, 18]
// 排序后: [1, 3, 5, 18, 21, 44]
引用数据类型
package Array;
import java.util.Arrays;
public class SelfArray {
class Student {
int age;
String name;
Student(String _name, int _age) {
this.age = _age;
this.name = _name;
}
@Override
public String toString() {
return "[age=" + age + ", name=" + name + "]";
}
}
public static void main(String[] args) {
Student[] stu = new Student[4];
stu[0] = new SelfArray().new Student("dog", 4);
stu[1] = new SelfArray().new Student("cat", 15);
stu[2] = new SelfArray().new Student("fish", 2);
stu[3] = new SelfArray().new Student("wolf", 14);
System.out.println("排序前: ");
for (Student student : stu) {
System.out.println(student.toString());
}
// 经典写法
// Arrays.sort(stu, new Comparator<Student>() {
// @Override
// public int compare(Student s1, Student s2) {
// return s1.age - s2.age; // 从小到大排序,相减为负的在前面的
// }
// });
// lamda表达式的写法,升序
Arrays.sort(stu, ((o1, o2) -> o1.age - o2.age));
System.out.println("排序后: ");
for (Student student : stu) {
System.out.println(student.toString());
}
}
}
/**
排序前:
[age=4, name=dog]
[age=15, name=cat]
[age=2, name=fish]
[age=14, name=wolf]
排序后:
[age=2, name=fish]
[age=4, name=dog]
[age=14, name=wolf]
[age=15, name=cat]
**/
手动实现
package Array;
/**
* 数组的插入,删除,以及按照下标的访问
*/
public class Array {
public int[] data;
// 数组容量的大小
private int n;
// 当前的数组实际长度,用来判断插入以及删除是否合法等
private int count;
public Array(int n) {
this.n = n;
this.data = new int[n];
this.count = 0;
}
public Array() {
}
//插入元素:头部插入,尾部插入
public boolean insert(int value) {
if (count == n) {
System.out.println("数组空间已满!");
return false;
}
data[count] = value;
count++;
return true;
}
public boolean insert(int index, int value) {
if (index < 0 || index >= n) {
System.out.println("插入位置不合法");
return false;
}
if (count == n) {
System.out.println("数组空间已满");
return false;
}
for (int j = count; j > index; j--) {
data[j] = data[j - 1]; // 向后移位
}
data[index] = value;
count++;
return true;
}
//根据索引,找到数据中的元素并返回
public int find(int index) {
if (index < 0 || index >= n) {
System.out.println("索引位置有误");
return -1;
}
return data[index];
}
//根据索引,删除数组中元素
public boolean delete() {
if (count == 0) {
System.out.println("数组为空!");
return false;
}
count--;
return true;
}
public boolean delete(int index) {
if (count == 0) {
System.out.println("数组为空");
return false;
}
if (index < 0 || index >= n) {
System.out.println("索引不合法!");
return false;
}
for (int i = index + 1; i < count; i++) {
data[i - 1] = data[i]; // 向前移位
}
count--;
return true;
}
public void printAll() {
for (int i = 0; i < count; i++) {
System.out.print(data[i] + " ");
}
}
public static void main(String[] args) {
Array test = new Array(10);
test.insert(5);
test.insert(51);
test.insert(15);
test.insert(125);
test.insert(12555);
test.printAll();
}
}
// 5 51 15 125 12555