目录
一维数组
二维数组
数组的排序及查找
冒泡排序
选择排序
数组元素一个一个查找
二分法查找
数组工具类
数组:
1、Java语言中的数组是一种引用数据类型。不属于基本数据类型,数组的父类是Object。
2、数组实际上是一个容器,可以容纳多个元素。(数组是一个数据的集合。)
数组:字面意思是“一组数据”。
3、数组当中可以存储“基本数据类型”的数据,也可以存储“引用数据类型”的数据。
4、数组因为是引用数据类型,所以数组对象是堆内存当中。(数组是存储在堆内存中的。)
5、数组当中如果存储的是“java对象”的话,实际上存储的是对象的“引用(内存地址)”,数组中不能直接存储java对象。
6、数组一旦创建,在Java中规定,长度不可变。(数组长度不可变)
7、数组的分类:一维数组、二维数组、多维数组...(一维数组较多,二维数组偶尔使用!)
8、所有的数组对象都有length属性(java自带的),用来获取数组中元素的个数。
9、java中的数组要求数组中的元素的类型统一。比如int类型数组只能存储int类型,Person类型数组只能存储Person类型。
10、数组在内存方面存储的时候,数组中的元素内存地址(存储的每一个元素都是有规则的挨着排序的)是连续的。内存地址连续。这是数组存储元素的特点(特色)。数组实际上是一种简单的数据结构。
11、所有的数组都是拿“第一个小方框的内存地址”作为整个数组对象的内存地址。
(数组中首元素的内存地址作为整个数组对象的内存地址。)
12、数组中每一个元素都是有下标的,下标从0开始,以1递增。最后一个元素的下标是:length - 1下标非常重要,因为我们对应数组中元素进行“存取”的时候,都需要通过下标进行。
13、数组这种数据结构的优点和缺点是什么?
优点:查询/查找/检索某个下标的元素时效率极高,可以说查询效率最高的一个数组结构。
为什么检索效率高?
第一:每一个元素的内存地址在空间存储上是连续的。
第二:每一个元素类型相同,所以占用空间大小一样。
第三:知道第一个元素内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式可以计算出某个下标上元素的内存地址,直接通过内存地址定位元素,所以数组的检索效率是最高的。
数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,
因为数组中元素查询的时候不会一个一个找,是通过数学表达式计算出来的。(算出一个
内存地址,直接定位点的。)
缺点:
第一:由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者添加元素的时候,效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作。
第二:数组不能存储大数据量,因为很难在内存空间上找到一块特别大的连续的内存空间。
注意:
对于数组中最后一个元素的增删,是没有效率影响的。
一维数组
1、怎么声明/定义一个一维数组?
语法格式:
int[] array1;
String[] array2;
2、怎么初始化一个一个一维数组呢?
包括两种方法:
* 静态初始化一维数组
语法格式:
int[] array = {100, 200, 300, 500};
* 动态初始化一维数组
语法格式:
int[] array = new int[5];
这里的"5"表示数组的元素个数。初始化一个5个长度的int类型数据,每一个元素int类型默认值0
什么时候采用静态初始化方式,什么时候使用动态初始化方式呢?
- 确定数组中存储哪些具体的元素时,采用静态初始化方式。
- 不确定将来数组中存储哪些数据,可以采用动态初始化方式,预先分配内存空间。
下面这种风格也可以,但是这是C++风格,不建议java中使用。
int array[] = {1, 100, 10, 20, 55, 234};
输出数组中的个数
System.out.println("数组中元素的个数是:" + array.length);
数组中每一个元素都有下标,通过下标对数组中的元素进行读和改。
System.out.println("第一个元素 = " + array[0]); //1 读
array[0] = 111; // 改
System.out.println("第一个元素 = " + array[0]); //111
读取数组最后一个元素
System.out.println("最后一个元素 = " + array[5]);
System.out.println("最后一个元素 = " + array[array.length - 1]);
【注意】当操作的下标超过数组最大下标的时候,会报ArrayIndexOutOfBoundsException异常,数组下标越界异常,一定要注意下标别越界
System.out.println(array[6]); // 抛出异常
遍历数组
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]); // i是从0 到5,是下标
}
数组还可以存一些引用类型,还可以用到多态的知识。
3、关于一维数组的扩容:
数组长度一旦确定不可变,那么数组满了,就需要扩容。
java中对数组的扩容时:
先新建一个大容量的数组,然后将小容量的数组中的数据一个一个的拷贝到大数组当中。
结论:
数组扩容效率较低。因为涉及到拷贝的问题,所以在以后开发中请注意:尽可能少的进行数组的拷贝。可以在创建数组对象的时候预估一些多长合适,最好预估准确,这样可以减少数组的扩容次数,提高效率。
调用System类中的arraycocy方法,来完成数组的拷贝
String[] stcs = {"hello", "word", "java", "oracle"};
String[] newStcs = new String[20];
System.arraycopy(stcs, 0, newStcs, 0, stcs.length);
for (int i = 0; i < newStcs.length; i++) {
System.out.println(newStcs[i]);
}
解读arraycocy方法(参数按顺序)
stcs是拷贝源(从这个数组中拷贝)
0 源数组中的起始位置
newStcs 目标数组。
0 目标数组中的起始位置。
stcs.length 要复制的数组元素的数量
基本数据类型也是类似。
二维数组
1、二维数组其实是一个特殊的一维数组,特殊在这个一维数组当中的每一个元素是一个一维数组。
2、三维数组是什么?
三维数组是一个特殊的二维数组,特殊在这个二维数组中每一个元素是一个一维数组。
实际开发中使用最多的就是一维数组,二维数组也很少使用,三维数组几乎不用。
3、二维数组静态初始化
int[][] array = {{1,1,1}, {2,3,4,5}, {0,0,0,0}};
int[][] a = {
{100, 200, 300},
{30, 20, 40, 50, 60},
{6, 7, 9, 1},
{0},
};
System.out.println(a.length); // 4
System.out.println(a[0].length); // 3
System.out.println(a[1].length); // 5
System.out.println(a[2].length); // 4
System.out.println(a[3].length); // 1
二维数组动态初始化(3个一维数组,每一个一维数组当中4个元素。)
int[][] ints = new int[3][4];
int[][] ints = new int[3][4]; System.out.println(ints.length); //3 System.out.println(ints[0].length); //4 System.out.println(ints[1].length); //4
关于二维数组中的元素的:读和写【注意别越界。】
a[二维数组中的一维数组的下标][一维数组的下标]
a[0][0] :表示第1个一维数组中的第1个元素。
a[3][10] : 表示第4个一维数组中的第11个元素。
【注意】:
对于a[3][10]来说,其中a[3]是一个整体,[10]是前面a[3]执行结束的结果然后再下标10.
System.out.println("第3个一维数组中第1个元素:" + a[2][0]); // 6
a[2][0] = 1000;
System.out.println(a[2][0]); //1000
遍历二维数组
for (int i = 0; i < a.length; i++) { // 外层循环3次。(负责纵向)
for(int j = 0; j < a[i].length; j++){
System.out.print(a[i][j] + " ");
}
System.out.println();
}
数组的排序及查找
冒泡排序
冒泡排序算法(以从小到大排序为例):
1、每一次循环结束之后,都要找到最大的数据,放到参与比较的这对数据的最右边。(冒出最大的那个气泡。)
2、核心:
拿着左边的数字和右边的数字对比,当左边 > 右边的时候,交换位置。
public class BubbleSort {
public static void main(String[] args) {
// 这是int类型的数组对象
int[] arr = {9, 8, 10, 7, 6, 0, 11};
int count1 = 0; // 计算循环比较次数
int count2 = 0; // 计算交换数据次数
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
count1++;
if (arr[j] > arr[j+1]){
int t;
t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
count2++;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("该数组冒泡排序循环比较次数为:" +count1); //21
System.out.println("该数组冒泡排序交换数据次数为:" + count2); //13
}
}
选择排序
选择排序算法(以从小到大排序为例):
1、每一次从这堆“参与比较的数据当中”找出最小值,拿着这个最小值和“参与比价的这堆最前的元素”交换位置。
2、选择排序比冒泡排序好在:每一次的交换位置都是有意义的。
3、关键点:选择排序中的关键在于,你怎么找出一堆数据中最小的。
public class SelectSort {
public static void main(String[] args) {
int[] arr = {9, 8, 10, 7, 6, 0, 11};
int count1 = 0; // 计算循环比较次数
int count2 = 0; // 计算交换数据次数
for (int i = 0; i < arr.length - 1; i++) {
int min = i;
for (int j = i+1; j < arr.length; j++) {
count1++;
if (arr[min] > arr[j]){
min = j; // 最小值的元素小标是j
}
}
if (min != i){
int temp;
temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
count2++;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("=================================");
System.out.println("该数组选择排序循环比较次数为:" +count1); //21
System.out.println("该数组选择排序交换数据次数为:" + count2); //5
}
}
两个排序对比:冒泡排序和选择排序实际上比较的次数没变。交换位置的次数减少了。
数组元素一个一个查找
一个一个挨着找,直到找到为止。
创建一个数组工具类ArrayUtil,添加静态方法arraySearch
public class ArrayUtil {
private static int arraySearch(int[] arr, int ele) {
for (int i = 0; i < arr.length; i++) {
if (ele == arr[i]){
return i;
}
}
return -1;
}
}
解析:从数组中检索某个元素的下标(返回的是第一个元素的下标。)
arr 被检索的数组 ,ele 被检索的元素
main中测试
int[] arr = {5, 6, 7, 89, 0};
int index = ArrayUtil.arraySearch(arr, 89);
System.out.println(index == -1 ? "该元素不存在!" : "该元素的下标为:" + index);
二分法查找
1、二分法查找(算法),这个效率较高。
2、二分法查找算法是基于排序的基础之上。(没有排序的数据是无法查找的。)
在数组工具类ArrayUtil,添加静态方法binarySearch
public class ArrayUtil {
private static int binarySearch(int[] arr, int dest) {
int begin = 0; // 开始下标
int end = arr.length - 1; // 结束下标
// 开始元素的下标只要在结束元素下标的左边,就有机会继续循环。
while (begin <= end){
int mid = (begin + end) / 2; // 中间元素下标
if (arr[mid] == dest){
return mid;
}else if (arr[mid] < dest){
begin = mid + 1; // 一直增
}else {
end = mid - 1; // 一直减
}
}
return -1;
}
}
解析:从数组中查找目标元素的下标
arr 被查找的数组(这个必须是已经排序的),dest 目标元素
返回值-1表示元素不存在,其它表示返回该元素的下标。
测试
int[] arr = {100, 200, 230, 260, 300, 350, 400};
int index = binarySearch(arr, 200);
System.out.println(index == -1 ? "该元素不存在!" : "该元素下标是:" + index);
数组工具类
SUN公司已经为我们写好了一个数组工具类:java.util.Arrays; 开发的时候要参考API帮助文档。
int[] arr = {3, 6, 5, 34, 1, 3, 5, 32};
Arrays.sort(arr); // 排序
// 遍历
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 二分法查找(建立在排序基础之上。)
int index = Arrays.binarySearch(arr, 5);
System.out.println(index == -1 ? "该元素不存在!" : "该元素下标是:" + index);


