一、基于一维数组的一些算法
1、对数组的元素统计分析
案例需求
需求:随机产生10个[0,100)整数放到一个数组中,统计他们的总和,平均值。
public class ArrayArithmetic1 {
public static void main(String[] args) {
//需求:随机产生10个[0,100)整数放到一个数组中,统计他们的总和,平均值
//(1)声明一个int[]数组,长度为10
int[] arr = new int[10];
//随机产生10个[0,100)整数放到arr数组中
int sum = 0;
double avg = 0.0;
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random()*100);
sum += arr[i];
System.out.println(arr[i]);
}
System.out.println("总和:" +sum);
// avg = sum/arr.length;// int/int 结果是int,然后升级为double
avg = (double)sum/arr.length; //对sum提升为double
System.out.println("平均值:" + avg);
}
}
案例需求
需求:随机产生10个[0,100)整数放到一个数组中,统计他们中3的倍数的个数、5的倍数的个数。
public class ArrayArithmetic2 {
public static void main(String[] args) {
//需求:随机产生10个[0,100)整数放到一个数组中,统计他们中3的倍数的个数、5的倍数的个数
//(1)声明一个int[]数组,长度为10
int[] arr = new int[10];
//随机产生10个[0,100)整数放到arr数组中
int three = 0;
int five = 0;
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random()*100);
System.out.print(arr[i]);
/*if(arr[i] % 3 == 0){
three++;
}else if(arr[i] % 5 == 0){
five++;
}*///不对,如果满足3和5的倍数,只统计了3的倍数
if(arr[i] % 3 == 0){
three++;
System.out.print("\t 3的倍数");
}
if(arr[i] % 5 == 0){
five++;
System.out.print("\t 5的倍数");
}
System.out.println();
}
System.out.println("three = " + three);
System.out.println("five = " + five);
}
}
2、在数组中找最大值
假设第一个元素最大
案例需求:随机产生10个[0,100)整数放到一个数组中,找出他们当中的最大值。
public class ArrayArithmetic3 {
public static void main(String[] args) {
//(1)声明一个int[]数组,长度为10
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 100);
System.out.print(arr[i]+" ");
}
System.out.println();
/*
找出最大值:
(1)先假设第一个元素最大,用max记录该值
(2)后续的元素一一与max变量比较,有比max还大的,修改max的值
*/
int max = arr[0];
for(int i=1; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
}
System.out.println("max = " + max);
}
}
把max初始化为一个比他们都小的数
public class ArrayArithmetic4 {
public static void main(String[] args) {
//案例需求:随机产生10个[0,100)整数放到一个数组中,找出他们当中的最大值
int[] arr = new int[10];
int max = 0; //max初始化为0或负数都可以,比所有元素都小
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random()*100);
System.out.print(arr[i] +" ");
if(arr[i] > max){
max = arr[i];
}
}
System.out.println();
System.out.println("max = " + max);
}
}
public class ArrayArithmetic4 {
public static void main(String[] args) {
//案例需求:随机产生10个[0,100)整数放到一个数组中,找出他们当中的最大值
int[] arr = new int[10];
// int max = 0; //max初始化为0或负数都可以,比所有元素都小
int max = Integer.MIN_VALUE; //int的最小值
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random()*100);
System.out.print(arr[i] +" ");
if(arr[i] > max){
max = arr[i];
}
}
System.out.println();
System.out.println("max = " + max);
}
}
3、在数组中找最大值及其下标
情况一:元素没有重复的情况
思路一:
public class ArrayArithmetic5 {
public static void main(String[] args) {
int[] arr = {4, 5, 6, 1, 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 class ArrayArithmetic5_2 {
public static void main(String[] args) {
int[] arr = {4, 5, 6, 1, 9};
//元素都不重复,找最大值及其下标
int maxIndex = 0;//最大值下标
for(int i=1; i<arr.length; i++){
if(arr[i] > arr[maxIndex]){
maxIndex = i;
}
}
System.out.println("maxIndex = [" + maxIndex +"]");
System.out.println("最大值 = " + arr[maxIndex]);
}
}
情况二:元素可能重复
此时最大值的下标可能有多个。
思路一:
public class ArrayArithmetic6 {
public static void main(String[] args) {
int[] arr = {4, 6, 1, 6, 9, 5, 9};
//找到最大值,及其所有下标
/*
思路一:
(1)先找到最大值
(2)再遍历数组,看哪些元素和最大值一样
*/
//先找到最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i] > max){
max = arr[i];
}
}
System.out.println("max = " + max);
//找出所有最大值的下标
System.out.println("所有最大值的下标:");
for (int i = 0; i < arr.length; i++) {
if(arr[i] == max){
System.out.print("[" + i+"] ");
}
}
}
}
思路二:
public class ArrayArithmetic6_2 {
public static void main(String[] args) {
int[] arr = {4, 6, 1, 6, 9, 5, 9};
//找到最大值,及其所有下标
/*
思路二:
(1)用max表示最大值
(2)用indexStr 表示最大值的所有下标,indexStr是String类型
*/
int max = arr[0];
String indexStr = "0";
for(int i=1; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
indexStr = i + "";//重新赋值
}else if(arr[i] == max){
indexStr = indexStr + "," + i;//拼接下标
}
}
System.out.println("max = " + max);
System.out.println("indexStr = [" + indexStr+"]");
}
}
4、数组的反转
public class ArrayArithmetic7 {
public static void main(String[] args) {
int[] arr = {4, 5, 6, 1, 9};
//需求:将数组元素反转,结果:{9,1,6,5,4}
System.out.println("交换前:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
for(int left=0,right=arr.length-1; left<right; left++,right--){
int temp = arr[left];
arr[left] =arr[right];
arr[right] = temp;
}
//交换后的结果:
System.out.println("交换后:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
}
}
5、在数组中查找元素
情况一:数组元素无序(顺序查找)
public class ArrayArimetic8 {
public static void main(String[] args) {
int[] arr = {4, 5, 6, 1, 9};
int target = 1;
int index = -1;//这里设置为[0, arr.length-1]以外的数都可以,习惯上用-1,表示非正常下标
// boolean flag = false;
for (int i = 0; i < arr.length; i++) {
if(arr[i] == target){
index = i;
// flag = true;
break;
}
}
/* if(flag){
System.out.println(target +"在数组存在");
}else{
System.out.println(target +"在数组不存在");
}*/
if(index == -1){
System.out.println(target +"在数组不存在");
}else{
System.out.println(target +"在数组存在,下标是:[" +index + "]");
}
}
}
情况二:数组元素有序
(1)顺序查找
public class ArrayArimetic8_2 {
public static void main(String[] args) {
int[] arr = {1, 5, 8, 9, 15};//元素是有序的,从小到大
int target = 7;
//顺序查找
int index = -1;
for (int i = 0; i < arr.length; i++) {
if(arr[i] == target){
index = i;
break;
}else if(arr[i] > target){
break;
}
}
if(index == -1){
System.out.println(target +"在数组不存在");
}else{
System.out.println(target +"在数组存在,下标是:[" +index + "]");
}
}
}
(2)二分查找
public class ArrayArithmetic9 {
public static void main(String[] args) {
int[] arr = {8,15,23,35,45,56,75,85};
int target = 100;
int index = -1;
for(int left=0,right=arr.length-1; left<=right; ){
// int mid = (left+right)/2;
int mid = left + (right-left)/2;
if(target == arr[mid]){
index = mid;
break;
}else if(target > arr[mid]){
//说明 目标值可能在本次查找范围的右边,修改查找范围
left = mid + 1;
}else{
//说明 目标值可能在本次查找范围的左边,修改查找范围
right = mid - 1;
}
}
if(index == -1){
System.out.println(target +"在数组不存在");
}else{
System.out.println(target +"在数组存在,下标是:[" +index + "]");
}
}
}
6、数组的排序
(1)直接选择排序
public class ArrayArithmetic10 {
public static void main(String[] args) {
//直接选择排序
int[] arr = {6, 9, 2, 9, 1};
/*
n个元素,需要找n-1个最小值
*/
for(int i=0; i<arr.length-1; i++){
//先找本轮的最小值
/*
当i=0,第1轮,要查找最小值的范围:arr[0] ~ arr[4],它应该在arr[0]位置
当i=1,第2轮,要查找最小值的范围:arr[1] ~ arr[4],它应该在arr[1]位置
当i=2,第3轮,要查找最小值的范围:arr[2] ~ arr[4],它应该在arr[2]位置
当i=3,第4轮,要查找最小值的范围:arr[3] ~ arr[4],它应该在arr[3]位置
*/
//看该最小值是否在它应该在的位置,如果不在它应该在的位置,交换
int min = arr[i];//假设本轮待排序元素的第1个元素最小
int index = i;//最小值的下标
//在arr[i+1] ~ arr[arr.length-1] 范围内查看是否有比min还小的元素
for(int j=i+1; j<arr.length; j++){
if(arr[j] < min){
min = arr[j];
index = j;
}
}
//本轮最小值现在在arr[index], 它应该arr[i]位置
if(index != i){
int temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
}
//查看排序结果
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] +" ");
}
System.out.println();
}
}
(2)冒泡排序
冒泡排序基本实现
public class ArrayArithmetic11 {
public static void main(String[] args) {
int[] arr = {6, 9, 2, 9, 1};
/*
n个元素,需要n-1轮
*/
for(int i=0; i<arr.length-1; i++){
/*
i=0, 要比较的数的范围arr[0]~arr[4]
arr[0]~ arr[1] j=0, arr[j]~arr[j+1]
arr[1]~ arr[2] j=1, arr[j]~arr[j+1]
arr[2]~ arr[3] j=2, arr[j]~arr[j+1]
arr[3]~ arr[4] j=3, arr[j]~arr[j+1]
for(int j=0; j<arr.length-1; j++)
i=1,要比较的数的范围arr[0]~arr[3]
arr[0]~ arr[1] j=0, arr[j]~arr[j+1]
arr[1]~ arr[2] j=1, arr[j]~arr[j+1]
arr[2]~ arr[3] j=2, arr[j]~arr[j+1]
for(int j=0; j<arr.length-2; j++)
i=2, 要比较的数的范围arr[0]~arr[2]
arr[0]~ arr[1] j=0, arr[j]~arr[j+1]
arr[1]~ arr[2] j=1, arr[j]~arr[j+1]
for(int j=0; j<arr.length-3; j++)
i=3,要比较的数的范围arr[0]~arr[2]
arr[0]~ arr[1] j=0, arr[j]~arr[j+1]
for(int j=0; j<arr.length-4; j++)
for(int j=0; j<arr.length-1-i; j++)
*/
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;
}
}
}
//输出排序结果
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] +" ");
}
System.out.println();
}
}
i=1开始的写法如下:
public class ArrayArithmetic11_2 {
public static void main(String[] args) {
int[] arr = {6, 9, 2, 9, 1};
/*
n个元素,需要n-1轮
*/
for(int i=1; i<arr.length; i++){
/*
i=1, 要比较的数的范围arr[0]~arr[4]
arr[0]~ arr[1] j=0, arr[j]~arr[j+1]
arr[1]~ arr[2] j=1, arr[j]~arr[j+1]
arr[2]~ arr[3] j=2, arr[j]~arr[j+1]
arr[3]~ arr[4] j=3, arr[j]~arr[j+1]
for(int j=0; j<arr.length-1; j++)
i=2,要比较的数的范围arr[0]~arr[3]
arr[0]~ arr[1] j=0, arr[j]~arr[j+1]
arr[1]~ arr[2] j=1, arr[j]~arr[j+1]
arr[2]~ arr[3] j=2, arr[j]~arr[j+1]
for(int j=0; j<arr.length-2; j++)
i=3, 要比较的数的范围arr[0]~arr[2]
arr[0]~ arr[1] j=0, arr[j]~arr[j+1]
arr[1]~ arr[2] j=1, arr[j]~arr[j+1]
for(int j=0; j<arr.length-3; j++)
i=4,要比较的数的范围arr[0]~arr[2]
arr[0]~ arr[1] j=0, arr[j]~arr[j+1]
for(int j=0; j<arr.length-4; j++)
for(int j=0; j<arr.length-i; j++)
*/
for(int j=0; j<arr.length-i; j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
//输出排序结果
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] +" ");
}
System.out.println();
}
}
冒泡排序优化
public class ArrayArithmetic11_3 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
/*
n个元素,需要n-1轮
如果中途发现数组已经有序了,可以提前结束排序过程。
思考:怎么证明数组已经有序了?
如果某一轮下来,没有进入过if,说明数组已经有序了
*/
for(int i=1; i<arr.length; i++){
boolean flag = true;//假设已经有序了
for(int j=0; j<arr.length-i; j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = false;//还未有序
}
}
if(flag){
break;
}
}
//输出排序结果
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] +" ");
}
System.out.println();
}
}
二、二维数组
为什么要使用二维数组?
一维数组是用来管理一组相同数据类型的数据的。例如:存储和管理一组学员的成绩。
二维数组是用来管理多组相同数据类型的数据的。例如:分别存储和管理多组(咱们班5个小组)学员的成绩。
二维数组的声明和使用
声明格式
元素的数据类型[][] 二维数组名; //标准写法,推荐写法
元素的数据类型 二维数组名[][];
元素的数据类型[] 二维数组名[];
初始化
1、静态的初始化
元素的数据类型[][] 二维数组名 = {{第一组的元素列表},{第二组的元素列表},{第三组的元素列表},...};
元素的数据类型[][] 二维数组名 = new 元素的数据类型[][]{{第一组的元素列表},{第二组的元素列表},{第三组的元素列表},...};
int[][] arr = {
{5,6,8,9,1},
{5,3,24,2},
{6,9,8,7}
};
2、动态初始化之规则的二维数组
规则的二维数组是指每一行的元素个数是相同的。
元素的数据类型[][] 二维数组名 = new 元素的数据类型[行数量][每一行的元素个数];
int[][] arr = new int[3][5];//代表有3行,每一行有5个元素
3、动态初始化之不规则的二维数组
不规则的二维数组是指每一行的元素个数是可能不相同的。
元素的数据类型[][] 二维数组名 = new 元素的数据类型[行数量][]; //小细节,右边第2个[]是空的,表示暂时不能确定每一行有几个元素
二维数组名[行下标] = new 元素的数据类型[该行的元素个数(或长度)];
int[][] arr = new int[3][];//代表有3行,每一行的元素个数还未定
arr[0] = new int[5];//给第一行申请5个元素的内存空间
arr[1] = new int[3];//给第二行申请3个元素的内存空间
arr[2] = new int[10];//给第三行申请10个元素的内存空间
4、代码演示
public class TwoDimensionalArrayDemo1 {
public static void main(String[] args) {
int[][] arr = {
{5,6,8,9,1},
{5,3,24,2},
{6,9,8,7}
};
System.out.println("二维数组的长度(行数):" + arr.length);
System.out.println("第一行:" + arr[0]);//[I@4dd8dc3
for(int i=0; i<arr.length; i++){//代表有几行,有几组
for(int j=0; j<arr[i].length; j++){//遍历每一行的 n个元素, arr[i]是一行,又是一个一维数组。
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
}
public class TwoDimensionalArrayDemo2 {
public static void main(String[] args) {
int[][] arr = new int[3][5];
System.out.println("二维数组的长度(行数):" + arr.length);
System.out.println("第一行:" + arr[0]);//[I@4dd8dc3
for(int i=0; i<arr.length; i++){//代表有几行,有几组
for(int j=0; j<arr[i].length; j++){//遍历每一行的 n个元素, arr[i]是一行,又是一个一维数组。
arr[i][j] = (int)(Math.random()*100);//随机产生[0,100)的整数,放到二维数组中
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
}
public class TwoDimensionalArrayDemo3 {
public static void main(String[] args) {
int[][] arr = new int[3][];
System.out.println("二维数组的长度(行数):" + arr.length);
System.out.println("第一行:" + arr[0]);//null
//表示第一行有几个元素还未确定,堆内存中还没有分配第1行的内存空间,所以是null
// System.out.println("第一行的第一个元素:" + arr[0][0]);//java.lang.NullPointerException: 空指针异常
//arr[0]不指向任何内存位置,所以内存中找不到 arr[0][0]元素
arr[0] = new int[5];//给第一行申请5个元素的内存空间
//arr[0]这个[0]是下标的意思,
//int[5]这是[5]是元素的个数的意思
//原则:数组名后面[]里面是下标
//原则:数据类型后面[]里面是长度,元素个数
System.out.println("第一行的第一个元素:" + arr[0][0]);//0
arr[1] = new int[3];//给第二行申请3个元素的内存空间
arr[2] = new int[10];//给第三行申请10个元素的内存空间
for(int i=0; i<arr.length; i++){//代表有几行,有几组
for(int j=0; j<arr[i].length; j++){//遍历每一行的 n个元素, arr[i]是一行,又是一个一维数组。
arr[i][j] = (int)(Math.random()*100);//随机产生[0,100)的整数,放到二维数组中
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
}
二维数组的遍历
int[][] arr = {
{5,6,8,9,1},
{5,3,24,2},
{6,9,8,7}
};
二维数组的长度:二维数组名.length ,代表一共有几组。 例如:arr.length的值为3
二维数组的某一行/组:二维数组名[行下标],例如arr数组有3行
- 第1行:arr[0],代表一个一维数组,{5,6,8,9,1},它也有长度,长度为5, arr[0].length的值为5
- 第2行:arr[1],代表一个一维数组,{5,3,24,2},它也有长度,长度为4, arr[1].length的值为4
- 第3行:arr[2],代表一个一维数组,{6,9,8,7},它也有长度,长度为4, arr[2].length的值为4
- 二维数组的一行,是一个一维数组,二维数组可以看成元素是一维数组的一维数组。
二维数组的某一行的某一个元素:二维数组名[行下标][列下标]
- 第1行的第1个元素:arr[0][0]
- 第2行的第3个元素:arr[1][2]
for(int i=0; i<二维数组名.length; i++){
for(int j=0; j<二维数组名[i].length; j++){
System.out.print(二维数组名[i][j]);
}
System.out.println();
}
二维数组的内存分析
int[][] arr = {
{5,6,8,9,1},
{5,3,24,2},
{6,9,8,7}
};
{6,9,8,7}
};
二维数组的长度:二维数组名.length ,代表一共有几组。 例如:arr.length的值为3
二维数组的某一行/组:二维数组名[行下标],例如arr数组有3行
- 第1行:arr[0],代表一个一维数组,{5,6,8,9,1},它也有长度,长度为5, arr[0].length的值为5
- 第2行:arr[1],代表一个一维数组,{5,3,24,2},它也有长度,长度为4, arr[1].length的值为4
- 第3行:arr[2],代表一个一维数组,{6,9,8,7},它也有长度,长度为4, arr[2].length的值为4
- 二维数组的一行,是一个一维数组,二维数组可以看成元素是一维数组的一维数组。
二维数组的某一行的某一个元素:二维数组名\[行下标][列下标]
- 第1行的第1个元素:arr\[0][0]
- 第2行的第3个元素:arr\[1][2]
```java
for(int i=0; i<二维数组名.length; i++){
for(int j=0; j<二维数组名[i].length; j++){
System.out.print(二维数组名[i][j]);
}
System.out.println();
}
二维数组的内存分析
int[][] arr = {
{5,6,8,9,1},
{5,3,24,2},
{6,9,8,7}
};