一、介绍
数组可以存放多个同一类型的数据。数组也是一种数据类型,是引用类型。即:数(数据)组(一组)就是一组数据。
二、例子
package com.hspedu;
public class hen {
public static void main(String[] args) {
//1.double[]表示是double类型的数组,数组名是hens
//2.{3, 5, 1, 3.4, 2, 50}表示数组的值/元素,以此表示数组的第几个元素
double[] hens = {3, 5, 1, 3.4, 2, 50};
//数组可以通过for循环遍历。
//遍历得到数组的所有元素的和,使用for循环
for (int i = 0; i < 6; i++){
//因为数组是0基的
System.out.println("第" + (i+1) + "个元素的值=" + hens[i]);
}
//hens.length返回数组的长度
System.out.println("数组的长度是 " + hens.length);
}
}
三、数组的三种使用方式
1、动态初始化1
下面是动态初始化的例子:
import java.util.Scanner;
public class array {
public static void main(String[] args) {
//第一种动态分配方式
double[] scores = new double[5];
Scanner scanner = new Scanner(System.in);
//遍历输入数组元素
for (int i = 0; i < scores.length; i++){
System.out.println("请输入第" + (i+1) + "个元素的值");
scores[i] = scanner.nextDouble();
}
//输出遍历数组
System.out.println("数组的元素情况如下");
for (int i = 0; i <scores.length; i++){
System.out.println("第" + (i+1) + "个元素的值=" + scores[i]);
}
}
}
2、动态初始化2
import java.util.Scanner;
public class array {
public static void main(String[] args) {
//第二种动态分配方式,先声明,再new 分配空间
double scores[]; //声明数组,此时scores是null
scores = new double[5]; //分配了内存空间,可以存放数据
Scanner scanner = new Scanner(System.in);
//遍历输入数组元素
for (int i = 0; i < scores.length; i++){
System.out.println("请输入第" + (i+1) + "个元素的值");
scores[i] = scanner.nextDouble();
}
//输出遍历数组
System.out.println("数组的元素情况如下");
for (int i = 0; i <scores.length; i++){
System.out.println("第" + (i+1) + "个元素的值=" + scores[i]);
}
}
}
3、静态初始化
例子就是最上面的那个hens代码。
四、数组的使用细节
- 数组是多个相同类型数据的组合,实现对这些数据的统一管理。
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是二者不能混用。
- 数组创建后,如果没有赋值,有默认值:int0;short0;byte0;long0;float0.0;double0.0;boolean false; String null。
- 使用数组的步骤:1.声明数组并开辟空间 2.给数组各个元素赋值 3.使用数组
- 数组的下标是从0开始的。
- 数组下标必须在指定范围内使用,否则异常。eg:int arr[] = new int[5]; 则有效下标为0~4。
- 数组是引用类型,数组型数据是对象。
五、数组练习
1、创建一个char类型的26个元素的数组,分别访问'A'~'Z',使用for循环访问所有元素并打印出来。提示:char类型数据运算‘A’+1 -> 'B'。
package com.hspedu.array;
/*
创建一个char类型的26个元素的数组,分别访问'A'~'Z'
使用for循环访问所有元素并打印出来
提示:char类型数据运算‘A’+1 -> 'B'
1.定义一个数组
2.因为‘A’+1 -> 'B', 使用for循环赋值
3.使用for循环访问所有元素
*/
public class ArrayExercise01 {
public static void main(String[] args) {
char chars[] = new char[26];
//循环给chars[i]赋值
for (int i = 0; i < chars.length; i++){ //循环26次
chars[i] = (char)('A' + i); //'A' + i是int,需要强转
}
//循环输出
System.out.println("===chars数组===");
for (int i = 0; i < chars.length; i++){
System.out.println(chars[i]);
}
}
}
2、请求出一个数组int[]的最大值{4, -1, 9, 10, 23},并得到对应的下标。
package com.hspedu.array;
/*
请求出一个数组int[]的最大值{4, -1, 9, 10, 23},并得到对应的下标。
*/
public class ArrayExercise02 {
public static void main(String[] args) {
//1.定义一个int数组
//2.假定max=arr[0]是最大值,maxIndex=0
//3.从下标1开始遍历arr,如果max<当前元素,说明max不是真正的最大值
//我们就max=当前元素;maxIndex=当前元素下标
//4.当我们遍历整个arr后,max就是真正的最大值,maxIndex=最大值对应的下标
int[] arr = {4, -1, 9, 10, 23};
int max = arr[0]; //假定第一个元素就是最大值
int maxIndex = 0;
for (int i = 1; i < arr.length; i++){ //从下标1开始遍历arr
if (max < arr[i]){ //如果max < 当前元素
max = arr[i]; //把max设置成当前元素
maxIndex = i;
}
}
System.out.println("最大值是 " + max + "\t" + "最大值的下标是 " + maxIndex);
}
}
六、数组赋值机制
普通的值是拷贝赋值,n2的变化,不会影响到n1的值。
//基本数据类型赋值,赋值方式是拷贝
//n2的变化,不会影响到n1的值
int n1 = 10;
int n2 = n1;
n2 = 80;
System.out.println("n1=" + n1); //10
System.out.println("n2=" + n2); //80
然而,数组是引用赋值,赋的是地址:
package com.hspedu.array;
public class ArrayExercise03 {
public static void main(String[] args) {
//数组在默认情况下是引用传递,赋的值是地址,赋值方式为引用
//arr2变化会影响到arr1
int[] arr1 = {1,2,3};
//看看arr1的值
System.out.println("=====修改arr2前,arr1的元素=====");
for (int i = 0; i < arr1.length; i++){
System.out.println(arr1[i]);
}
//把arr1赋值给arr2
int[] arr2 = arr1;
arr2[0] = 10;
//看看修改arr2后,arr1的值
System.out.println("=====修改arr2后,arr1的元素=====");
for (int i = 0; i < arr1.length; i++){
System.out.println(arr1[i]);
}
}
}
拷贝赋值和引用赋值图解:
七、数组拷贝
如果我就想要某个数组的内容,而不是上面那样的地址赋值,就要用到数组拷贝。就是新new一个数组开辟空间,然后遍历拷贝赋值就行。
要求:将int[] arr1 = {10,20,30}; 拷贝到arr2数组,要求数据空间是独立的。
package com.hspedu.array;
public class ArrayCopy {
public static void main(String[] args) {
//将int[] arr1 = {10,20,30}; 拷贝到arr2数组,要求数据空间是独立的。
int[] arr1 = {10,20,30};
//先创建一个新的数组arr2,开辟新的数据空间
//大小 arr1.length
int[] arr2 = new int[arr1.length];
//遍历arr1,把每个元素拷贝到arr2对应的位置
for (int i = 0; i < arr1.length; i++){
arr2[i] = arr1[i];
}
}
}
八、数组反转
要求:把数组的元素内容反转。eg:arr{1,2,3,4,5} ---> arr{5,4,3,2,1}
1、通过找规律反转
package com.hspedu.array;
/*
1.通过找规律reverse
*/
public class ArrayReverse {
public static void main(String[] args) {
//定义数组
int[] arr = {11,22,33,44,55,66};
//1.把arr[0]和arr[5]进行交换 {66,22,33,44,55,11}
//2.把arr[1]和arr[4]进行交换 {66,55,33,44,22,11}
//3.把arr[2]和arr[3]进行交换 {66,55,44,33,22,11}
//4.一共要交换3次 = arr.length / 2
//5.每次交换时,对应的下标是arr[i]和arr[arr.length - 1 - i]
int temp = 0;
int len = arr.length;
for (int i = 0; i < arr.length/2; i++){
temp = arr[len - 1 - i]; //先保存在temp
arr[len - 1 - i] = arr[i];
arr[i] = temp;
}
System.out.println("===反转后的数组===");
for (int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
}
}
2、通过逆序赋值反转
package com.hspedu.array;
/*
2.通过逆序赋值反转
*/
public class ArrayReverse02 {
public static void main(String[] args) {
//定义数组
int[] arr1 = {11,22,33,44,55,66};
//1.先创建一个数组arr2,大小arr.length
//2.逆序遍历 arr1,将每个元素拷贝到arr2的元素中(顺序拷贝)
//3.增加一个循环变量
int[] arr2 = new int[arr1.length];
for (int i = arr1.length - 1, j = 0; i >= 0; i--, j++){
arr2[j] = arr1[i];
}
//4.当for循环结束,arr2就是一个逆序的数组{66,55,44,33,22,11}
//5.让arr1指向arr2数据空间,此时arr1原来的数据空间就没有使用了,会被当作垃圾销毁。
arr1 = arr2;
System.out.println("===arr2的内容===");
for (int i =0; i < arr1.length; i++){
System.out.println(arr1[i]);
}
}
}
九、数组添加
要求:实现动态的给数组添加元素,实现对数组扩容。
- 原始数组使用静态分配 int[] arr = {1,2,3}
- 增加的元素,直接放在数组的最后 arr = {1,2,3,4}
- 用户可以通过如下方法决定是否继续添加,添加成功,是否继续? y/n
package com.hspedu.array;
import java.util.Scanner;
/*
1.原始数组使用静态分配 int[] arr = {1,2,3}
2.增加的元素,直接放在数组的最后 arr = {1,2,3,4}
3.用户可以通过如下方法决定是否继续添加,添加成功,是否继续? y/n
*/
public class ArrayAdd {
public static void main(String[] args) {
//1.定义初始数组 int[] arr = {1,2,3}
//2.定义一个新的数组,int[] arrNew = new int[arr.length + 1];
//3.遍历arr数组,依次将arr的元素拷贝到arrNew数组
//4.将4拷贝给arrNew[arrNew.length - 1] = addNum; 把addNum赋给arrNew最后一个元素
//5.让arr指向arrNew;
//6.创建一个Scanner可以接受用户输入
//7.因为用户什么时候退出不确定,故使用do-while + break来控制
Scanner myScanner = new Scanner(System.in);
//初始化的数组
int[] arr = {1,2,3};
do {
int[] arrNew = new int[arr.length + 1];
//3.遍历arr数组,依次将arr的元素拷贝到arrNew数组
for (int i = 0; i < arr.length; i++) {
arrNew[i] = arr[i];
}
System.out.println("请输入你要添加的元素");
int addNum = myScanner.nextInt();
//把addNum赋值给arrNew的最后一个元素
arrNew[arrNew.length - 1] = addNum;
//让arr指向arrNew,原来的数组arr就没有使用了,被销毁
arr = arrNew;
//输出arr看看效果
System.out.println("===arr扩容后元素情况===");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
//问用户是否继续
System.out.println("是否继续添加y/n");
//Scanner是java.util包下的一个类,.next()是Sanner类下面的一个方法。
// .next()方法是接收用户输入的字符串,但Scanner类下面没有接收字符(.nextChar())的方法
//因此出现了charAt(int index),返回 char指定索引处的值。
//Scanner.next().charAt(0)具体含义就是,获取用户输入的字符串中的第一个字符。
char key = myScanner.next().charAt(0);
if (key == 'n'){ //如果输入n,就结束
break; //break就是跳出循环了
}
}while (true);
System.out.println("你退出了添加...");
}
}
十、排序
1、内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。
2、外部排序:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。
十一、冒泡排序法(Bubble Sorting)
基本思想:通过对待排序内容从后向前(从下标较大的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就像水底下的气泡一样逐渐向上冒。
案例:五个无序:24,69,80,57,13。使用Bubble Sorting将其排成一个从小到大的有序排列。
麻烦的写法:(这样写非常麻烦!!因此要嵌套for循环)
package com.hspedu.array;
public class BubbleSort {
public static void main(String[] args) {
//化繁为简,先死后活
/*
数组[24, 69, 80, 57, 13]
第一轮排序:目标把最大数放在最后
第1次比较[24, 69, 80, 57, 13]
第2次比较[24, 69, 80, 57, 13]
第3次比较[24, 69, 57, 80, 13]
第4次比较[24, 69, 57, 13, 80]
*/
int[] arr = {24, 69, 80, 57, 13};
int temp = 0; //用于辅助变换的变量
//第一轮排序,目标是把最大的数放最后
for (int j = 0; j < 4; j++){ //4次比较
//如果前面的数大于后面的数,就交换
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("===第1轮===");
for (int j = 0; j < arr.length; j++){
System.out.print(arr[j] + "\t");
}
System.out.println();
//第二轮排序:目标把第二大的数放后面
for (int j = 0; j < 3; j++){ //3次比较
//如果前面的数大于后面的数,就交换
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("===第2轮===");
for (int j = 0; j < arr.length; j++){
System.out.print(arr[j] + "\t");
}
System.out.println();
//第三轮排序:目标把第三大的数放在后面
for (int j = 0; j < 2; j++){ //2次比较
//如果前面的数大于后面的数,就交换
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("===第3轮===");
for (int j = 0; j < arr.length; j++){
System.out.print(arr[j] + "\t");
}
System.out.println();
//第四轮排序:目标把第四大的数放在后面
for (int j = 0; j < 2; j++){ //2次比较
//如果前面的数大于后面的数,就交换
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("===第4轮===");
for (int j = 0; j < arr.length; j++){
System.out.print(arr[j] + "\t");
}
System.out.println();
//第五轮排序:目标把第五大的数放在后面
for (int j = 0; j < 1; j++){ //1次比较
//如果前面的数大于后面的数,就交换
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("===第5轮===");
for (int j = 0; j < arr.length; j++){
System.out.print(arr[j] + "\t");
}
System.out.println();
}
}
for循环嵌套的写法:(从上面那种写法一步步推导过来的)
package com.hspedu.array;
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {24, 69, 80, 57, 13, -1, 100, 500};
int temp = 0; //用于辅助变换的变量
for (int i = 0; i < arr.length-1; i++){ //外层循环是四次
for (int j = 0; j < arr.length-1 - i; j++){ //4次比较:3次-2次-1次
//如果前面的数大于后面的数,就交换
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("===第"+(i+1)+"轮===");
for (int j = 0; j < arr.length; j++){
System.out.print(arr[j] + "\t");
}
System.out.println();
}
}
}
十二、数组中的查找
1、顺序查找
2、二分法查找
下面是顺序查找的例子,里面有一个编程技巧需要学习:
package com.hspedu.array;
import java.util.Scanner;
/*
有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王猜数游戏:
从键盘中任意输入一个名称,判断数列中是否包含此名称【顺序查找】
要求:如果找到了,就提示找到,并给出下标值
1.定义一个字符串数组
2.接受用户输入,遍历数组,逐一比较,如果有,则提示信息并退出
*/
public class SequenceSearch {
public static void main(String[] args) {
String[] names = {"白眉鹰王","金毛狮王","紫衫龙王","青翼蝠王"};
Scanner myScanner = new Scanner(System.in);
System.out.println("请输入名字");
String findName = myScanner.next();
//遍历数组,逐一比较,如果有就退出
//一种编程思想/技巧,经典用法
int index = -1;
for (int i = 0; i < names.length; i++){
if (findName.equals(names[i])){
System.out.println("恭喜你找到了 " + findName);
System.out.println("下标为= " + i);
//把i保存到index
index = i;
break;
}
}
if (index == -1){ //没有找到,都没有进入上面一个if循环
System.out.println("sorry, 没有找到 " + findName);
}
}
}