一、概念
1.什么是数组 2.为什么要用到数组
二、使用方法
1.声明并分配空间 2.赋值 3.处理数据
三、数组的各种应用
1.求数组中最大/最小值 2.数组反转和插值 3.三种排序方法 4.自由长度的数组 5.二分查找法
四、二维数组
1.声明并分配空间 2.赋值
一、概念
1.什么是数组
一组类型相同且长度固定的数据。
因为每种数据类型在内存空间中占据的大小不同,所以一个数组不能存放不同的数据类型。
2.为什么要用到数组
应对程序的各种需求,需要对多个同种数据进行打包处理。
二、使用方法
1.声明并分配空间
声明一个长度为5的整型数组:
int[] a = new int[5];
2.赋值
a[0] = 8;
赋值和声明也可以连写:
int[] scores = {89,79,76};
int[] scores = new int[]{89,79,76};
3.处理数据
a[0] = a[0]*10;
还有专门针对数组的循环——增强for循环:
int [] nums = {1,2,3,4};
for (int x : nums) {
// 循环体代码块
}
三、数组的各种应用
1.求数组中最大/最小值
public class Test1 {
public static void main(String[] args) {
// 求数组{5,9,8,7,2,4}里的最大值和最小值
int[] arr = {5, 9, 8, 7, 2, 4};
int max = arr[0];
int min = arr[0];
for (int i : arr) {
if (i > max) {
max = i;
}
if (i < min) {
min = i;
}
}
System.out.println("最大值为:" + max);
System.out.println("最小值为:" + min);
}
}
上述代码的执行结果:
最大值为:9
最小值为:2
分析:想象一场擂台赛,擂台的名字叫max/min。先默认,第一位选手(arr[0])是最强的,然后选手(数值)们依次(通过foreach循环)上台与当前最强的pk(判断大小)。如果获胜就占领擂台(max = i),直到最后一个站在台上的一个则是最大/最小的。
2.数组反转和插值
(1)数值反转
public class Test2 {
public static void main(String[] args) {
// 数值反转:将数组{{5,9,8,7,2,4}}的顺序反过来
int[] arr = {5, 9, 8, 7, 2, 4};
int mid;
for (int i = 1; i <= arr.length/2 ; i++) {
mid = arr[i-1];
arr[i-1] = arr[arr.length-i];
arr[arr.length-i] = mid;
}
for (int i:arr) {
System.out.print(i+" ");
}
}
}
上述代码的执行结果:4 2 7 8 9 5
分析:首先考虑,要将该数组倒过来,需要交换几次元素。此数组元素有6个,个数是偶数,需要调换6/2=3次。如果只有5个元素,只需调换(5-1)/2=2次,但我们可以利用java的int类型做除法时丢失精度的原理,直接用5/2=2次。所以无论数组的元素个数是单数还是双数,我们都可以用arr.length/2来得到要交换的次数。之后通过for循环即可以完成交换操作。
(2)插值
package Homework;
import java.util.Scanner;
public class Task9 {
/*9.定义一个有序数列,{1,5,20,30,80},
要求用户输入一个数字,然后插到数组中,并保持升序,不能使用冒泡排序。*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] arr = {1, 5, 20, 30, 80};
int num = 0;
System.out.print("请输入一个数字:");
int awr = sc.nextInt();
// 得到插入位置下标
for (int i = 0; i < arr.length; i++) {
if (awr > arr[i]) {
num++;
} else {
break;
}
}
int[] arrNew = new int[arr.length + 1];
// 插入下标之前的和原数组一一对应
for (int i = 0; i < arrNew.length; i++) {
if (i != num) {
arrNew[i] = arr[i];
} else {
break;
}
}
// 插入下标之后的和原数组错一位对应
for (int i = num; i < arrNew.length; i++) {
if (i == num) {
arrNew[num] = awr;
} else {
arrNew[i] = arr[i - 1];
}
}
// 输出数组
for (int i : arrNew) {
System.out.print(i+" ");
}
}
}
上述代码的执行结果:
请输入一个数字:25
1 5 20 25 30 80
3.三种排序方法
(1)冒泡排序
public class Test3 {
public static void main(String[] args) {
// 冒泡排序:将数组{{5,9,8,7,2,4}}从小到大进行排序
int[] arr = {5, 9, 8, 7, 2, 4};
int mid;
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j]>arr[j+1]){
mid = arr[j];
arr[j] = arr[j+1];
arr[j+1] = mid;
}
}
}
for (int i:arr) {
System.out.print(i+" ");
}
}
}
分析:冒泡排序的原理是从左到右让相邻的两个数进行比较,将较大者换到右边。外层的for决定来几次从左到右的比较,里层的for决定每次比较到几个数。
(2)选择排序
for (int i = 0; i <=arr.length-2 ; i++) {
int index = i;
for (int j = i+1; j <=arr.length-1 ; j++) {
if (arr[j]<arr[index])
index = j;
}
int mid = arr[i];
arr[i] = arr[index];
arr[index] = mid;
}
分析:外层for表示要比较的那个位置的下标,并假设那个位置的值是最小的。里层for表示要与之比较的位置的下标。比较之后得到实际最小值所在位置的下标,然后交换。
(3)快速排序
快速排序需要封装在函数方法里,因为要进行递归
public static void quickSort(int[] arr, int low, int high){
int i, j, temp, t;
if (low>high) {
return;
}
i = low;
j = high;
temp = arr[low];
while (i<j) {
while (arr[j]>=temp && i<j) {
j--;
}
while (arr[i]<=temp && i<j) {
i++;
}
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
arr[low] = arr[i];
arr[i] = temp;
quickSort(arr, low, j-1);
quickSort(arr, j+1, high);
}
分析:快速排序的核心思想是以最左边为基准位,左右两边分别派哨兵去查找比基准位大/小的数并交换位置,两个哨兵重合的位置就是基准位的数把数组左右两边分为比它小和比它大的两部分的位置。此时再将基准位的数换到重合位置来。左右两边再由此方法递归执行,即可完成整个数组的排序。
4.自由长度的数组
写在前面:我们都知道,java的数组在定义时长度就已经固定了,但是我们仍然可以通过一些方法让其达到类似自由长度的效果。
下面来看一个例子:
import java.util.Scanner;
public class Test4 {
public static void main(String[] args) {
// 输入任意数量的数,并将其放入一个数组
int[] arr = new int[0];
int[] arrNew;
Scanner sc = new Scanner(System.in);
int flag = 1;
// 通过循环来使arr数组逐渐变长
for (int i = 0;; i++) {
arrNew = new int[arr.length+1];
System.out.print("请输入第"+(i+1)+"个数:");
arrNew[i] = sc.nextInt();
for (int j = 0; j <arr.length ; j++) {
arrNew[j]= arr[j];
}
arr = arrNew;
System.out.print("是否继续输入:(1:继续; 0:停止)");
flag = sc.nextInt();
if (flag!=1) {
System.out.println("好的,停止输入。");
break;
}
}
for (int i:arr) {
System.out.print(i+" ");
}
}
}
分析:我们可以创建两个数组,用数组二来接收输入的数据,并使数组二每次循环都增加长度,而且将数组二多次赋值给数组一,从而达到数组一貌似在自增长的样子。
5.二分查找法
int low = 0, high = arr.length - 1; // 首先定义查找区间的最前端和最后端
while (true) {
int mid = (low+high)/2; //定义查找区间中间的数
// 判断中间的数比要查找的数大还是小
// 大则继续查找左半边
if (arr[mid] > key) {
high = mid-1;
} else if (arr[mid]<key) { // 小则继续查找右半边
low = mid+1;
} else { // 相等则直接确定
System.out.println("它在升序后数组的位置下标是:" + mid);
break;
}
// 查找区间头尾擦肩后,结束查询
if (low>high) {
System.out.println("抱歉,未找到该数。");
break;
}
}
分析:二分查找法的条件是必须是升序数组。首先将数组最中间的那个数与要查找的数进行比较,如果中间数较大,则继续比较左半边的数组的中间数,反之继续比较右半边的数组的中间数。以此类推,直到找到与要查找的数相等的数,或者当要查找的区间长度变为负数的时候终止输出未查找到。
四、二维数组
1.声明并分配空间
int[ ][ ] a = new int[ 5][ ]; // 要定义最大维数
2.赋值
int[ ][ ] a = {{1,2,3},{4,5,6},{7}};
两点注意:
1.二维数组的一维数组的真实长度可以超过预定长度
2.arr[0] = new int[]{1,2,3}; 中的new int[] 不可省略