Javase---数组
一、数组的概述
-
数组的理解
-
- 数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理
-
数组相关概念
-
- 数组名
- 元素
- 角标、下标、索引(从0开始)
- 数组的长度:元素的个数
-
数组的特点
-
- 数组是有序排列的
- 数组属于引用数据类型,数据的元素既可以是基本数据类型,也可以是引用数据类型
- 创建数据对象会在内存中开辟一整块连续的空间
- 数据的长度一旦确定,就不能修改
-
数组的分类
-
- 按照维度:一维数组、二维数组
- 按照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组
二、一维数组的使用
-
一维数组的使用:声明
-
- 一维数组的声明方式:type var[] 或type[] var;例如:int a[]; int[] a1; double b[]; String[] c;//引用类型变量数组
- Java语言中声明数组时不能指定其长度(数组中元素的数),例如:int a[5];//非法
-
一维数组的使用:初始化
-
- 动态初始化:数组声明且为数组元素分配空间与赋值的操作分开进行
- 静态初始化:在定义数组的同时就为数组元素分配空间并赋值
-
一维数组的使用:数组元素的引用
-
- 定义并用运算符new为之分配空间后,才可以引用数组中的每个元素
- 数组元素的引用方式:数组名[数组元素下标]
-
-
- 数组元素下标可以是整型常量或者是整型表达式。如:a[3],b[i],c[6*i]
- 数组元素下标从0开始:长度为n的数组合法下标取值范围为:0->n-1
-
-
- 每个数组都有一个属性length指明它的长度,如:a.length为数组a的长度
public class ArrayTest{
public static void main(String[] args){
//1.一维数组的声明和初始化
int num;//声明
num = 10;//初始化
int num = 1001;//声明+初始化
int[] ids;//声明
//1.1静态初始化:数组的初始化和数组元素的赋值操作同时进行
ids = new int[]{1001,1002,1003,1004,1005};
//1.2动态初始化:数组的初始化和数组元素的赋值操作分开进行
String[] names = new String[5];
//错误的写法:
int[] arr1 = new int[];
int[5] arr2 = new int[5];
int[] arr3 = new int[3]{1,2,3};
//也是正确的写法:
int[] arr4 = {1,2,3,4,5};//类型判断:静态初始化
//总结:数组一旦初始化完成,其长度就确定了。
//2.如何调用数组的指定位置的元素:通过角标的方式调用。
//数组的角标(或索引)从0开始,到数组的长度-1结束。
names[0] = "王铭";
names[1] = "王赫";
names[2] = "张学良";
names[3] = "孙居龙";
names[4] = "王宏志";//charAt(0)
names[5] = "周扬";
//3.如何获取数组的长度。
//属性:length
System.out.println(name.length);//5
System.out.println(ids.length);
//如何遍历数组
/*System.out.println(names[0]);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);
System.out.println(names[4]);*/
for(int i = 0;i < names.length;i++){
System.out.println(names[i]);
}
}
}
-
一维数组的使用:数组元素的默认初始化值
-
- 对于基本数据类型而言,默认初始化值各有不同
- 对于引用数据类型而言,默认初始化值为null(与0不同!)
-
一维数组的使用:一维数组的内存解析
-
- 栈(stack):局部变量
- 堆(heap):new出来的结构:对象,数组
package com.er.java;
/*
* ⑤ 数组元素的默认初始化值
* > 数组元素是整型:0
* > 数组元素是浮点型:0.0
* > 数组元素是char型:0或'\u0000',而非'0'
* > 数组元素是boolean型:false
*
* > 数组元素是引用数据类型:null
*
* ⑥ 数组的内存解析
*/
public class ArrayTest1 {
public static void main(String[] args) {
//5.数组元素的默认初始化值
int[] arr = new int[4];
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
System.out.println("**********");
short[] arr1 = new short[4];
for(int i = 0;i < arr1.length;i++){
System.out.println(arr1[i]);
}
System.out.println("**********");
float[] arr2 = new float[5];
for(int i = 0;i < arr2.length;i++){
System.out.println(arr2[i]);
}
System.out.println("**********");
char[] arr3 = new char[4];
for(int i = 0;i < arr3.length;i++){
System.out.println("----" + arr3[i] + "****");
}
if(arr3[0] == 0){
System.out.println("你好!");
}
System.out.println("**********");
boolean[] arr4 = new boolean[5];
System.out.println(arr4[0]);
System.out.println("**********");
String[] arr5 = new String[5];
System.out.println(arr5[0]);
if(arr5[0] == null){
System.out.println("北京天气不错!");
}
}
}
-
- 内存的简化结构
三、多维数组的使用
-
理解
-
- 对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。其实,从数组底层的运行机制来看,其实没有多维数组
-
二维数组的使用
-
- 规定:二维数组分为外层数组的元素,内层数组的元素
- int[][] arr = new int[4][3];
外层元素:arr[0],arr[1]等
内层元素:arr[0][0],arr[1][2]等
-
- 二维数组的声明和初始化
- 如何调用数组的指定位置的元素
- 如何获取数组的长度
- 如何遍历数组
public class ArrayTest2{
public static void main(String[] args){
//1.二维数组的声明和初始化
int[] arr = new int[]{1,2,3};//一维数组
//静态初始化
int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
//动态初始化1
String[][] arr2 = new String[3][2];
//动态初始化2
String[][] arr3 = new String[3][];
//错误的情况
// String[][] arr4 = new String[][4];
// String[][] arr5 = new String[][];
// int[][] arr6 = new int[4][3]{{1,2,3},{4,5},{6,7,8}};
//也是正确的写法
int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};
//2.如何调用数组的指定位置的元素
System.out.println(arr1[0][1]);//2
System.out.println(arr2[1][1]);//null
arr3[1] = new String[4];
System.out.println(arr3[1][0]);
//3.获取数组的长度
System.out.println(arr4.length);//3
System.out.println(arr4[0].length);//3
System.out.println(arr4[1].length);//4
//4.如何遍历二维数组
for(int i = 0;i < arr4.length;i++){
for(int j = 0;j < arr4[i].length;j++){
System.out.print(arr4[i][j] + " ");
}
System.out.println();
}
}
}
-
- 数组元素的默认初始化值:见ArrayTest3.java
-
-
- 针对初始化方式一:比如:int[][] arr = new int[4][3];
-
-
-
-
- 外层元素的初始化值为:地址值
- 内层元素的初始化值为:与一维数组初始化情况相同
-
-
-
-
- 针对于初始化方式二:比如:int[][] arr = new int[4][];
-
-
-
-
- 外层元素的初始化值为:null
- 内层元素的初始化值为:不能调用,否则报错。
-
-
-
- 数组的内存解析:见ArrayTest3.java
public class ArrayTest3 { public static void main(String[] args) { int[][] arr = new int[4][3]; System.out.println(arr[0]);//[I@15db9742 System.out.println(arr[0][0]);//0 // System.out.println(arr);//[[I@6d06d69c System.out.println("*****************"); float[][] arr1 = new float[4][3]; System.out.println(arr1[0]);//地址值 System.out.println(arr1[0][0]);//0.0 System.out.println("*****************"); String[][] arr2 = new String[4][2]; System.out.println(arr2[1]);//地址值 System.out.println(arr2[1][1]);//null System.out.println("*****************"); double[][] arr3 = new double[4][]; System.out.println(arr3[1]);//null // System.out.println(arr3[1][0]);//报错 } }
-
- 二维数组的内存解析
-
- 练习4---杨辉三角
- 使用二维数组打印一个 10 行杨辉三角。
【提示】
-
-
- 第一行有 1 个元素, 第 n 行有 n 个元素
- 每一行的第一个元素和最后一个元素都是 1
- 从第三行开始, 对于非第一个元素和最后一个元
素的元素。即:
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
-
public class yanghui {
public static void main(String[] args) {
//声明并初始化二维数组
int[][] yanghui = new int[10][];
for(int i = 0;i < yanghui.length;i++){
yanghui[i] = new int[i+1];
yanghui[i][0] = yanghui[i][i] = 1;
for(int j = 1;j < yanghui[i].length - 1;j++){
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
}
}
for(int i = 0;i < yanghui.length;i++){
for(int j = 0;j < yanghui[i].length;j++){
System.out.print(yanghui[i][j] + " ");
}
System.out.println("");
}
}
}
四、数组中涉及到的常见算法
-
练习
/*求数值型数组中元素的最大值、最小值、平均数、总和等
*
* 定义一个int型的一维数组,包含10个元素,分别赋一些随机整数,
* 然后求出所有元素的最大值,最小值,和值,平均值,并输出出来。
* 要求:所有随机数都是两位数。
*
* [10,99]
* 公式:(int)(Math.random() * (99 - 10 + 1) + 10)
*/
public class ArrayTest1 {
public static void main(String[] args) {
int[] arr = new int[10];
for(int i = 0;i < arr.length;i++){
arr[i] = (int)(Math.random() * (99 - 10 + 1) + 10);
}
//遍历
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");
}
System.out.println();
//求数组元素的最大值
int maxValue = arr[0];
for(int i = 1;i < arr.length;i++){
if(maxValue < arr[i]){
maxValue = arr[i];
}
}
System.out.println("最大值为:" + maxValue);
//求数组元素的最小值
int minValue = arr[0];
for(int i = 1;i < arr.length;i++){
if(minValue > arr[i]){
minValue = arr[i];
}
}
System.out.println("最小值为:" + minValue);
//求数组元素的总和
int sum = 0;
for(int i = 0;i < arr.length;i++){
sum += arr[i];
}
System.out.println("总和为:" + sum);
//求数组元素的平均数
int avgValue = sum / arr.length;
System.out.println("平均数为:" + avgValue);
}
}
/*
* 算法的考查:数组的复制、反转、查找(线性查找、二分法查找)
*
*
*/
public class ArrayTest2 {
public static void main(String[] args) {
String[] arr = new String[]{"JJ","DD","MM","BB","GG","AA"};
//数组的复制(区别于数组变量的赋值:arr1 = arr)
String[] arr1 = new String[arr.length];
for(int i = 0;i < arr1.length;i++){
arr1[i] = arr[i];
}
//数组的反转
//方法一:
// for(int i = 0;i < arr.length / 2;i++){
// String temp = arr[i];
// arr[i] = arr[arr.length - i -1];
// arr[arr.length - i -1] = temp;
// }
//方法二:
// for(int i = 0,j = arr.length - 1;i < j;i++,j--){
// String temp = arr[i];
// arr[i] = arr[j];
// arr[j] = temp;
// }
//遍历
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");
}
System.out.println();
//查找(或搜索)
//线性查找:
String dest = "BB";
dest = "CC";
boolean isFlag = true;
for(int i = 0;i < arr.length;i++){
if(dest.equals(arr[i])){
System.out.println("找到了指定的元素,位置为:" + i);
isFlag = false;
break;
}
}
if(isFlag){
System.out.println("很遗憾,没有找到的啦!");
}
//二分法查找:(熟悉)
//前提:所要查找的数组必须有序。
int[] arr2 = new int[]{-98,-34,2,34,54,66,79,105,210,333};
int dest1 = -34;
dest1 = 35;
int head = 0;//初始的首索引
int end = arr2.length - 1;//初始的末索引
boolean isFlag1 = true;
while(head <= end){
int middle = (head + end)/2;
if(dest1 == arr2[middle]){
System.out.println("找到了指定的元素,位置为:" + middle);
isFlag1 = false;
break;
}else if(arr2[middle] > dest1){
end = middle - 1;
}else{//arr2[middle] < dest1
head = middle + 1;
}
}
if(isFlag1){
System.out.println("很遗憾,没有找到的啦!");
}
}
}
-
-
二分法查找
-
//二分法查找:要求此数组必须是有序的。
public class BinarySearch{
int[] arr3 = new int[]{-99,-54,-2,0,2,33,43,256,999};
boolean isFlag = true;
int number = 256;
//int number = 25;
int head = 0;//首索引位置
int end = arr3.length - 1;//尾索引位置
while(head <= end){
int middle = (head + end) / 2;
if(arr3[middle] == number){
System.out.println("找到指定的元素,索引为:" + middle);
isFlag = false;
break;
}else if(arr3[middle] > number){
end = middle - 1;
}else{//arr3[middle] < number
head = middle + 1;
}
}
if(isFlag){
System.out.println("未找打指定的元素");
}
}
-
-
排序算法
-
-
-
- 排序:假设含有n个记录的序列为{R1,R2,...,Rn},其相应的关键字序列为 {K1,K2,...,Kn}。将这些记录重新排序为{Ri1,Ri2,...,Rin},使得相应的关键 字值满足条Ki1<=Ki2<=...<=Kin,这样的一种操作称为排序。
- 通常来说,排序的目的是快速查找。
- 衡量排序算法的优劣:
-
-
-
-
- 1.时间复杂度:分析关键字的比较次数和记录的移动次数
- 2.空间复杂度:分析排序算法中需要多少辅助内存
- 3.稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。
-
-
-
-
十大内部排序算法
-
-
-
- 选择排序
-
-
-
-
- 直接选择排序、堆排序
-
-
-
-
- 交换排序
-
-
-
-
- 冒泡排序、快速排序
-
-
-
-
- 插入排序
-
-
-
-
- 直接插入排序、折半插入排序、希尔排序
-
-
-
-
- 归并排序
- 桶式排序
- 基数排序
-
-
-
算法的五大特征
-
-
-
- 输入、输出、有穷性(有限性)、确定性(明确性)、可行性(有效性)
-
-
-
冒泡排序
-
-
-
- 排序思想:
-
-
-
-
- 1.比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个
- 2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 3.针对所有的元素重复以上的步骤,除了最后一个。
- 4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止。
-
-
-
-
快速排序
-
-
-
- 排序思想:
- 1.从数列中挑出一个元素,称为“基准”(pivot)
- 2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作
- 3.递归地(recursive)把小于基准值元素的子数列和大于基准值的子数列排序
- 4.递归的最底部清醒,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去
-
-
-
排序算法的性能对比
-
-
-
各种内部排序算法方法性能比较
-
-
-
- 1.从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序
- 2.从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较 简单,将其认为是简单算法。对于Shell排序、堆排序、快速排序和归并排序 算法,其算法比较复杂,认为是复杂排序。
- 3.从稳定性看:直接插入排序、冒泡排序和归并排序是稳定的;而直接选择排序、快速排序、Shell排序和堆排序是不稳定排序
- 4.从待排序的记录数n的大小看:n较小时,宜采用简单排序;而n较大时宜采用改进排序。
-
-
-
排序算法的选择
-
-
-
- (1)若n较小(如n≤50),可采用直接插入或直接选择排序。当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插入,应选直接选择排序为宜。
-
-
-
- (2)若文件初始状态基本有序(指正序),则应选用直接插入、冒泡或随机的快速排序为宜;
- (3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
-
五、Arrays工具类的使用
- java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(排序和搜索等)的各种方法
六、数组使用中常见的异常