前言
学的进度很慢,想日报一样把每天新学的东西略作总结,会更有收获,就权当是个记录吧。
day_2 数组
数组的长度是不可变的,一旦分配好空间,是多长,就多长,不能增加也不能减少。
·创建数组的几种方法
以创造一个长度为5的数组为例:
int a[]=new int[5];//创建长度为5的数组,但不指定数组内的元素
int a[]=new int[] {1,2,3,4,5};//创建数组a,a含有五个元素,分别是1,2,3,4,5。
int a[]={1,2,3,4,5};//省略new int[]也是可以的。
int a[]=new int[5] {1,2,3,4,5};//即指定长度又指定内容的方法,但是长度必须和内容相匹配。
实践题目
1.数组最小值
首先创建一个长度是100的数组
然后给数组的每一位赋予随机整数
通过for循环,遍历数组,找出最小的一个值出来
int a[]=new int[100];
for(int i=0;i<100;i++) {
a[i]=(int) (Math.random() * 100);//Math.random() :到一个0-1之间的随机浮点数
System.out.println(a[i]);
}
int max=a[0];
int weishu=0,j=0;
for (j=0;j<100;j++){
if (a[j]>max){
max=a[j];
weishu=j;
}
}
System.out.println("最大值为数组中的第"+weishu+"位,它的值为:"+max);
或者,也可以用增强型for循环:
int a[] = new int[100];
for (int i = 0; i < 100; i++) {
a[i] = (int) (Math.random() * 100);//Math.random() :到一个0-1之间的随机浮点数
System.out.println(a[i]);
}
int max = 0;
for (int each : a) {
if (each > max)
max = each;
}
System.out.println("数组中的最大值为:" + max);
2.反转数组
首创建一个长度是10的数组,并填充随机数,对这个数组实现反转效果。这个题理解好了,对之后的反转链表会有帮助。
思路:
对于一个长度为n的数组a[n],下标为0——n-1。数组反转后,其中内容以n/2为界实现镜像翻转,即,a[0]与a[n-1]对换,a[1]与a[n-2]对换……以此类推。
int a[]=new int[10];
for(int i=0;i<10;i++) {
a[i]=(int) (Math.random() * 100);//Math.random() :到一个0-1之间的随机浮点数
System.out.println(a[i]);
}//随机生成一个10位数组
int space=0,j=0;
for (j=0;j<5;j++){
/*这里的5是10/2得到。考虑长度为n的数组,当n为奇数时,原数组最中间的数有两位,
分别是a[int(n/2)]与a[int(n/2)+1],根据代码,j会累加到n/2向下取整,
直到实现a[int(n/2)]与a[int(n/2)+1]对调;当n为偶数时,中间位只有一位即a[n/2],
j会累加到a[n/2-1],因为数组反转后a[n/2]仍为居中那位,因而不必反转。
因此此代码奇数偶数都适用。*/
space=a[j];
a[j]=a[10-1-j];//注意长度为n的数组,下标最大值为n-1,我第一次跑的时候忘记在n的基础上-1,然后报错了。
a[(10-1-j)]=space;
}
System.out.println("反转后数组为:");
for(int i=0;i<10;i++) {
System.out.println(a[i]);
}
3.数组的排序
这个也可以说是经典问题了,给出任意长度为n的数组,将其按照数值升序/降序排序。
冒泡排序
我只能想到冒泡法……,以n=10,实现降序排列为例:
int a[] = new int[10];
for (int i = 0; i < 10; i++) {
a[i] = (int) (Math.random() * 100);//Math.random() :到一个0-1之间的随机浮点数
System.out.println(a[i]);
}
int space, j;
for (int m=9;m>1;m--){//最大值是9是因为下标比长度小一位
for (j = 0; j < m; j++) {
if (a[j] < a[j + 1]) {//如果实现升序排列,把<改为>即可
space = a[j];
a[j] = a[j + 1];
a[j + 1] = space;
}
//紧挨的元素两两比较,最终把最小值放到数组末尾
}
}
System.out.println("排序后数组为:");
for (int i = 0; i < 9; i++) {
System.out.println(a[i]);
}
经过后来的学习,我知道了冒泡法是排序当中优先级很低的方法,它的时间复杂度为O(n2)。关于时间复杂度的计算,可以参考如下视频:link
但是网上看了一下冒泡排序的复杂度计算,很多没有过程,在这里浅析一下冒泡排序的时间复杂度计算:
冒泡排序的意义为:“排除已经通过冒泡实现了顺位的部分,将数组中剩余的部分的相邻的元素两两比较,每次比较中,如果出现逆序情况,则交换这组数据的位置以实现 ‘冒泡’ 。”
假设原数组长度为n,剩下需要比较的数组长度为m,则由于每次需要比较的数组部分的长度在递减,即(m=n;m>1;m–;),所以对于某固定的m,执行【比较】的次数为(m-1)+(m-2)+(m-3)+…+1=m*(m-1)/2。
“每次比较中,如果出现逆序情况,则交换这组数据的位置”。不难看出,在最好的情况下,数组本身就是顺序的,不需要进行元素交换(0次交换),所以执行交换次数为0次;在最坏的情况下每次都要进行交换,执行【交换】的次数为3*(m-1)次(因为交换这个步骤有3行代码)。
综上,在最坏的情况下代码执行的次数为:
在计算时间复杂度时,只考虑最高阶项,求和符号可以被忽略,加好右侧的项可以忽略;且不考虑系数,m最大等于(n-1),所以带入上式得出,冒泡排序的时间复杂度为O(n2)。
当时还想到另一种排序思路:从原数组中依次取出元素进行排列,每次将新取出的元素按照大小顺序插入已排好的(之前取出的)有序数组中,直到所有元素都被取出。这种方法又称为插入排序法。但是它的时间复杂度仍然是O(n2),因此同样不推荐。
更优的解法
对于排序,推荐的方法有快速排序法、归并排序法和堆排序。它们的时间复杂度都是O(N*logN),其空间复杂度分别是O(logN)、O(N)、O(1)。但值得注意的是,快速排序法是不稳定的,不稳定的意思是指,算法在排序过程中可能会使两个大小相等的元素之间发生交换,如果只是单纯的比较数值大小,确实没什么影响,但是有时候这个数值仅仅是某组数据中提取的一个标签,它们的位置交换会带来不可预测的后果。
目前我的学习只支持我理解这几个算法的原理,自己写出代码还有些困难,我想放在后面学习算法知识的时候再来填坑,这里不再赘述。
·复制数组的方法
System.arraycopy(src, srcPos, dest, destPos, length)
src: 源数组
srcPos: 从源数组复制数据的起始位置
dest: 目标数组
destPos: 复制到目标数组的起始位置
length: 复制的长度
练习:合并数组
将两个长度在5–10之间,且元素均为100内的整随机数的数组进行合并。
由于数组长度是固定不可更改的,因此只能新创建一个数组等于前两者的合并。
用到的方法:用random取随机数;用增强型for循环 for (int each : nums)遍历数组;用 System.arraycopy复制数组。
//利用Random类生成两个[5,10]之间的随机数n、m作为数组a,b的长度。
//记得要在最前面调库“import java.util.Random;”
Random rand = new Random();
int n=rand.nextInt(5 + 5);
int m=rand.nextInt(5 + 5);
int a[] = new int[n];
int b[] = new int[m];
//给a,b数组填充0-100的随机数
for (int i = 0; i < n-1; i++) {
a[i] = rand.nextInt(100);
}
for (int i = 0; i < m-1; i++) {
b[i] = rand.nextInt(100);
}
//用增强型for循环打印a,b数组
System.out.println("a数组:");
for (int each : a) {
System.out.println(each);
}
System.out.println("b数组:");
for (int each : b) {
System.out.println(each);
}
//之后再生成一个新数组,长度为a,b数组长度的和
int c[] = new int[m+n];
//利用System.arraycopy复制数组
System.arraycopy(a,0,c,0,n);
System.arraycopy(b,0,c,n,m);
System.out.println("c数组:");
for (int each : c) {
System.out.println(each);
}
·二维数组
二维数组,又被称为数组的数组,即该数组中的每个元素也是数组。创建二维数组的方法:
int[][] a = new int[内含数组的个数][每个数组的长度];
在实际应用中,可以只指定内含数组的个数而把长度空着,因为这些内含数组不一定都是等长的,如果在上式中一旦指定长度,表示所有元素的长度都一样。
需要注意的是,如果要访问某内含数组的元素,必须先规定该元素所在内含数组的长度。
练习:二维数组中的最大值
对于一个10x10的二维数组,其中数值为0-100的随机数,找出二维数组中的最大值。
Random rand = new Random();
int a[][]=new int[5][5];
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
int num=a[i][j] = rand.nextInt(100);
System.out.print(num+" ");//每行代表一个一维数组,子数组中的元素以空格分开
}
System.out.println("");//每个内含一维数组打印完毕后提行
}
int max=0;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (a[i][j]>max)
max=a[i][j];
}
}
System.out.println("数组a中最大值为"+max);
当然,打印二维数组也可以用嵌套增强型for循环:
for (int row[] : a) {//遍历二维数组a中的每一行row[]
for (int each : row) {
System.out.print(each + "\t");
}
System.out.println();
}
·数组工具Arrays(需要import java.util.Arrays;)
1.复制
生成一个新数组,该数组为已有数组a中,从第b个元素开始起到第c个元素为止但不包括第c个元素的复制,
Arrays.copyOfRange(a,b,c);
2. 排序
对a数组按照升序排序:
Arrays.sort(a);
3.查找某元素位置
查找a数组中特定原数值的位置,将返回该元素的下标值。
Arrays.binarySearch(a, 元素值);
当该元素值不唯一时,返回值也不唯一确定。
4.填充数组
将数组中填满某相同的元素a。
Arrays.fill(a, 要填充的值);
5. 转化字符串
将数组a转换成字符串,通常用在打印时。注意这个方法不适用二维数组,二维数组可以先强制for循环再转化字符串打印。
Arrays.toString(a);
6.判断两数组是否相同
判断a,b数组是否相同并返回一个布尔值,ture表示相同,false表示不同。
Arrays.equals(a, b);
练习:用Arrys方法对一随机5*8的二维数组排序
参考解答:
//生成一5*8的二维数组,其元素为100内的随机整数
Random rand = new Random();
int a[][]=new int[5][8];
for (int i=0;i<5;i++){
for (int j=0;j<8;j++){
a[i][j] = rand.nextInt(100);
}
}
//打印数组a
System.out.println("数组a为");
for (int[] row:a){
System.out.println(Arrays.toString(row));
}
//对二维数组展开为一维数组
int b[]=new int[40];
int destpos=0;
for (int[] row:a){
System.arraycopy(row,0,b,destpos,row.length);
destpos=destpos+row.length;
}
System.out.println(Arrays.toString(b));
//对一维数组进行排序,查看排序结果
Arrays.sort(b);
System.out.println(Arrays.toString(b));
int srcpos=0;
//把排序后的一维数组b的元素重新赋到二维数组a中。
//第一次写的时候用了下面这种方法,虽然后来反应过来,强制for循环只能读取数值,不能改写!但是这里运行的结果却又是对的,感到有些疑惑。
/*
for (int[] row:a){
System.arraycopy(b,srcpos,row,0,8);
srcpos=srcpos+8;
}*/
//用一般for循环实现:
int row_num;
for (row_num=0;row_num<5;row_num++){
a[row_num]=Arrays.copyOfRange(b,srcpos,srcpos+a[row_num].length);
srcpos=srcpos+a[row_num].length;
}
System.out.println("排序后的a数组为:");
for (int[] row:a) {
System.out.println(Arrays.toString(row));
}