数组的定义
- 引言:为什么定义数组?
- 方法不能返回多个值,将欲返回的多个值放在数组中,就可以间接实现返回多个值的效果。
public double getInfo(){
double weight = 95.5;
double height = 1.69;
return weight, height;//出错
}
1、相同数据类型——数据在内存中的数据类型。
2、基本数据类型元素构成的数组也是引用类型。
int [] ageArray = {22,34,56};//存放int类型数据的数组
double [] priceArray = new double[]{9.9,1};//存放double类型数据的数组,输出的1为1.0(double)
String [] nameArray = new String[3];//存放String类型数据的数组
----------
double [] scores = new double[3];
scores[0] = 99.0;
scores[1] = 100.0;
scores[2] = 88;
System.out.println(scores[2]);//输出88.0,即内存中存储的数据是同一个类型——double类型
1、 定义数组
- 定义:数组是相同数据类型的数据按顺序组成的一种引用数据类型。
2、声明数组
- 声明一位数组:数组元素数据类型 [ ] 数组名;
double [] scores;
- 声明二维数组:数组元素数据类型[ ][ ] 数组名;
String [] [] accounts;
3、实例化数组
——声明数组仅仅给出了元素的数据类型和数组名字,要使用数组就必须为它分配内存空间,即实例化数组。当实例化一个数组时就申请了一段连续的内存空间存储数组中的元素。
- 数据分配内存空间时指定数组长度
- `数组名 = new 数组元素数据类型 [数组元素个数];
- 这种方式实例化数组后系统会为数组中的元素赋默认值,例如float数组中元素的默认值是0.0f,引用类型数组中的元素的默认值是null。
String [] nameArray;
nameArray= new String[3];
等价于
String [] nameArray=new String [3];
一维数组
public class Test {
public static void main(String[] args) {
String [] nameArray;//声明数组
nameArray=new String[3];//实例化数组,表明可以存储三个数据
//上面两个式子等价于 String [] nameArray=new String [3];
System.out.println(nameArray[2]);//输出null
----------
double [] scores = new double[5];
scores[0] = 3.4;
scores[1] = 3.6;
scores[2] = 4.0;
scores[3] = 5.5;
scores[4] = 6.6;
System.out.println(scores[2]);//输出4.0
}
}
二维数组
public class Test2 {
public static void main(String[] args) {
//double [][] wages=new double [2][30];
double [][] wages;
wages = new double [2][30];//表明有两个一维数组,每个一维数组中可存储30个数据
System.out.println(wages[0][14]);//输出0.0
}
}
----------
public class Test2 {
public static void main(String[] args) {
int [][] scores;
scores = new int [2][];//实例化数组,有两个一维数组
scores[0]=new int [2];//第一个一位数组中可存储2个数据
scores[1]=new int [30];//第二个一维数组中可存储30个数据
scores[1][5]=24;//对第二个一维数组中的第六个元素赋值
System.out.println(scores[1][5]);//输出24
}
}
----------
- 穷举法
int [] scores = {99,100,88,96,66};
等价于
int [] scores = new int [] {99,100,88,96,66}
一维数组
public class Test2 {
public static void main(String[] args) {
int [] scores1 = {99,100,88,96,66};
int [] scores2 = new int [] {65,77,88,90,47}
System.out.println(scores1[3]);//输出96
System.out.println(scores2[3]);//输出90
}
}
二维数组
对称二维数组
public class Test2 {
public static void main(String[] args) {
int [][] scores1 = {{99,100,88},{96,66,77}};;
int [][] scores2 = new int [][] {{98,80,88},{78,69,85}};;
System.out.println(scores1[1][1]);//输出66
System.out.println(scores2[0][2]);//输出88
}
}
非对称二维数组
public class Test2 {
public static void main(String[] args) {
int [][] scores1 = {{99,100,},{96,66,77}};;
int [][] scores2 = new int [][] {{80,88},{78,69,85}};;
System.out.println(scores1[1][1]);//输出66
System.out.println(scores2[0][0]);//输出80
}
}
注意:
public static void main(String[ ] args){
int[ ] scoreArray = new int[5];
scoreArray = {60, 80, 90, 70, 85};//错误
int[ ] ageArray;
ageArray = {21, 16, 28};//错误
}
上面这种穷举法只能用于初始化数组,即必须和声明数组代码放在一条语句中完成,
正确
public static void main(String[ ] args){
int[ ] scoreArray = {60, 80, 90, 70, 85};
int[ ] ageArray = {21, 16, 28};
}
数组的操作
操作数组元素
- 数组中的数据通过数组名和数组下标来操作数据,下标从0开始:
- 为元素赋值
public class Test2 {
public static void main(String[] args) {
double [] scores = new double[5];
scores[0] = 3.4;
scores[1] = 3.6;
scores[2] = 4.0;
scores[3] = 5.5;
scores[4] = 6.6;
}
}
- 获取元素值
public class Test2 {
public static void main(String[] args) {
double [] scores = new double[5];
scores[0] = 3.4;
scores[1] = 3.6;
scores[2] = 4.0;
scores[3] = 5.5;
scores[4] = 6.6;
System.out.println(scores[4]);//输出6.6
}
}
遍历数组元素
- 由于数组内存空间是连续的且从下标0开始,所以可以使用for循环遍历数组。
传统for循环
一维数组
public class Test2 {
public static void main(String[] args) {
int [] numbers = new int[] {21,99,3,1024,16};
System.out.println(numbers.length);//获取数组长度5
for(int i=0;i<numbers.length;i++) {
System.out.print(numbers[i]+",");
//遍历数组,不加ln表示不换行,以逗号分隔
}
}
}
二维数组
public class Test2 {
public static void main(String[] args) {
double [][] scores = {{100.0,88.7},{99.8,66.0,78.5}};
for(int i=0;i<scores.length;i++) {//获取有几个一维数组,有 2个
double [] score = scores[i];//将每个一维数组定义在新的一维数组中
for(int j=0;j<score.length;j++) {
System.out.print(score[j]+",");//输出不同一位数组中的值
}
}
}
}
加强for循环####
语法:
for (集合中元素数据类型 元素名 : 数组名) {
}
一维数组
public class Test2 {
public static void main(String[] args) {
int [] numbers = new int[] {21,99,3,1024,16};
for(int number:numbers) {
System.out.println(number);//注意不加[i];
}
}
}
二维数组
public class Test2 {
public static void main(String[] args) {
double [][] scores = {{100.0,88.7},{99.8,66.0,78.5}};
for(double [] score:scores) {
for(double sco:score) {
System.out.println(sco);//不加[i]
}
}
}
}
数组越界
public static void main(String[ ] args) {
int[ ] scores = new int[1];//总共有可存储一个数据
scores[0] = 90;
scores[1] = 85;
System.out.println(scores[1]);
}
值传递与引用传递
值传递
- 值传递(pass by value)是指在调用函数时将实际参数 复制 一份传递到函数中,这样在函数中如果对 参数 进行修改,将不会影响到实际参数。
public class array2 {
//将参数复制到函数中,无法通过函数改变参数
public static void main(String[] args) {
int x=6;
test(x);
System.out.println(x);//输出6
}
public static void test(int i) {
System.out.println(i);//输出6
i=0;
System.out.println(i);//输出0
}
}
引用传递
- 引用传递(pass by reference)是指在调用函数时将实际参数的地址 直接 传递到函数中,那么在函数中对 参数 所进行的修改,将影响到实际参数。
public class array2 {
//将实际参数的地址传递到函数中去,通过外部函数在此地址的改变参数即会影响参数
public static void main(String [] args) {
int [] numbers= {6};
print(numbers);
System.out.println(numbers[0]);//输出2
}
public static void print(int [] i) {
i[0] = 2;
}
}
数组的排序
冒泡排序
- 冒泡排序法是最基本的排序法之一,冒泡排序法的运行机制是通过循环遍历元素并调整相邻元素顺序来实现的一种简单排序方法。
- 冒泡排序的实质是 相邻两个元素比较,然后按照升序或降序调换位置。
public class Test2{
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+" ");
}
}
}
插入排序
- 每循环一次都将一个待排序的元素所对应的数据按其顺序大小插入到前面已经排序的序列的合适位置,直到全部插入排序完为止,其难点在于如何在前面已经排好序的序列中找到合适的插入位置。该排序方法有很多,比如直接插入排序、二分插入排序、希尔排序等等。
//{1,2,4,5,3}————>{1,2,3,4,5}
public class Test2{
public static void main(String [] args){
int [] numbers = {1,2,6,5,3,4,5};
for(int i=2;i<numbers.length;i++) {
int data = numbers[i];
//找位置
int j=0;
for(;j<i;j++) {
if(numbers[j]>numbers[i]) {
break;
}
}
if(j==i) {
continue;
}
//做移动
for(int k=i;k>j;k--) {
numbers[k]=numbers[k-1];
}
//插入
numbers[j]=data;//数据给插入的位置
}
for(int number:numbers) {
System.out.println(number);
}
}
}
- 插入排序的实质:
1、将数组分为有序区和无序区,定义一个标记无序区第一个元素的定位变量,
2、将该元素与前面的有序区内元素遍历比较,找到该元素应该插入位置,
3、然后将应插入位置到待插入元素所在位置之间的元素后移一位,
4、最后再将待插入元素插入到应插入的位置,有序区扩增一位,无序区减少一位,定位变量再次后移,锁定后面无序区第一位元素位置。
public class Test2{
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 Test2{
public static void main(String [] args){
int [] numbers = {1,4,6,7,9,12};
int data =4;
int low=0;
int high=numbers.length-1;
while(low<=high) {
int middle=(low+high)/2;
if(numbers[middle]<data) {
low=middle+1;//+1是因为middle所代表的值不包括在内
}else if(numbers[middle]>data) {
high=middle-1;//同理
}else {
System.out.println(middle);//输出1
break;
}
}
}
}