1、什么是数组
数组:数组是一种数据结构,在内存中是一块连续的空间,俗称为容器。
数组的特点:
①元素是连续存储的,每个元素都有自己的编号,通常称为下标。(因为有下标,故访问效率快)
②数组长度一旦确定,就不可更改。
2、什么时候用数组
当我们需要同时管理一组相同数据类型的数据时,采用数组,比采用多个同类型的变量要简单的多。
案例:
public class TestArray {
public static void main(String[] args) {
//需求:存储5个同学的成绩
int s1 = 89;
int s2 = 96;
int s3 = 76;
int s4 = 98;
int s5 = 60;
//对它们进行数据管理:输出显示、找最高分、最低分、排序等 ==> 非常麻烦
System.out.println("s1 = " + s1);
System.out.println("s2 = " + s2);
System.out.println("s3 = " + s3);
System.out.println("s4 = " + s4);
System.out.println("s5 = " + s5);
int max = s1 > s2 ? s1 : s2;
max = max > s3 ? max : s3;
max = max > s4 ? max : s4;
max = max > s5 ? max : s5;
System.out.println("max = " + max);
int[] score = {89, 96, 76, 98, 60};
//输出5个分数,找最高分
max = score[0];
for (int i = 0; i < score.length; i++) {
if(score[i]>max){
max = score[i];
}
System.out.print(score[i]+" ");
}
System.out.println("max = " + max);
}
}
3、如何使用数组
3.1 声明数组的语法格式
元素的类型[] 数组名;
例如:
//存储一组商品的价格
double[] prices;
//存储一组同学的姓名
String[] names;
//存储26个英文字母
char[] letters;
3.2 数组的初始化
(1)静态初始化
在写代码时,直接确定了数组的元素。
数组名 = new 元素的类型[]{元素1,元素2,....};
当声明与静态初始化在一个语句时,可以简略成:
元素的类型[] 数组名 = {元素1,元素2,....};
案例:
public class TestArray {
public static void main(String[] args) {
// String[] names;
// names = new String[]{"熊大","熊二","光头强","吉吉"};
String[] names = {"熊大","熊二","光头强","吉吉"};
System.out.println(names.length);//4
for (int i = 0; i < names.length; i++) {
System.out.println("第" + (i+1) +"个元素的值是:" + names[i]);
}
}
}
(2)动态初始化
在程序运行时,才确定元素的值。
数组名 = new 元素的类型[长度];
数组名[下标] = 值;
案例
import java.util.Scanner;
public class TestArray {
public static void main(String[] args) {
//从键盘输入5个同学的名字
String[] names = new String[5];
Scanner input = new Scanner(System.in);
for(int i=0; i<names.length; i++) {
System.out.print("请输入第"+(i+1)+"个同学的姓名:");
names[i] = input.next();
}
//统一输出显示
System.out.println("5个同学的名字如下:");
for (int i = 0; i < names.length; i++) {
System.out.print(names[i]+" ");
}
input.close();
}
}
3.3 数组的遍历
使用for循环变量数组的场景是最多。当然,其实也可以使用while,或do-while。
for(int i=0; i<数组名.length; i++){
//.....
}
3.4 数组的内存分析
-
为什么打印数组名看不到元素?
-
因为数组名里面存储了数组对象的首地址
-
-
为什么需要用下标来访问元素?
-
因为数组有多个元素,每一个元素只能通过编号进行区分
-
-
为什么下标从0开始?
-
访问第1个元素的时候,不需要跨过任何单元格
-
访问第2个元素的时候,需要 首地址 + 1 * 每一个单元格的宽度 计算该元素的地址
-
访问第3个元素的时候,需要 首地址 + 2 * 每一个单元格的宽度 计算该元素的地址
-
下标相当于从首地址开始,需要跨过几个单元格来访问当前元素
-
元素的类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0 |
char | \u0000 或 编码值为0的字符 |
boolean | false |
String等引用数据类型 | null |
3.5 两个数组or1个数组
4 二维数组
一维数组,即[],是用来存储一组数据的。例如:存储1个小组的学员信息
二维数组,即[][],是用来存储多组数据的 。例如:存储咱们班5个小组的学员信息
4.1 声明数组
元素的类型[][] 数组名;
4.2 数组的初始化
(1)静态初始化
元素的类型[][] 数组名 = {{第一组数据},{第二组数据},{第三组数据}};
public class ArrayPlus {
public static void main(String[] args) {
int[][] scores = {{89, 96, 76, 98, 60}, {99,100,98}, {7,8,9,6}};
for (int i = 0; i < scores.length; i++) {//scores.length=3
// System.out.println(scores[i]);//看到首地址
//scores[i]也是一个一维数组
/*
i=0, scores[i].length=5
i=1, scores[i].length=3
i=2, scores[i].length=4
*/
for (int j = 0; j < scores[i].length; j++) {
System.out.print(scores[i][j]+" ");
//[i]是行下标,定位行,或者 组
// [j]是列下标,定位列,在组中第几个
}
System.out.println();
}
}
}
(2)动态初始化
-
规则的矩阵
元素的类型[][] 数组名 = new 元素的类型[共有几行][每一行共有几个元素];
/*
1 2 3 4 5 第一组
6 7 8 9 10 第二组
11 12 13 14 15 第三组
每一组的元素个数相同
*/
public class ArrayPlus {
public static void main(String[] args) {
int[][] nums = new int[3][5];//3代表有3组,5代表每一组有5个元素
int a = 1;
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < nums[i].length; j++) {
nums[i][j] = a;
a++;
System.out.print(nums[i][j]+"\t");
}
System.out.println();
}
}
}
-
不规则矩阵
元素的类型[][] 数组名 = new 元素的类型[共有几行][]; //此时只确定了有几组,但是每一组有几个元素是待定
数组名[行下标] = new 元素的类型[这一组有几个元素];
/*
从键盘输入:
86,96,12
75,63
52
*/
public class ArrayPlusDemo3 {
public static void main(String[] args) {
int[][] nums = new int[3][];
nums[0] = new int[6];//第1组有6个元素
nums[1] = new int[5];//第2组有5个元素
nums[2] = new int[7];//第3组有7个元素
//如果是数组名后面[数字],就一定是下标,下标的范围[0, 长度-1]
//如果是数据类型后面[数字],就一定是长度
nums[0][0] = 86;
nums[0][1] = 96;
nums[0][2] = 12;
nums[1][0] = 75;
nums[1][1] = 63;
nums[2][0] = 52;
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < nums[i].length; j++) {
System.out.print(nums[i][j]+" ");
}
System.out.println();
}
}
}
4.3 遍历
for(int i=0; i<二维数组名.length; i++){
for(int j=0; j<二维数组名[i].length; j++){
//二维数组名[i][j]
}
}
4.4 二维数组的内存分析
5 数组的基本算法
算法:解决问题的步骤
常见的数组算法:
(1)统计数组中元素满足xx条件的个数情况,例如:数组中偶数的个数、3的倍数的个数、素数的个数、完数的个数、水仙花的个数
(2)统计数组元素的总和、平均值
(3)查找数组元素的最大值、最小值
(4)对数组进行反转
(5)在数组中查找某个值是否存在
(6)数组的排序
。。。。。。
5.1 统计分析元素情况
案例:随机产生10个[0,100)的整数,然后统计这些随机数中偶数的个数、3的倍数各有多少个?
//随机产生10个[0,100)的整数,然后统计这些随机数中偶数的个数、3的倍数各有多少个?
public static void test(){
int[] arr = new int[10];
int oushu=0;
int beishu=0;
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random()*100);
if (arr[i] % 2 == 0){
oushu++;
}
if (arr[i]%3==0){
beishu++;
}
System.out.print(arr[i]+" ");
}
System.out.println("---------");
System.out.println(oushu);
System.out.println(beishu);
}
5.2 统计总和、平均值
案例:随机产生5个[0,100)的整数,求它们的平均值
//案例:随机产生5个[0,100)的整数,求它们的平均值
public static void test(){
int[] arr = new int[10];
int sum=0;
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random()*100);
sum+=arr[i];
System.out.print(arr[i]+" ");
}
System.out.println();
System.out.println("平均数:"+sum/ arr.length);
}
5.3 找最大值、最小值
//案例:随机产生5个[0,100)的整数,求它们的平均值
//方法-
public static void test() {
int[] arr = {4, 5, 6, 11, 9};
//第一步:假设第1个元素的值最大/最小
int max = arr[0];
int min = arr[0];
//第二步:用后面的元素逐一与max比较,有比max大的,就修改max变量的值
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
if (arr[i] < min) {
min = arr[i];
}
}
System.out.println("max = " + max);
System.out.println("min = " + min);
}
//方法二
public static void test2(){
int[] arr = {4, 5, 6, 11, 9};
//第一步:假设第1个元素的值最大/最小
int max = 0;
int min = 0;
for (int i = 0; i < arr.length; i++) {
if (i==0){
max=arr[0];
min=arr[0];
}else if(arr[i] > max){
max = arr[i];
}else if(arr[i] < min){
min = arr[i];
}
}
System.out.println("max = " + max);
System.out.println("min = " + min);
}
5.4 找最大值及其下标位置
(1)元素不重复情况下
//方法-
public static void test() {
int[] arr = {4,5,6,11,9};
//需求:找出最大值是多少,并且确定它的下标位置
int max = arr[0];
//这个变量用来存储下标
int index = 0;
for (int i = 1; i < arr.length; i++) {
if(arr[i] > max){
max = arr[i];
index = i;
}
}
System.out.println("max = " + max);
System.out.println("index = " + index);
}
//方法二
public static void test2(){
int[] arr = {4, 5, 6, 11, 9};
int index=0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] > arr[index]){
index=i;
}
}
System.out.println("max = " + arr[index]);
System.out.println("index = " + index);
}
(2)元素重复情况下
//方法-
//基础思路:
//(1)先找出最大值
//(2)在遍历一遍,看哪些元素和最大值一样,打印它们的下标
public static void test() {
int[] arr = {4, 5, 2, 6, 11, 9, 11};
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
System.out.println("max = " + max);
System.out.println("max对应的下标有:");
for (int i = 0; i < arr.length; i++) {
if (arr[i] == max) {
System.out.print("[" + i + "] ");
}
}
System.out.println();
}
//方法二
public static void test2() {
int[] arr = {4, 5, 2, 6, 11, 9, 11};
int max=arr[0];
String str = "0";
for (int i = 0; i < arr.length; i++) {
if (arr[i]>max){
max=arr[i];
str=i+"";
}else if (arr[i] == max){
str+=","+i;
}
}
System.out.println("max = " + max);
System.out.println("下标有:" + str);
}
5.5 数组反转
//方法-
public static void test() {
int[] arr = {5, 6, 8, 7, 21};
//思路一:借助一个同等长度的数组(功能没问题,缺点就是需要同等大小的数组空间)
int[] arrNew = new int[arr.length];
//倒着复制元素
for (int i = 0; i < arr.length; i++) {
arrNew[arr.length-1-i]=arr[i];
}
arr = arrNew;
//查看结果
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
//方法二
public static void test2() {
//首尾对应位置交换法
int[] arr = {4, 5, 2, 6, 11, 9, 11};
int left =0;
int right =arr.length-1;
while (left<right){
int temp = arr[left];
arr[left] =arr[right];
arr[right]=temp;
left++;
right--;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
5.6 数组的查找之顺序查找
//方法-
public static void test() {
int[] arr = {5, 6, 8, 7, 21};
int target = 10;
//判断target是不是数组中的一个元素
boolean flag = false;//false在这里代表没找到
for (int i = 0; i < arr.length; i++) {
if(arr[i] == target){
flag = true;//true代表找到了
break;//停止查找
}
}
if(flag){//if(flag==true) {
System.out.println("找到了");
}else{
System.out.println("没找到");
}
}
//方法二
public static void test2() {
//首尾对应位置交换法
int[] arr = {4, 5, 2, 6, 11, 9,10, 11};
int target = 10;
//判断target是不是数组中的一个元素
int index = -1;//index代表下标。 -1代表不存在
for (int i = 0; i < arr.length; i++) {
if(arr[i] == target){
index = i;
break;//停止查找
}
}
if(index != -1){
System.out.println("找到了,它的位置:" + index);
}else{
System.out.println("没找到");
}
}
如果如果数组是有序的,优化查找
顺序查找
public static void test() {
int[] arr = {5, 6, 8, 7, 21};
int target = 10;
int index = -1;
for (int i = 0; i < arr.length; i++) {
if(arr[i] == target){
index = i;
break;
}else if(arr[i] > target){
break;
}
}
System.out.println(index==-1?"不存在":"存在");
}
二分查找
ublic static void test2() {
int[] arr = {4, 5, 2, 6, 11, 9, 10, 11};
int target = 10;
int left = 0;
int right = arr.length - 1;
int index = -1;
while (left < right) {
int mid = left + (right - left) / 2; //防止left+right过大数据溢出
if (arr[mid]>target){
right = mid-1;
} else if (arr[mid] < target) {
left=mid+1;
}else {
index=mid;
break;
}
}
System.out.println(index == -1 ? "不存在" : "存在");
}
5.7 冒泡排序
以从小到大排序过程为例,简单的描述冒泡排序的过程:
-
每一轮,从头开始,通过==相邻元素比较==来实现排序。当前面的元素>后面的元素时,就交换它们。每一轮下来,可以保证本轮参与的所有元素中最大值会被交换到它应该在的位置。==n个元素经过n-1轮==之后,实现最终排序。
public static void test() {
int[] arr = {5, 6, 8, 7, 21, 23, 1, 2, 8}; // 定义要排序的数组
// 外层循环控制趟数,每趟将一个最大的数放到末尾
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]) { // 如果前一个元素大于后一个元素,则交换它们
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}