本文内容:
1、为什么要使用数组呢?
在我们的函数中,一个函数只能有一个返回值,那么如果想返回多个值该怎么办呢?
通过将多个返回值放到数组中,让函数返回数组,就可以达到间接返回多个值的效果。
2、数组:
数组的定义:
数组是相同数据类型的数据按顺序组成的一种引用数据类型。
①这里的相同数据类型指的是,数据在内存中的数据类型,比如:double [] priceArray = new double[]{9.9,1},虽然我在这个数组中写了一个int类型的数据1,但是在内存中会自动转换成double类型的。②基本数据类型元素构成的数组 也是引用类型。
数组的声明:
一维数组:数组元素数据类型 [ ] 数组名; String [] array;
二维数组:数组元素数据类型[ ][ ] 数组名;double [] [] array;
多维数组:数组元素数据类型[ ][ ] ...数组名; int [] [] [] ... array; 其中的array是数组的名字。
数组的实例化一共有两种:
①数组名 = new 数组元素数据类型 [数组元素个数]; 例如:
String [] name; name = new String[2]; 这代表name数组中有两个元素
String [] [] names; names = new String[2][]; names[0] = new String[2]; names[1] = new String[10]; 这表示该二维数组names中有两个一维数组,第一个一维数组names[0]中有两个元素,第二个一维数组names[1]中有十个元素。
② 采用穷举法实例化数组:
int [] num= {1,2,3,4}; int [] num = new int [] {1,2,3,4} 这两个实例化表示该一维数组num中有有四个元素,分别是1,2,3,4
int [] [] nums = {{1,2,3},{4,5,6,7}}; int [] [] nums = new int [] [] {{1,2,3},{4,5,6,7}}; 这两个实例化表示该二维数组nums中,第一个一维数组nums[0]中有三个元素分别是1,2,3 第二个一维数组nums[1] 中有四个元分别是4,5,6,7
注意:二维及以上数组中,每个一维数组中包含的元素个数,可相同也可以不相同。
易错点:
int[ ] score = new int[ ];
score[0] = 89;
score[1] = 63;
System.out.println(score[0]);
//编译阶段就会出错,因为实例化时没有写明数组大小,也没有给出数组中的元素值
int [ ] scoreArray = new int [5];
scoreArray = {60, 80, 90, 70, 85};
//编译阶段出错,这种穷举法只能用于初始化数组,必须和声明数组代码放在一条语句中,正确结果如下:
int [ ] scoreArray = {60, 80, 90, 70, 85};
操作数组元素:
//为元素赋值: 注意数组的下标从0开始
int [] num = new int [2]; num[0] = 1; num[1] = 1;
//获取元素值:
int [] num = {1,2,3,4}; System.out.println(num[0]);
//遍历数组:遍历一维数组
for(int i=0; i<num.length; i++){
System.out.println(num[i]);
}
//遍历二维数组比如数组 int [] [] nums = {{1,2,3},{4,5,6,7}}
for(int i=0; i<nums.length; i++){
int [] num = nums[i];
for(int j=0; j<num.length; j++){
System.out.println(num[j]);
}
}
//加强for循环,一维数组
for(int num : nums){
System.out.println(num);
}
//二维数组
for(int [] num : nums){
for(int data : num){
System.out.println(data);
}
}
易错点:
public static void main(String[ ] args) {
int[ ] scores = new int[1];
scores[0] = 90;
scores[1] = 85;
System.out.println(scores[1]);
}
//解释阶段出错,数组越界了
数组的排序:
冒泡排序法每一次排序目的是将数值较大(针对于升序排序)或较小(针对于降序排序)的元素移动到数组的尾部。
以升序为例:
第一次循环:将元素21与元素99进行比较,由于21 < 99,所以不用交换元素;
第二次循环:将元素99与元素3进行比较,由于99 > 3,所以需要交换元素(即99和3的位置互换,数组的序列被调整为 {21, 3, 99, 1024, 16});
第三次循环:将元素99与元素1024进行比较,由于99 < 1024,所以也不用交换元素;
第四次循环:将元素1024与元素16进行比较,由于1024 < 16,所以需要交换元素(即1024与16的位置互换)。
经过第一次遍历将最大的元素1024调整到了数组的尾部,数组序列变为 {21, 3, 99, 16, 1024}。
int [] array = {21,99,3,1024,16};
for(int i=0;i<array.length-1; i++){
int currentData = array[i];//当前遍历数据
int nextData = array[i+1];//当前数据的下一个元素的数据
if(currentData>nextData){//如果前一个数据比后一个数据大,则进行数据交换
int temp = currentData;
array[i] = nextData;
array[i+1]=temp;
}
}
冒泡排序法的第二次排序与第一次原理一致,只不过第二次排序不再关系数组尾部元素,因为经过前一次排序后,数组尾部元素已经存储了数组中数值最大的元素,所以第二次排序的目的是将数组中数值第二大的元素存储到数组的倒数第二个位置(即此时只关心数组前四个元素 {21, 3, 99, 16}的顺序)。
第一次循环:将元素21与元素3进行比较,由于21 > 3,所以需要交换元素(即21和3位置互换,数组的前四位序列被调整为 {3, 21, 99, 16});
第二次循环:将元素21与元素99进行比较,由于21 < 99,所以不用交换元素;
第三次循环:将元素99与元素16进行比较,由于99 > 16,所以需要交换元素(即99和16的位置互换);
第四次循环:将元素99与元素1024进行比较,由于99< 1024,所以不用交换元素。
经过第二次排序数组序列变为 {3, 21, 16, 99, 1024}。
以下N次排序都和上一次排序原理相同,直至达到想要的结果。下面给出完整代码:
public class ArraySort{
public static void main(String [] args){
int [] array={21, 99, 3, 1024, 16};//升序排列
for(int loopTime=1;loopTime<array.length;loopTime++){//只是控制内部for循环的次数
for(int i=0;i<array.length-1;i++){//该for循环每循环一次就会将较大的数据放在适当的位置,比如loopTime=1;则将最大数据放在最后;loopTime=2;则将第二大数据放在倒数第二个元素位置;
int currentData = array[i];//当前遍历出来的数据
int nextData = array[i+1];//当前数据下标对应的下一个元素的数据
if(currentData>nextData){//如果当前元素大于其后面的元素,则意味着需要调换两个元素之间的位置
array[i] = nextData;
array[i+1]=currentData;
}
}
}
for(int data:array){
System.out.print(data+" ");
}
}
}
//说明:
//loopTime=1时如P23页PPT;
//loopTime=2时如P24页PPT,但是最后一次循环多余;
//loopTime=3时如P25页PPT,但是最后二次循环多余;
//loopTime=4时如P26页PPT,但是最后三次循环多余;
//下面是改进后的代码
public class ArraySort{
public static void main(String [] args){
int [] array={21, 99, 3, 1024, 16};//升序排列
for(int loopTime=1;loopTime<array.length;loopTime++){//只是控制内部for循环的次数
for(int i=0;i<array.length-loopTime;i++){//该for循环每循环一次就会将较大的数据放在适当的位置,比如loopTime=1;则将最大数据放在最后;loopTime=2;则将第二大数据放在倒数第二个元素位置;array.length-loopTime:从提高代码的性能角度出发,减少该循环“多余”的循环次数
int currentData = array[i];//当前遍历出来的数据
int nextData = array[i+1];//当前数据下标对应的下一个元素的数据
if(currentData>nextData){//如果当前元素大于其后面的元素,则意味着需要调换两个元素之间的位置
array[i] = nextData;
array[i+1]=currentData;
}
}
}
for(int data:array){
System.out.print(data+" ");
}
}
}
插入排序:每循环一次都将一个待排序的元素所对应的数据按其顺序大小插入到前面已经排序的序列的合适位置,直到全部插入排序完为止,其难点在于如何在前面已经排好序的序列中找到合适的插入位置。该排序方法有很多,比如直接插入排序、二分插入排序、希尔排序等等。
public class ArraySort{
public static void main(String [] args){
int [] array={1,2,6,7,2,9,12,2};//升序排列
for(int i=1;i<array.length;i++){//i为待排序数据的下标,由于将第一个元素是有序的,所以i从1开始;i<array:这样才能遍历完后续数组,进而实现全部排序;
int willSortData=array[i];//将待排序数据保存到变量willSortData中
int j=0;
/*
*查找待插入数据“应该”插入的下标位置
*/
for(;j<i;j++){//j<i:和待排序数据前面(i)的所有元素进行比较,以找到“应该”插入的下标位置。说明:不能这样写j<=i,因为无需自己和自己比对
if(willSortData<array[j]){//如果条件成立意味着待插入数据小于其前面的某个元素值
break;//当if条件成立时就找到了该待插入数据“应该”插入的下标位置,所以这时必须终止循环
}
}//for循环执行结束意味着找到了待插入数据“应该”插入的下标位置
if(i==j){//i与j相等意味着不用排序,下面代码也不用执行
continue;//停止不用排序这次循环,进入下次循环
}
/*
*下面循环用于元素后置
*/
for(int k=i;k>j;k--){//int k=i:待插入数据所在位置就是元素后移开始的下标位置;k>j:待插入数据“应该”插入位置(j)就是元素后移结束位置
array[k]=array[k-1];//元素后置
}
/*
*下面代码用于将待插入数据插入到“应该”插入的下标位置
*/
array[j]=willSortData;
}//该循环体每循环完一次就代表着本次待插入数据已经和前面元素是有序的了
for(int data:array){
System.out.print(data+" ");
}
}
}
插入排序的实质:将数组分为有序区和无序区,定义一个标记无序区第一个元素的定位变量,将该元素与前面的有序区内元素遍历比较,找到该元素应该插入位置,然后将应插入位置到待插入元素所在位置之间的元素后移一位,最后再将待插入元素插入到应插入的位置,有序区扩增一位,无序区减少一位,定位变量再次后移,锁定后面无序区第一位元素位置。
数组元素的查找:
二分法查找:搜索数据与有序数组(比如升序)中间元素比较以确定在中间元素左边还是右边,如果在右边,则调整最小搜索索引值,然后进入下次循环;如果在左边,则调整最大搜索索引值,然后进入下次循环;如果相等则当前位置就是查找数据所在位置,停止循环;
public class Test {
public static int search(int[] array, int data) {
Arrays.sort(array);// 将数组升序排列
int low = 0;
int high = array.length - 1;
while (low <= high) {
int middle = (low + high) / 2;
// 搜索数据与中间元素比较确定在中间元素左边还是右边,进而不断缩小查找范围
if (data > array[middle]) {//右边
low = middle + 1;
} else if (data < array[middle]) {//左边
high = middle - 1;
} else {
return middle;
}
}
return -1;
}
public static void main(String[] args) {
int[] numbers = {5, 1, 7, 3, 2};
int index = search(numbers, 5);
if (index != -1) {
System.out.println("数组中包含该数据");
} else {
System.out.println("数组中不包含该数据");
}
}
}
3、值传递和引用传递:
public class Test {
public static void main(String[] args) {
int x=10;
test(x);
System.out.println(x);//输出10
}
public static void test(int y) {
y=0;
}
}
//值传递,在函数中对参数进行修改,不会影响到实际参数的值
public class Test {
public static void main(String[] args) {
int [] x= {10};
test(x);
System.out.println(x[0]);//输出0
}
public static void test(int [] y) {
y[0]=0;
}
}
//引用传递,在调用函数时将实际参数的地址直接传递到函数中,在函数中对参数所进行的修改,将影响到实际参数。