Java数组
一、
数组中常出现的异常
class Demo
{
public static void main(String []args){
int []x = new int[3];
int []y = new int[3];
y[1] = 89;
x = null;
sop(x[1]);
}
}
x[1]是多少呢?
NullPointerException空指针异常:当引用没有任何指向,值为null的情况,该引用还在用于操作实体,就会报该异常。
报NullPointerException异常。因为x被赋值为null,原来指向new int[3]的引用没有了。所以就会抛空指针异常。
图示:
int []arr = new int[]{3,1,6,5,4};//静态初始化方式
int []arr = {3,1,6,5,4};
class Demo
{
public static void main(String []args){
int []arr = new int[3];
System.out.println(arr[3]);
}
}
ArrayIndexOutOfBoundsException数组角标越界异常。因为操作数组时,访问到了数组中不存在的角标。
报ArrayIndexOutOfBoundsException异常。因为角标从0开始,而数组长度为3,没有为3的角标位。操作超过了数组范围,所以报数组角标越界异常。
二、数组的操作
遍历:获取数组中的元素,通常会用到遍历。
length:作为数组中的一个属性,可以直接获取到元素个数。使用方式:数组名称.length。
需求:定义功能,用于打印数组中的元素,元素间用
“,”隔开。
class Demo
{
public static void main(String []args){
int []arr = {1,2,3,4,5,6};
printArray(arr);
}
public static void printArray(int []arr){
System.out.print("[");
for(int x=0;x<arr.length;x++){
if(x==arr.length-1)
System.out.println(arr[x]+"]");
else
System.out.print(arr[x]+",");
}
}
}
class Demo
{
public static void main(String []args){
int []arr = {1,2,3,4,5,6};
System.out.println(arr);
}
}
[I@de6ced的含义:[I@de6ced是数组存放在堆内存中的地址值,“[”表示是数组类型,“I”表示是int类型,“@”表示是引用,“de6ced”表示数组存放的内存地址。该值是由哈希算法得来。
三、练习
给定一个数组{5,1,6,4,2,8,9}。获取数组中的最大值以及最小值。
思路:
1、获取最值需要进行比较,每一次比较都会有一个较大的值,因为该值不确定。
2、让数组中的每一个元素都和这个变量的值进行比较。
3、当所以的元素都比较完成,那么该变量中存储的就是数组中的最大值了。
步骤:
1、
定义变量:初始化为数组中的任意一个元素即可。
2、通过循环语句对数组进行遍历。
3、在遍历过程中定义判断条件。如果遍历到的元素比变量中的元素大,就赋值给该变量。
需要定义一个功能来完成,以便提高复用性。
1、明确结果:数组中的元素int。
2、未知内容:一个数组int[]。
class Demo
{
public static void main(String []args){
int []arr = {3,9,2,4,1};
System.out.println("Max="+getMax(arr));
System.out.println("Min="+getMin(arr));
}
//获取最大值
public static int getMax(int []arr){
int max = arr[0];
for(int x=0;x<arr.length;x++){
if(max<arr[x])
max = arr[x];
}
return max;
}
//获取最小值
public static int getMin(int []arr){
int min = arr[0];
for(int x=0;x<arr.length;x++){
if(min>arr[x])
min = arr[x];
}
return min;
}
}
获取最大值的另一种方式:
可不可以将临时变量初始化为0呢?
答:可以,这种方式其实是初始化为数组中任意一个角标。
class Demo
{
public static void main(String []args){
int []arr = {3,9,2,4,1};
System.out.println("Max="+getMax(arr));
System.out.println("Min="+getMin(arr));
}
//获取最大值
public static int getMax(int []arr){
int max = 0;
for(int x=0;x<arr.length;x++){
if(arr[max]<arr[x])
max = x;
}
return arr[max];
}
//获取最小值
public static int getMin(int []arr){
int min = 0;
for(int x=0;x<arr.length;x++){
if(arr[min]>arr[x])
min = x;
}
return arr[min];
}
}
获取double类型数组中的最大值,因为功能一致,所以定义相同的函数名称,以重载形式存在。
public static double getMax(double []arr){
int min = 0;
for(int x=0;x<arr.length;x++){
if(arr[min]<arr[x])
min = x;
}
return arr[min];
}
四、
数组的排序
需求:对给定数组进行排序:{5,1,6,4,2,8,9}
选择排序:
图示:
class Demo
{
public static void main(String []args){
int []arr = {5,1,6,4,2,8,9};
printArray(arr);
selectSort(arr);
printArray(arr);
}
//选择排序算法
public static void selectSort(int []arr){
for(int x=0;x<arr.length-1;x++){
for(int y=x+1;y<arr.length;y++){
if(arr[x]>arr[y])
change(x,y,arr);
}
}
}
//交换位置
public static void change(int a,int b,int []arr){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
//打印数组
public static void printArray(int []arr){
System.out.print("[");
for(int x=0;x<arr.length;x++){
if(x==arr.length-1)
System.out.println(arr[x]+"]");
else
System.out.print(arr[x]+",");
}
}
}
选择排序特点:内循环结束一次,最值出现在头角标位置上。
冒泡排序:
图示:
class Demo
{
public static void main(String []args){
int []arr = {5,1,6,4,2,8,9};
printArray(arr);
bubbleSort(arr);
printArray(arr);
}
//冒泡排序算法
public static void bubbleSort(int []arr){
for(int x=0;x<arr.length-1;x++){
for(int y=0;y<arr.length-x-1;y++){
if(arr[y]>arr[y+1])
change(y,y+1,arr);
}
}
}
//交换位置
public static void change(int a,int b,int []arr){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
//打印数组
public static void printArray(int []arr){
System.out.print("[");
for(int x=0;x<arr.length;x++){
if(x==arr.length-1)
System.out.println(arr[x]+"]");
else
System.out.print(arr[x]+",");
}
}
}
冒泡排序法特点:最值出现在最后位置上。
最快的排序算法:希尔排序。
在java.util包中,已经定义好了一种排序方式对数组排序——Array.sort(数组);。
五、数组的查找操作
需求:定义功能,获取key第一次出现在数组中的位置。如果返回-1,那么代表该key在数组中不存在。
class Demo
{
public static void main(String []args){
int []arr = {5,1,6,4,2,8,9};
System.out.println(find(arr,8));
}
public static int find(int []arr,int key){
for(int x=0;x<arr.length;x++){
if(arr[x]==key)
return x;//如果和指定的key相等,则返回对应角标。
}
return -1;//如果没有找到则返回-1。
}
}
科普一下:用-1来标识数组中没有找到的情况,这是操作数组的惯例。
折半查找:提高效率,但是必须要保证该数组是有序的。
class Demo
{
public static void main(String []args){
int []arr = {2,3,6,8,9,10,15,23,32,100};
System.out.println(halfSearch(arr,1));
}
public static int halfSearch(int []arr,int key){
int min = 0,max = arr.length-1,mid = (min+max)>>1;
//min为数组头角标,另max为数组最后一个元素的角标,mid为中间元素角标右移一位比除以2高效。
while(arr[mid]!=key){
//当中间值不能与key的时候开始循环
if(key<arr[mid])
//当key小于中间值时,把尾角标变为中间角标,因为中间值mid已经比过了所以要mid-1;
max = mid-1;
if(key>arr[mid])
//当key小于中间值时,把尾角标变为中间角标,因为中间值mid已经比过了所以要mid-1;
min = mid+1;
if(min>max)
return -1;
mid = (min+max)>>1;
}
return mid;
}
}
另一种方式
class Demo
{
public static void main(String []args){
int []arr = {2,3,6,8,9,10,15,23,32,100};
System.out.println(halfSearch(arr,101));
}
public static int halfSearch(int []arr,int key){
int min = 0,max = arr.length-1,mid;
while(min<=max){
mid = (min+max)>>1;
if(key<arr[mid])
max = mid-1;
else if(key>arr[mid])
min = mid+1;
else
return mid;
}
return -1;
}
}
练习:有一个有序的数组,想要将一个元素插入到该数组中。还要保证该数组还是有序的。如何获取该元素在数组中的位置。
class Demo
{
public static void main(String []args){
int []arr = {2,3,6,8,9,10,15,23,32,100};
System.out.println(halfSearch(arr,7));
}
public static int halfSearch(int []arr,int key){
int min = 0,max = arr.length-1,mid;
while(min<=max){
mid = (min+max)>>1;
if(key<arr[mid])
max = mid-1;
else if(key>arr[mid])
min = mid+1;
else
return mid;
}
return min;
}
}
练习:十进制转二进制
class Demo
{
public static void main(String []args){
toBin(4);
}
public static void toBin(int num){
StringBuffer sb = new StringBuffer();//定义一个临时容器
while(num!=0){
int x = num&1;
num = num>>>1;
sb.append(x);
}
System.out.println(sb.reverse());//翻转容器
}
}
原理:
图示
练习:十进制转十六进制
class Demo
{
public static void main(String []args){
toHex(60);
}
public static void toHex(int num){
//利用查表法,先要定义一个表。
char[] chs = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
//定义临时容器
StringBuffer sb = new StringBuffer();
while(num!=0){
//二进制中的4为代表一个十六进制,1111的对应16进制是15.&1111所得的值就是相应的16进制的一位
int x = num&15;
//继续右移4位,为的是获取下一个16进制位。
num = num>>>4;
//将所得值利用查表法,装到容器里。
sb.append(chs[x]);
}
System.out.println(sb.reverse());
}
}
原理:
图示
class Demo
{
public static void main(String []args){
toHex(60);
}
public static void toHex(int num){
//利用查表法,先要定义一个表。
char[] chs = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
//定义临时容器
StringBuffer sb = new StringBuffer();
while(num!=0){
//二进制中的4为代表一个十六进制,1111的对应16进制是15.&1111所得的值就是相应的16进制的一位
int x = num&15;
//继续右移4位,为的是获取下一个16进制位。
num = num>>>4;
//将所得值利用查表法,装到容器里。
sb.append(chs[x]);
}
System.out.println(sb.reverse());
}
}
神马是查表法?
查表法:将所有的元素临时存储起来,建立对应关系。每一次&15后的值作为索引去查建立好的表,就可以找到对应的元素。
这个表怎么建立呢?
可以通过数组的形式来定义。采用StringBuffer reverse功能来完成。
功能优化:发现查表法不仅适应与十进制转十六进制,同样也适合八进制和二进制。
class Demo
{
public static void main(String []args){
toOct(8);
}
//十进制转二进制
public static void toBin(int num){
trans(num,1,1);
}
//十进制转八进制
public static void toOct(int num){
trans(num,7,3);
}
//十进制转十六进制
public static void toHex(int num){
trans(num,15,4);
}
public static void trans(int num,int base,int offset){
//num为需要转换的数,base为相&的数,offset为偏移量。
//利用查表法,先要定义一个表。
char[] chs = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
//定义临时容器
StringBuffer sb = new StringBuffer();
while(num!=0){
int x = num&base;
num = num>>>offset;
sb.append(chs[x]);
}
System.out.println(sb.reverse());
}
}
六、二维数组
格式1:int [][] arr = new int[3][2];
1、定义了名称为arr的二维数组。
2、二维数组中游3个一维数组。
3、每一个一维数组中有2个元素。
4、一维数组的名称分别为arr[0],arr[1],arr[2]。
5、给第一个一维数组1角标位赋值为78,写法是arr[0][1] = 78;。
格式2:int [][] arr = new int [3][];
1、二维数组中有3个一维数组。
2、每个一维数组都是默认初始化值null。
可以对这三个一维数组分别进行初始化。
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
int [][] arr = new int[3][4];
System.out.println(arr);
[[I@de6ced的含义:“[[”表示是二维数组,“I”代表数据类型为int,“@”表示引用。“de6ced”表示地址值。
int [][] arr = new int[3][4];
System.out.println(arr[0]);
[I@de6ced的含义:“[”表示是一维数组,“I”代表数据类型为int,“@”表示引用。“de6ced”表示地址值。
int [][] arr = new int[3][];
System.out.println(arr);
int [][] arr = new int[3][];
System.out.println(arr[0]);
int [][] arr = new int[3][];
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
内存中的存储:
图示
System.out.println(arr.length);//打印的是二维数组的长度
System.out.println(arr[0].length);//打印的是第一个一维数组的长度
累加:
class Demo
{
public static void main(String []args){
//静态初始化
int [][] arr = {{3,5,1,7},{2,3,5},{6,1,8,2}};
int sum = 0;
//控制外角标
for(int x=0;x<arr.length;x++){
//控制内角标
for(int y=0;y<arr[x].length;y++){
//获取元素并累加
sum = sum+arr[x][y];
}
}
System.out.println("sum="+sum);
}
}
练习:
int [] x,y[];判断赋值对错。
a、x[0] = y;
b、y[0] = x;
c、y[0][0] = x;
d、x[0][0] = y;
e、y[0][0] = x[0];
f、x = y;
a错,b对,c错,d错,e对,f错。
一维数组的声明:int []x;或int x[];
二维数组的声明:int [][]x;或int x[][];还有int []y[];(面试)。
上题中int [] x,y[];相当于
int []x;
int []y[];
所以y其实是二维数组。