第4章 数组
4.1 数组的相关观念
数组:代表一组数据,当有一组“相同数据类型”的数据需要管理时,可以考虑使用数组,使用统一的名称来管理它们,这个统一的名称称为“数组名”。这组数据中的每一个数据,称为“元素”,每一个元素通过编号进行区分,这个编号称为”下标/索引“,下标的范围:[0, 数组的长度-1],元素的表示方式:数组名[下标],这组数据的总个数称为数组的长度,数组名.length。
int[] arr= {4,5,7,6,1};
int[] nums=newint[5];
arr数组的第一个元素:arr[0]
arr数组的第二个元素:arr[1]
nums数组的第一个元素:nums[0]
nums数组的第二个元素:nums[1]
arr数组的长度:arr.length
nums数组的长度:nums.length
4.2 数组的声明、初始化、使用
数组的声明格式:
元素的数据类型[] 数组名;
数组的初始化:
静态初始化:
和声明合起来一句,元素的数据类型[] 数组名= {元素值1,元素值2,....};
声明和初始化分开呢,
元素的数据类型[] 数组名;
数组名=new元素的数据类型[]{元素值1,元素值2,....};
动态初始化:
和声明合起来一句,元素的数据类型[] 数组名=new元素的数据类型[长度];
声明和初始化分开呢,
元素的数据类型[] 数组名;
数组名=new元素的数据类型[长度];
数组的遍历:
快捷键:数组名.fori 或直接itar
for(inti=0; i<数组名.length; i++){
}
4.3 数组的算法
4.3.1 对元素的统计分析
通常:统计元素中偶数的个数、3的倍数的个数、平均值、总和、素数的个数.....
原则:从头到尾遍历数组的元素,挨个判断即可 或 挨个累加
例如:
publicclassArrayReview1 {
publicstaticvoidmain(String[] args) {
int[] arr= {8, 6, 9, 4, 2, 5, 3, 1};
//统计里面偶数和奇数的个数
inteven=0;//存储偶数的个数
intodd=0;//存储奇数的个数
//遍历数组的元素,判断它们是偶数还是奇数
for (inti=0; i<arr.length; i++) {
if(arr[i] %2==0){
even++;
}else{
odd++;
}
}
System.out.println("odd = "+odd);
System.out.println("even = "+even);
}
}
4.3.2 找最大值/最小值
思路:
情况一:元素值已经确定
(1)先假设第1个元素最大或最小,即把第一个元素赋值给max/min变量
(2)用max或min变量 与 数组剩下的元素一一比较,如果有比max大,比min小的情况,就修改max或min的值
publicclassArrayReview2 {
publicstaticvoidmain(String[] args) {
int[] arr= {8, 6, 9, 4, 2, 5, 3, 1};
//找最大值
/*
情况一:元素值已经确定
(1)先假设第1个元素最大或最小,即把第一个元素赋值给max/min变量
(2)用max或min变量 与 数组剩下的元素一一比较,如果有比max大,比min小的情况,就修改max或min的值
*/
intmax=arr[0];
for (inti=1; i<arr.length; i++) {
if(arr[i] >max){//if(max < arr[i]){
max=arr[i];
}
}
System.out.println("max = "+max);
}
}
情况二:元素的值暂时不确定的,想着在确定值的同时找最大值/最小值
(1)通常把max初始化一个小于等于当前元素取值范围的最小值
例如:元素值的范围是[0,100],max = 0
如果元素值没有具体范围,int类型的话,max = Integer.MIN_VALUE;
通常把min初始化为一个大于等于当前元素取值范围的最大值
例如:元素值的范围是[0,100],min = 100
如果元素值没有具体范围,int类型的话,max = Integer.MAX_VALUE;
(2)用max或min变量 与 数组所有元素一一比较,如果有比max大,比min小的情况,就修改max或min的值
publicclassArrayReview3 {
publicstaticvoidmain(String[] args) {
int[] arr=newint[10];
//找最大值和最小值
/*
情况二:元素的值暂时不确定的,想着在确定值的同时找最大值/最小值
(1)通常把max初始化一个小于等于当前元素取值范围的最小值
例如:元素值的范围是[0,100),max = 0
通常把min初始化为一个大于等于当前元素取值范围的最大值
例如:元素值的范围是[0,100),min = 100
(2)用max或min变量 与 数组所有元素一一比较,如果有比max大,比min小的情况,就修改max或min的值
*/
intmax=0;
intmin=100;
for (inti=0; i<arr.length; i++) {
arr[i] = (int)(Math.random()*100);
System.out.print(arr[i] +" ");
if(arr[i] >max){
max=arr[i];
}elseif(arr[i] <min){
min=arr[i];
}
}
System.out.println();
System.out.println("max = "+max);
System.out.println("min = "+min);
}
}
4.3.3 找最大值及其下标
情况一:元素不重复,假设元素已经确定
(1)声明两个变量,一个变量是max(存最大值),一个变量是index(存它的下标)
先假设第1个元素最大或最小,即把第一个元素赋值给max变量,index初始化为0
(2)用剩下的元素与max比较,如果有比max大的,同时修改max和index
publicclassArrayReview4 {
publicstaticvoidmain(String[] args) {
int[] arr= {8, 6, 9, 4, 2, 5, 3, 1};
//找最大值及其下标
/*
情况一:元素不重复,假设元素已经确定
(1)声明两个变量,一个变量是max(存最大值),一个变量是index(存它的下标)
先假设第1个元素最大或最小,即把第一个元素赋值给max变量,index初始化为0
(2)用剩下的元素与max比较,如果有比max大的,同时修改max和index
*/
intmax=arr[0];
intindex=0;
for (inti=1; i<arr.length; i++) {
if(arr[i] >max){//if(max < arr[i]){
max=arr[i];
index=i;
}
}
System.out.println("max = "+max);
System.out.println("index = ["+index+"]");
}
}
情况二:元素可能重复,假设元素已经确定
(1)第一步先找最大值
(2)第二步再找和最大值相等的所有元素的下标
publicclassArrayReview5 {
publicstaticvoidmain(String[] args) {
int[] arr= {8, 6, 9, 4, 2, 5, 9, 1};
//找最大值及其下标
/*
情况二:元素可能重复,假设元素已经确定
(1)第一步先找最大值
(2)第二步再找和最大值相等的所有元素的下标
*/
intmax=arr[0];
for (inti=1; i<arr.length; i++) {
if(arr[i] >max){//if(max < arr[i]){
max=arr[i];
}
}
System.out.println("max = "+max);
for (inti=0; i<arr.length; i++) {
if(arr[i] ==max){
System.out.println("index = ["+i+"]");
}
}
}
}
4.3.4 元素查找
情况一:元素是无序
只能顺序查找,从第一个元素开始判断它是否是目标值,如果是,就说明目标值存在,当所有元素都判断过了,才能确定目标不存在。
(1)先声明一个boolean的变量flag,初始化为flag = false(不存在)
(2)遍历数组,挨个元素与目标值比较,如果相等,flag修改为true,同时可以break了,因为目标值已存在可以确定了
(3)遍历结束后,如果flag==false,就说明目标值不存在。
或者
(1)先声明一个int的变量index,初始化为-1(不存在),(因为正常元素的下标不会是-1)
(2)遍历数组,挨个元素与目标值比较,如果相等,index=该元素的下标,同时可以break了,因为目标值已存在可以确定了
(3)遍历结束后,如果index==-1,就说明目标值不存在。
publicclassArrayReview6 {
publicstaticvoidmain(String[] args) {
int[] arr= {8, 6, 9, 4, 2, 5, 9, 1};
//查找目标值7是否存在
inttarget=7;
/*
只能顺序查找,从第一个元素开始判断它是否是目标值,如果是,就说明目标值存在,当所有元素都判断过了,才能确定目标不存在。
(1)先声明一个boolean的变量flag,初始化为flag = false(不存在)
(2)遍历数组,挨个元素与目标值比较,如果相等,flag修改为true,同时可以break了,因为目标值已存在可以确定了
(3)遍历结束后,如果flag==false,就说明目标值不存在。
或者
(1)先声明一个int的变量index,初始化为-1(不存在),(因为正常元素的下标不会是-1)
(2)遍历数组,挨个元素与目标值比较,如果相等,index=该元素的下标,同时可以break了,因为目标值已存在可以确定了
(3)遍历结束后,如果index==-1,就说明目标值不存在。
*/
booleanflag=false;//不存在
for (inti=0; i<arr.length; i++) {
if(arr[i] ==target){
flag=true;//存在
break;
}
}
if(flag){
System.out.println("存在");
}else{
System.out.println("不存在");
}
}
}
情况二:元素是有序的,假设元素是从小到大
二分查找:
思路:
(1)声明left,right,mid变量,left表示左边界的下标,right表示右边界的下标,mid表示当前查找范围的中间元素的下标
left = 第一个元素的下标 = 0,right = 最后一个元素的下标= 数组名.length-1,
mid = (left + right) / 2 ; 更优一点写法 mid = left + (right - left)/2;
(2)循环条件 left <= right,循环条件成立还要查找,否则就结束
(3)用目标值target与 数组名[mid]比较是否相等,还可以用 目标值target 与 数组名[left] 比较是否相等, 还可以用 目标值target 与 数组名[right 比较是否相等,如果它们都不成立,看目标值target 比 数组名[mid]大还是小,
如果目标值target 比 数组名[mid]小,去左边,即要修改右边界 right = mid - 1,如果之前 比较过(目标值target 与 数组名[left] ),还可以修改left=left+1,如果之前 没有比较过(目标值target 与 数组名[left] ),不能写 left=left+1
如果目标值target 比 数组名[mid]大,去右边,即要修改左边界 left = mid +1,如果之前 比较过(目标值target 与 数组名[right] ),还可以修改right = right-1,如果之前没有比较过(目标值target 与 数组名[right] ),不能写right = right-1.
publicclassArrayReview7 {
publicstaticvoidmain(String[] args) {
int[] arr= {1,5,9,14,36,56};
//查找目标值7是否存在
inttarget=7;
intindex=-1;//假设target不存在,正常下标不会是-1
/*
思路:
(1)声明left,right,mid变量,left表示左边界的下标,right表示右边界的下标,mid表示当前查找范围的中间元素的下标
left = 第一个元素的下标 = 0,right = 最后一个元素的下标= 数组名.length-1,
mid = (left + right) / 2 ; 更优一点写法 mid = left + (right - left)/2;
(2)循环条件 left <= right,循环条件成立还要查找,否则就结束
(3)用目标值target与 数组名[mid]比较是否相等,还可以用 目标值target 与 数组名[left] 比较是否相等, 还可以用 目标值target 与 数组名[right 比较是否相等,如果它们都不成立,看目标值target 比 数组名[mid]大还是小,
如果目标值target 比 数组名[mid]小,去左边,即要修改右边界 right = mid - 1,如果之前 比较过(目标值target 与 数组名[left] ),还可以修改left=left+1,如果之前 没有比较过(目标值target 与 数组名[left] ),不能写 left=left+1
如果目标值target 比 数组名[mid]大,去右边,即要修改左边界 left = mid +1,如果之前 比较过(目标值target 与 数组名[right] ),还可以修改right = right-1,如果之前没有比较过(目标值target 与 数组名[right] ),不能写right = right-1.
*/
intleft=0;
intright=arr.length-1;
while(left<=right){
intmid=left+ (right-left)/2;//left与right的值可能会被修改,每次修改完都要重新计算mid的值
if(target==arr[mid]){//找到了
index=mid;
break;
}elseif(target==arr[left]){//找到了
index=left;
break;
}elseif(target==arr[right]){//找到了
index=right;
break;
}elseif(target<arr[mid]){//暂时还没找到,去左边
right=mid-1;
//因为前面比较了 if(target == arr[left]),所以可以修改left
left++;
}else{//暂时还没找到,去右边
left=mid+1;
//因为前面比较了 if(target == arr[right],所以可以修改right
right--;
}
}
if(index==-1){
System.out.println("不存在");
}else{
System.out.println("存在");
}
}
}
4.3.5 反转
思路:
左边与右边的元素交换,对应位置的元素交换。
步骤:
(1)声明两个变量,left,right,left代表左边的下标,right代表右边的下标
(2)数组名[left] 与 数组名[right]交换,
(3)每次交换完, left++,right--
(4)循环条件 ,left < right
publicclassArrayReview8 {
publicstaticvoidmain(String[] args) {
int[] arr= {1,5,9,14,36,56};
//反转
//左边与右边的元素交换,对应位置的元素交换。
/*
步骤:
(1)声明两个变量,left,right,left代表左边的下标,right代表右边的下标
(2)数组名[left] 与 数组名[right]交换,
(3)每次交换完, left++,right--
(4)循环条件 ,left < right
*/
for(intleft=0,right=arr.length-1; left<right; left++,right--){
inttemp=arr[left];
arr[left] =arr[right];
arr[right] =temp;
}
for (inti=0; i<arr.length; i++) {
System.out.print(arr[i] +" ");
}
}
}
4.3.6 冒泡排序
目标:从小到大
总思路:相邻元素比较,如果前面的元素 比 后面的元素 大,就交换它们,n个元素需要比较n-1轮,每一轮都可以从第一个元素开始,每一轮已经排好序的元素可以不用参与了。
步骤:
(1)外循环控制轮数
(2)内循环每一轮比较的过程
publicclassArrayReview9 {
publicstaticvoidmain(String[] args) {
int[] arr= {8,6,2,4,9,1};
/*
目标:从小到大
总思路:相邻元素比较,如果前面的元素 比 后面的元素 大,就交换它们,
n个元素需要比较n-1轮,每一轮都可以从第一个元素开始,每一轮已经排好序的元素可以不用参与了。
步骤:
(1)外循环控制轮数
(2)内循环每一轮比较的过程
*/
/*
arr.length = 6,元素下标范围[0,5]
int i = 1,2,3,4,5
*/
for (inti=1; i<arr.length; i++) {
/*
i=1, j=0,1,2,3,4
arr[0]~arr[1]
arr[1]~arr[2]
arr[2]~arr[3]
arr[3]~arr[4]
arr[4]~arr[5]
i=2,j=0,1,2,3
arr[0]~arr[1]
arr[1]~arr[2]
arr[2]~arr[3]
arr[3]~arr[4]
本轮 arr[5]没有参与
i=3,j=0,1,2
i=4,j=0,1
i=5,j=0
前后元素:arr[j] 与 arr[j+1]
*/
for (intj=0; j<arr.length -i; j++) {
if(arr[j] >arr[j+1]){
inttemp=arr[j];
arr[j] =arr[j+1];
arr[j+1] =temp;
}
}
}
for(inti=0; i<arr.length; i++){
System.out.println(arr[i]);
}
}
}
4.3.7 选择排序
目标:从小到大
总思路:找出每一轮未排序元素的最小值,让它去到它应该在的位置。
步骤:
(1)外循环:控制轮数,n个元素依然是n-1轮
(2)内循环
A:先找出本轮的未排序元素的最小值及其现在的下标
第一轮:查找最小值的范围[0, arr.length-1]
第二轮:查找最小值的范围[1, arr.length-1]
....
B:如果它没有在它应该在的位置,就交换
第一轮,它应该在 [0]位置
第二轮,它应该在 [1] 位置
....
publicclassArrayReview10 {
publicstaticvoidmain(String[] args) {
int[] arr= {8,6,2,4,9,1};
/*
目标:从小到大
总思路:找出每一轮未排序元素的最小值,让它去到它应该在的位置。
步骤:
(1)外循环:控制轮数,n个元素依然是n-1轮
(2)内循环
A:先找出本轮的未排序元素的最小值及其现在的下标
第一轮:查找最小值的范围[0, arr.length-1]
第二轮:查找最小值的范围[1, arr.length-1]
....
B:如果它没有在它应该在的位置,就交换
第一轮,它应该在 [0]位置
第二轮,它应该在 [1] 位置
....
*/
for (inti=0; i<arr.length-1; i++) {
intmin=arr[i];
intindex=i;
for (intj=i+1; j<arr.length; j++) {
if(arr[j] <min){
min=arr[j];
index=j;
}
}
if(index!=i){
//交换arr[i] 与 arr[index]
inttemp=arr[i];
arr[i] =arr[index];
arr[index] =temp;
}
}
for(inti=0; i<arr.length; i++){
System.out.println(arr[i]);
}
}
}
4.4 二维数组
二维数组的声明:
元素的类型[][] 数组名;
例如:
int[][] arr; //推荐写法
intarr[][]; //也是对的
int[] arr[];//也是对的
二维数组的静态初始化:
元素的类型[][] 数组名= {{第一行的元素}, {第二行的元素},。。。。};
//如果声明和静态初始化不能在一句完成
元素的类型[][] 数组名;
数组名=new元素的类型[][]{{第一行的元素}, {第二行的元素},。。。。};
二维数组的动态初始化:
//每一行的列数是完全相同的,矩阵
元素的类型[][] 数组名=new元素的类型[总行数][每一行的列数];
例如:
abcde
fghij
zzzzz
每一行都是5个元素
元素的类型[][] 数组名=new元素的类型[3][5];
元素的类型[][] 数组名=new元素的类型[总行数][];
数组名[行下标] =new元素的类型[该行的列数];
//每一行的列数是不同的
例如:
abc
fghij
zzzzzhtgd
mn
元素的类型[][] 数组名=new元素的类型[4][];
数组名[0] =new元素的类型[3];
数组名[1] =new元素的类型[5];
数组名[2] =new元素的类型[9];
数组名[3] =new元素的类型[2];
第一行的元素:数组名[0][0]、数组名[0][1]、数组名[0][2]
第二行的元素:数组名[1][0]、数组名[1][1]、数组名[1][2]、数组名[1][3] 、数组名[1][4]
....
二维数组的遍历:
for(inti=0; i<二维数组名.length; i++){
for(intj=0; j<二维数组名[i].length; j++){
二维数组名[i][j]代表元素
}
}