第五节:数组
1.数组的定义
(1)定义:
数组是相同数据类型的数据按顺序组成的一种引用数据类型。
说明:
- 这里的“相同数据类型”是指数据在内存中的数据类型。
- 基本数据类型元素构成的数组也是引用类型。
(2)声明数组:
声明一维数组:数组元素数据类型 [ ] 数组名;
String [] countryArray;
声明二维数组:数组元素数据类型[ ][ ] 数组名;
double [] [] wagesArray;
(3)实例化数组:
声明数组仅仅给出了元素的数据类型和数组名字,要使用数组就必须为它分配内存空间,即实例化数组。当实例化一个数组时就申请了一段连续的内存空间存储数组中的元素。实例化数组的方法有两种:
①数组分配内存空间时指明数组长度;
语法格式:数组名 = new 数组元素数据类型 [数组元素个数];
例如:
double [] scores = new double [3];
String [] [] accounts =new String [3][2];
②采用穷举法实例化数组:
例如:
double [] scores = {9.9,8.8,7.7};
double [] scores;
scores=new double [] {9.9,8.8,7.7};
double [] scores=new double [] {9.9,8.8,7.7};
String [] [] accounts = {{"小张","123"},{"小李","456"},{"小焦","789"}};
String [] [] accounts = new String [][] {{"小张","123"},{"小李","456"},{"小焦","789"}};
错误示例:
public static void main(String[ ] args){
int[ ] scoreArray = new int[5];
scoreArray = {60, 80, 90, 70, 85};
int[ ] ageArray;
ageArray = {21, 16, 28};
}
`编译阶段出错,上面这种穷举法只能用于初始化数组,即必须和声明数组代码放在一条语句中完成。
2.数组的操作
(1)赋值和获取元素值:
通过数组名和数组下标来操作数据,下标从0开始:
(2)遍历数组:
有两种方法遍历数组,传统方法简单,不作阐述,第二种方法语法如下:
for (集合中元素数据类型 元素名 : 数组名) {
}
示例如下:
double [] scores = new double[3];
//如何赋值
scores[0] = 99.0;
scores[1] = 66.6;
scores[2] = 88;
//如何遍历数组
for(int i=0;i<scores.length;i++) {
//如何获取值
System.out.println(scores[i]);
}//方法1
for(double score:scores) {
System.out.println(score);
}//方法2
3.值传递与引用传递
(1)值传递:
值传递(pass by value)是指在调用函数时将实际参数 复制 一份传递到函数中,这样在函数中如果对 参数 进行修改,将不会影响到实际参数。
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;
}
}
(2)引用传递:
引用传递(pass by reference)是指在调用函数时将实际参数的地址 直接 传递到函数中,那么在函数中对 参数 所进行的修改,将影响到实际参数。
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;
}
}
4.数组的排序
(1)冒泡排序法:
冒泡排序法是最基本的排序法之一,冒泡排序法的运行机制是通过循环遍历元素并调整相邻元素顺序来实现的一种简单排序方法。
以数组 {21, 99, 3, 1024, 16}升序排列为例演示冒泡排序的原理:
代码如下:
int temp;
int [] numbers = new int [] {21,99,3,1024,16};
for(int time=1;time<numbers.length;time++) {
for(int i=0;i<numbers.length-time;i++) {//亮点:减去time可减少多余的循环次数,提高代码的性能
temp=numbers[i+1];
numbers[i+1]=numbers[i];
numbers[i]=temp;
}
}
for(int i=0;i<numbers.length;i++)
System.out.print(numbers[i]+"\t");
(2)插入排序:
- 每循环一次都将一个待排序的元素所对应的数据按其顺序大小插入到前面已经排序的序列的合适位置,直到全部插入排序完为止,其难点在于如何在前面已经排好序的序列中找到合适的插入位置。该排序方法有很多,比如直接插入排序、二分插入排序、希尔排序等等。
- 先看如何解决这个问题:已知数组{1, 2, 4, 5, 3},将3插入到适当位置,使之成为一个升序排列的数组,即{1, 2, 3, 4, 5}。
int [] numbers = {1,2,4,5,3};
int i=4;//3的位置
int data = numbers[i];
//1、找位置
int j=0;
for(;j<i;j++) {
if(numbers[j]>numbers[i]) {
break;
}
}
//2、做移动
for(int k=i;k>j;k--) {
numbers[k] = numbers[k-1];
}
//3、插入数据
numbers[j]=data;
//遍历数组
for(int number:numbers) {
System.out.println(number);
}
语法结构及解释阐述如下:
例如数组{2,8,6,7,0,9}代码如下:
int [] numbers = {2,8,6,7,0,9};
for(int i=1;i<numbers.length;i++) {
int data = numbers[i];
//1、找位置
int j=0;
for(;j<i;j++) {
if(numbers[j]>numbers[i]) {
break;
}
}
//2、做移动
for(int k=i;k>j;k--) {
numbers[k] = numbers[k-1];
}
//3、插入数据
numbers[j]=data;
}
//遍历数组
for(int number:numbers) {
System.out.println(number);
}
性能提升小方法:如果比较的两个数字大小相同,那么就会多执行下面的移动和插入数据步骤,因此在找位置和做移动之间加入continue去掉不必要的循环,如下图:
插入排序的实质:将数组分为有序区和无序区,定义一个标记无序区第一个元素的定位变量,将该元素与前面的有序区内元素遍历比较,找到该元素应该插入位置,然后将应插入位置到待插入元素所在位置之间的元素后移一位,最后再将待插入元素插入到应插入的位置,有序区扩增一位,无序区减少一位,定位变量再次后移,锁定后面无序区第一位元素位置。
5.数组元素查找
普通查找法:直接遍历数组的每个元素与要查找的元素相比较,若相同,输出所在位置并结束循环遍历(数组中不含相同元素且可以无序);
二分法查找:搜索数据与有序数组(比如升序)中间元素比较以确定在中间元素左边还是右边,如果在右边,则调整最小搜索索引值,然后进入下次循环;如果在左边,则调整最大搜索索引值,然后进入下次循环;如果相等则当前位置就是查找数据所在位置,停止循环;
语法结构及例子如下:
例如在数组{1,2,3,4,5}中查找数据2
int [] numbers = new int [] {1,2,3,4,5};
int data=2;//要查找的数据
int middle;
int low = 0;
int high = numbers.length-1;
while(low<=high) {
middle=(low+high)/2;
if(data>numbers[middle]) {
low=middle+1;
}else if(data<numbers[middle]) {
high=middle-1;
}else {
System.out.println(middle);
break;
}
}