第七章:一维数组
一.数组的基本知识
1.三种创建数组的方法
int[] array=new int[3];
array[0]=1;
array[1]=2;
array[2]=3;
int[] array={1,2,3};
int[] array=new array[]{1,2,3};
错误创建数组示例:int[] array;array={1,2,3,4};
2.数组的打印
数组只能由循环打印输出
int[] array={1,2,3,4};
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");//1 2 3 4
}
//java支持一种简便的for循环,foreach循环
for(int i:array){//其中i的类型必须与数组array中元素类型相同
System.out.print(i+" ");//1 2 3 4
}
但是,对于char类型数组可以直接输出
char[] array={'h','e','l','l','o'};
System.out.println(array);//hello
3.注意
- 创建数组后不能修改它的大小,可以使用array.length方法得到数组大小
- 数组中的元素都必须为相同类型
- 声明数组是并不给数组变量分配内存空间,只是创建数组的引用的存储位置
int[] array;//不包含对数组的引用,array的值为null,除非数组已经创建,否则不能给它分配任何空间
- 声明数组后,可以使用new操作符创建一个数组,并将它的引用赋给一个变量
int[] array;
array=new int[5];
- 一个数组变量看起来存储了一个数组,其实存储的是指向数组的引用
- 创建数组后,它的元素都被赋予默认值
int[] array=new int[3];//数据的基本类型都被赋予0
char[] array2=new char[3];//char类型都被赋予'\u0000'
boolean[] array3=new boolean[3];//boolean类型都被赋予false
- 创建数组是要赋予初始大小
二.复制数组
array2=array1
此法不能将数组array1引用的数组的内容赋值给数组2,而是将array1的引用赋给了array2,他们指向同一个数组
赋值前 | 赋值后 |
array1 -> larray1的内容 | array1 -> larray1的内容 |
array2 -> larray2的内容 | array2 -> larray1的内容 |
array2原先所引用的数组会变成垃圾,不能再使用,会被JVM自动回收
所以复制数组有三种方法
- 使用循环语句逐个的复制数组元素
- 使用System类中的静态方法arraycopy
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] array = { 'h', 'e', 'l', 'l', 'o' };
char[] array2 = { 'j', 'a', 'v', 'a' };
System.arraycopy(array, 0, array2, 1, 2);
System.out.println(array2);//jhea
}
System.arraycopy(源数组,源数组起始,目标数组,目标数组起始,源数组复制到目标数组的个数)
arraycopy是唯一一个没有按方法命名规则的方法
注意复制长度不能超过目标数组长度
- 使用clone()方法复制数组(后面章节详解)
三.将数组传递给方法和从方法中返回数组
1.将数组传递给方法
int[] array={5,6,7,8,3};
printArray(array);
printArray(new int[]{1,2,3,4});//没有显式引用变量,传递一个匿名数组
public static void printArray(int[] array){}
2.与基本类型传参的区别
基本类型传递的是实参的值,而数组传递的是引用,基本类型的实参不会受到变换,而数组会发生变化
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] array = { 'h', 'e', 'l', 'l', 'o' };
int x = 1;
changeArray(x, array);
System.out.println(x);//1 未发生改变
System.out.println(array);//Jallo 发生改变
}
public static void changeArray(int y, char[] list) {
list[0] = 'J';
list[1] = 'a';//array[0]和array[1]发生变化
y = 2;
}
接下来这个案例有一点迷惑性,请擦亮双眼
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] array = { 'o', 'k' };
// swapArray(array);
// System.out.println(array);//ko 值变了
swapArray(array[0], array[1]);
System.out.println(array);//ok 不变
}
public static void swapArray(char[] list) {
char temp = list[0];
list[0] = list[1];
list[1] = temp;
}
public static void swapArray(char a, char b) {
char temp = a;
a = b;
b = temp;
}
2.从方法中返回数组
案例:在不使用新数组的情况下倒置数组
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = { 1, 2, 3, 4, 5 };
for (int i : trans(array))
System.out.print(i + " ");//5 4 3 2 1
}
public static int[] trans(int[] list) {
for (int i = 0, j = list.length - 1; i <= list.length / 2 && j >= list.length / 2; i++, j--) {
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}
return list;
}
四.可变长参数列表、数组的查找、数组排序
1.可变长参数列表
语法:typeName…parameter(类型名…参数名)
java将可变长参数当做数组对待
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = { 1, 2, 3, 4, 5 };
printMax(array);
printMax(new int[] { 6, 7, 4, 9, 2 });
}
public static void printMax(int... list) {//可变长参数
if (list.length == 0) {
System.out.println("list is null");
System.exit(1);
}
int max = list[0];
for (int i = 0; i < list.length; i++) {
if (list[i] > max) {
max = list[i];
}
}
System.out.println(max);//5 9
}
【补充 20220217】
可变参数长度使用场景:当不确定参数有多少个的时候使用
- 可变长参数列表必须是列表的最后一个
- 可以个体可变长参数列表传递数组,并且可以当作数组使用
- 可以传递0或多个参数
- 可变长参数和数组作为参数实际上是一个方法,不能构成重载
3.冒泡排序
基本思想:里层循环找出最大值放到最后一位,循环a.length次
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = { 5, 45, 68, 79, 48, 35, 46, 52, 15, 46, 12, 78, 98, 31 };
for (int j = 0; j < a.length; j++) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {//如果a[i]>a[i+1],则互换位置
int max = a[i];
a[i] = a[i + 1];
a[i + 1] = max;
}
}
}
for (int i : a) {
System.out.print(i+" ");//5 12 15 31 35 45 46 46 48 52 68 78 79 98
}
}
3.选择排序
基本思想:从索引i开始往后找到最小值与i对应的值互换
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = { 5, 45, 68, 79, 48, 35, 46, 52, 15, 46, 12, 78, 98, 31 };
for (int i = 0; i < a.length; i++) {
int min = a[i];// 设置当前最小值
int currentIndex = i;// 设置当前索引
for (int j = i; j < a.length; j++) {// 找到最小值和最小值的索引
if (a[j] < min) {
min = a[j];
currentIndex = j;
}
}
if (currentIndex != i) {// 如果最小值索引不等于i,则互换位置
a[currentIndex] = a[i];
a[i] = min;
}
}
for (int i : a) {
System.out.print(i + " ");
}
}
4.快速排序
基本思想:设置一个中间元素,即运用递归保证中间元素左边的都小于中间元素,右边的都大于中间元素
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = { 45, 68, 79, 48, 35, 46, 52, 31 };
quickSort(a, 0, a.length - 1);// 传入数组和排序区间
for (int i : a) {
System.out.print(i + " ");
}
}
public static void quickSort(int[] a, int begin, int end) {
if (begin - end >= 1) {
return;
}
boolean b = true;// 作为左右比较的开关,并默认从右边开始比较
int leftIndex = begin;// 设置左边指针为初始位置
int currentMid = a[begin];// 设置中间的比较元素
int rightIndex = end;// 设置右边指针为截止位置
L: while (leftIndex < rightIndex) {
if (b) {// 从右边开始比较
for (int i = rightIndex; i > leftIndex; i--) {
if (a[i] <= currentMid) {// 如果有比中间元素小的,则进行交换操作
a[leftIndex++] = a[i];// 左指针向右移动
b = !b;// 此时开关变为向左比较
continue L;
} else {// 不满足时右指针向左移动
rightIndex--;
}
}
rightIndex = leftIndex;// 循环都不满足时,设置二者相等跳出while
} else {// 当指针从左向右移动时
for (int i = leftIndex; i < rightIndex; i++) {
if (a[i] >= currentMid) {// 如果元素大于等于中间比较元素,则进行交换操作
a[rightIndex--] = a[i];// 并将右指针位置左移
b = !b;// 此时开关变为向右比较
continue L;
} else {// 不满足时左指针向右移
leftIndex++;
}
}
leftIndex = rightIndex;// 循环都不满足时,设置二者相等跳出while
}
}
a[leftIndex] = currentMid;// 左指针此时等于右指针,将中间元素放入,保证中间元素的左边全部小于中间元素,右边全部大于中间元素
quickSort(a, begin, leftIndex - 1);// 排序中间元素左边的数组
quickSort(a, leftIndex + 1, end);// 排序中间元素右边的数组
}
2.数组的查找
二分查找必须在数组排好序的情况下
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = { 45, 68, 79, 89, 93, 123, 153, 159 };
System.out.println(find(a, 93));// 传入数组和查找的元素
}
public static boolean find(int[] a, int y) {
int low = 0;//创建初始指针
int high = a.length - 1;//创建结束指针
while (low <= high) {
int mid = (low + high) / 2;//设置中间指针
if (a[mid] < y) {//如果中间元素<查找元素
low = mid + 1;//初始指针设置为中间之后后面一位
} else if (a[mid] == y) {//如果中间元素=查找元素
return true;//找到
} else {//如果中间元素>查找元素
high = mid - 1;//结束指针设置为中间之后前面一位
}
}
return false;//全都找不到,则返回
}
二分查找需要log2n次的比较,即使是最坏的情况也是log2n+1次比较
【补充】——20200323
二分查找
返回第一个匹配的元素的下标
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
// 创建一个数组
int[] array = { 1, 4, 4, 5, 7, 9 };
// 输入要查找的数
int a = in.nextInt();
System.out.println(getIndex(array, array.length, a));
}
public static int getIndex(int[] array, int n, int a) {
// 当数组长度为0或者数组为空时返回-1
if (n <= 0 || array == null)
return -1;
// 创建初始指针
int low = 0;
// 创建结尾指针
int high = n - 1;
while (low < high) {
int mid = (low + high) / 2;
if (array[mid] < a) {
low = mid + 1;
} else if (array[mid] > a) {
high = mid - 1;
} else
high = mid;
}
if (array[low] == a) {
return low;
}
return -1;
}```
## 五.Arrays类
**1.Arrays.sort()排序**
```java
public static void main(String[] args) {
// TODO Auto-generated method stub
double[] array = { 3.5, 2.4, 8.9, 34.5, 23.7, 23.9, 54 };
java.util.Arrays.sort(array);//排序
for (double i : array)
System.out.print(i + " ");
}
}
【补充 20220217】
原理是通过快排的方式
2.Arrays.equals()比较
public static void main(String[] args) {
// TODO Auto-generated method stub
double[] array = { 3.5, 2.4, 8.9, 34.5, 23.7, 23.9, 54 };
double[] array2 = { 6.3, 2.4, 8.9, 34.5, 23.7, 23.9, 54 };
System.out.println(java.util.Arrays.equals(array, array2));//false
}
3.Arrays.fill()填充
public static void main(String[] args) {
// TODO Auto-generated method stub
double[] array = { 3.5, 2.4, 8.9, 34.5, 23.7, 23.9, 54 };
java.util.Arrays.fill(array, 5);//全部填充
for (double i : array)
System.out.print(i + " ");//5.0 5.0 5.0 5.0 5.0 5.0 5.0
}
public static void main(String[] args) {
// TODO Auto-generated method stub
double[] array = { 3.5, 2.4, 8.9, 34.5, 23.7, 23.9, 54 };
java.util.Arrays.fill(array, 1, 5, 8);//从1到5-1填充8
for (double i : array)
System.out.print(i + " ");//3.5 8.0 8.0 8.0 8.0 23.9 54.0
}
4.Arrays.toString()转为字符串
public static void main(String[] args) {
// TODO Auto-generated method stub
double[] array = { 3.5, 2.4, 8.9, 34.5, 23.7, 23.9, 54 };
System.out.println(java.util.Arrays.toString(array));//[3.5, 2.4, 8.9, 34.5, 23.7, 23.9, 54.0]
}
【补充 20220217】
补充两点
- 有两种方式可以阻止继承,一种是构造方法私有,一种是用final修饰
但是构造方法私有可以用静态内部类破解
class A{
private A(){
System.out.println("A创建了");
}
private void e(){
System.out.println("e");
}
public void test(){
e();
System.out.println("test");
}
// 使用静态内部类
public static class B extends A{
public B(){
System.out.println("B创建了");
}
@Override
public void test() {
// 重写A中的test方法
super.test();
}
}
}
class C extends A.B{
public C(){
System.out.println("C创建了");
}
@Override
public void test() {
// 重写B中的test方法
super.test();
}
}
public class Test6 {
public static void main(String[] args) {
// A a = new A("34");
C c = new C();
c.test();
System.out.println();
}
}
- Arrays.asList(T…a)生成List的集合
T 继承Object,所以传递基本数据类型不行
六.命令行参数
1.可以向main函数传递参数
2.运行程序时没有传递参数,使用new String[0]创建数组,args.length=0,因此args不等于null
3.命令行运行乘法时避免使用*,因为*一般代表所有文件
4.命令行调用时,向main中args传参数如果有空格用“”括起来,没有就不用
public static void main(String[] args){
if(args.length!=0){
System.out.println(java.util.Arrays.toString(args));
}
}
七.总结
通过对本章的学习,我学会了创建数组,复制数组的三种方法,通过方法调用和返回数组,对数组进行排序和查找,学会了使用Arrays类,以及通过命令行向main方法传参数。
加油!第八章待更……