数组剖析

文章目录

  • 包装类(Wrapper Class)
  • 数组(Array)
  • Swap交换
    • 接口的数组
  • 数组的比较
  • 冒泡排序。(掌握交换排序,快速排序的原理与实现方式)
    • arraycopy方法
  • 二分查找(Binary Search)
  • 数组的一道应用题
    • 获取随机数的两种方法
      • Random类中的nextInt方法
      • Math类中的random方法

包装类(Wrapper Class)

  1. 针对于原生数据类型的包装,所有的包装类(8 个)都位于java.lang 包下。
    例如:Integer把原生数据类型int包装在对象中,类型Integer的对象包含了一个单独的一个int类型的值。
public class IntegerTest {

	public static void main(String[] args) {
		int a = 10;
		
		Integer integer = new Integer(a);
		
		int b = integer.intValue();
		
		System.out.println(a == b);

	}

}

 结果是:true
 其他的类型同理
  1. Java 中的 8 个包装类分别是:Byte,Short,Integer,Long,Float,Double,Character, Boolean。 他们的使用方式都是一样的,可以实现原生数据类型与包装类型的双向转换。

数组(Array)

  1. 相同类型数据的集合就叫做数组。
  2. 如何定义数组,我们可以从new关键字看出数组其实是一个对象。
  3. type[] 变量名 = new type[数组中元素的个数];可以按照下列方式定义长 type[] 变量名 = new type[数组中元素的个数];可以按照下列方式定义长度为 10 的数组:
int[] a = new int[10]; 
int a[] = new int[10];      //不建议使用
  1. 数组中的元素索引是从 0 开始的。对于数组来说,最大的索引==数组的长度 – 1。
public class ArraryTest {

	public static void main(String[] args) {
		int[] a = new int[4];
		int b[] = new int[2];
		
		a[0] = 1;
		a[1] = 2;
		a[2] = 3;
		a[3] = 4;
		b[0] = 1;
		b[1] = 2;
		System.out.println(a[3]);
		System.out.println(b[1]);
	}
}

int[]是一个整体a代表int类型的数组

  1. 定义数组的第 3 种方式: type[] 变量名 = {new type[]}{逗号分隔的初始化值列表};
		int[] b = {1,2,3,4};
		int[] c = new int[] {1,2,3,4};
		
		System.out.println(b[2]);

		System.out.println(c[0]);

结果是3 ,1
但是不可以写成new int[4]{1,2,3,4}

6. Java 中的每个数组都有一个名为 length 的属性,表示数组的长度。 length 属性是 public,final, int 的。 数组长度一旦确定,就不能改变大小。
7. int[] a = new int[10],其中 a 是一个引用,它指向了生成的数组对象的首地址,数组中
每个元素都是 int 类型,其中仅存放数据值本身。

		int[] a = new int[4];
		boolean[] b = new boolean[2];
		
		System.out.println(a[0]);
		System.out.println(b[1]);

结果是0,false

		int[] a = {1,2,3};
		int[] b = {1,2,3};
		
		System.out.println(a.equals(b));
		System.out.println(a == b );
		System.out.println(a[0] == b[0]);

结果是false false true
int[]并没有重写object类中的equals方法,所以两个对象并不相同。

8. 引用类型的变量的初值为空,数组中存放的是引用所以

public class ArrayTest2 {

	public static void main(String[] args) {
		Person[] p = new Person[3];
		
		System.out.println(p[0]);

	}

}

class Person{
	
	int age;
	
	public Person(int age) {
		this.age = age;
	}
}

结果为null

	public static void main(String[] args) {
		Person[] p = new Person[3];
		
		//System.out.println(p[0]);
		p[0] = new Person(10);
		p[1] = new Person(20);
		p[2] = new Person(30);
		
		for(int i = 0;i < p.length; i++) {
			System.out.println(p[i].age);
		}
		
		Person[] p2 = new Person[5];
		
		for(int i = 0;i < p2.length; i++) {
			System.out.println(p2[i]);
		}

	}

}

class Person{
	
	int age;
	
	public Person(int age) {
		this.age = age;
	}
}

结果为10
20
30
null
null
null
null
null
执行完Person[] p = new Person[3];内存给数组分配3个空间,并且引用p指向p[0]的首地址,并且p[0],p[1],p[2]中存放的是引用并不是person对象,p[0] = new Person(10);p[1] = new Person(20);p[2] = new Person(30);当执行完这三句后p[0],p[1],p[2]存放的是指向person的引用,执行之前,数组中存放的是null

将单数叫lisi双数叫zhangsan的例子:

public class ArrayTest3 {

	public static void main(String[] args) {
		Student[] s = new Student[100];
		
		for(int i = 0;i < s.length; i++) {
			s[i] = new Student();  //先生成对象
			/*
			if(i % 2 == 0){
				s[i].name = "zhangsan";
			}
			else {
				s[i].name = "lisi";
			}
			*/
			s[i].name = i % 2 == 0 ? "zhangsan" : "lisi";
		}
		for(int i = 0;i < s.length; i++) {
			System.out.println(s[i].name);
		}

	}

}

class Student{
	String name;
}
  1. 二维数组。 二维数组是一种平面的二维结构,本质上是数组的数组。 二维数组的定义方式: type[][] a = new type[2][3];
public class ArrayTest4 {

	public static void main(String[] args) {
		int[][] i = new int[2][3];
		
		System.out.println(i instanceof Object);//证明i是对象
		System.out.println(i[0] instanceof int[]);//证明i[0]是数组
	}

}

我们也可以把每一个行赋予不同的列,例如第一行2列,第二行3列,第三行1列

public class ArraryTest5 {

	public static void main(String[] args) {
		int[][] a = new int[3][];
		
		a[0] = new int[2];
		a[1] = new int[3];
		a[2] = new int[1];

	}

}

注意:但是我们不能int[][] a = new int[][3];这样写,因为我们只知道有三列而不知道有几行无法初始化。
我们将不规则的二维数组的值取出例子如下:

public class ArraryTest5 {

	public static void main(String[] args) {
		int[][] b = new int[][]{{1,2,3},{4},{5,6,7,8}};
		for(int i = 0;i < b.length; i++) {
			for(int j = 0;j <b[i].length; j++) {
				System.out.print(b[i][j]+" ");
			}
			System.out.println();
		}

	}

}

结果是
1 2 3
4
5 6 7 8

  1. 三维数组。 type[][][] a = new type[2][3][4];
public class ThreeDimensionArrayTest {

	public static void main(String[] args) {
		int[][][] a = new int[2][3][4];
		
		System.out.println(a instanceof int[][][]);
		System.out.println(a[0] instanceof int[][]);
		System.out.println(a[0][0] instanceof int[]);

	}

}

结果是
true
true
true

Swap交换

我们想要把x,y交换该如何作?
如果用第一种方法,x,y只是把值传给swap方法,a,b的改变并不影响x,y。
第二种方法才是正确的将x,y的值交换的方式。
第三种方法是不适用中间变量将a,b交换的方法。

public class Swap {
	
	public static void swap(int a,int b) {
		int temp = a;
		a = b;
		b = temp;
	}

	public static void main(String[] args) {
		int x = 3;
		int y = 4;
		
		Swap.swap(x, y);
		
		System.out.println(x);
		System.out.println(y);
		
		int temp = x;
		x = y;
		y = temp;
		
		System.out.println(x);
		System.out.println(y);
		
		int a = 3;
		int b = 4;
		
		a = a + b;
		b = a - b;
		a = a - b;
		
		System.out.println(x);
		System.out.println(y);
	}

}

结果是
3
4
4
3
4
3

那我们如果非要用方法实现两个数的交换该怎么办昵?
我们先来看下面这个例子

public class Swap2 {
	
	public static void swap(char[] ch,char c) {
		ch[0] = 'B';
		c = 'D';
	}

	public static void main(String[] args) {
		char[] ch = {'A','C'};
		
		swap(ch, ch[1]);
		
		for(int i = 0;i < ch.length; i++) {
			System.out.println(ch[i]);
		}

	}

}

结果是
B
C

从上面这个例子我们可以看到char[]数组传的是引用,main方法中的ch[0]和swap中的ch[0]是指向的同一个地址所以swap方法把ch[0]里的值改变了,而char是数值c是一个全新的字符型常量,并不是之前的ch[1],所以ch[1]并没有改变
这样我们接着实现两个整数的交换

public class Swap3 {

	public static void swap(int[] i) {
		int temp = i[0];
		i[0] = i[1];
		i[1] = temp;
	}
	
	public static void main(String[] args) {
		int[] i = {1,2};
		
		swap(i);
		
		System.out.println(i[0]);
		System.out.println(i[1]);

	}

}

结果是
2
1

接口的数组

public class ArrayTest6 {

	public static void main(String[] args) {
		I[] i = new I[2];
		I j = null;

	}

}
interface I{
	
}

上述的例子编译并不会出错,尽管接口不能实例化,但是上述的i中存放的是引用并没有I的实例,所以不会出错,i[0]和j的效果是一样的,只是给分配了地址,并没有把接口实例化,只有输入new I(),程序才会报错。
当我们想给接口实例化时,必须让C实现接口I,这里用到了多态。
public class ArrayTest6 {

public static void main(String[] args) {
	I[] i = new I[2];
	
	i[0] = new C();
	i[1] = new C();
	
	I[] b = new I[] {new C(),new C()};

}

}
interface I{

}

class C implements I{

}

数组的比较

import java.util.Arrays;

public class ArrayEqualsTest {
	
	public static boolean isEqueals(int[] a,int[] b) {
		if(a == null || b ==null) {
			return false;
		}
		if(a.length != b.length) {
			return false;
		}
		for(int i = 0; i < a.length; i++) {
			if(a[i] != b[i]) {
				return false;
			}
		}
		return true;
	}

	public static void main(String[] args) {
		int[] a = {1,2,3};
		int[] b = {1,2,3};
		
		System.out.println(isEqueals(a, b));
		System.out.println(Arrays.equals(a, b));
	}

}

结果是
true
true

第一个true是我们自己实现的数组比较的方法,而第二个是java自带的在Arrays类中的方法,专门用来比较数组的。

冒泡排序。(掌握交换排序,快速排序的原理与实现方式)

arraycopy方法

这个方法是JDK提供的API,这个方法在java.lang.System。
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)

Parameters:
src - the source array(原数组).
srcPos - starting position in the source array(原数组中的起始位置,从此位置开始拷贝).
dest - the destination array(目标数组).
destPos - starting position in the destination data(目标数组的起始位置,从此位置开始接收).
length - the number of array elements to be copied(待拷贝的的数组的个数).

public class ArrayCopy {

	public static void main(String[] args) {
		int[] a = new int[] {1, 2, 3, 4};
		
		int[] b = new int[4];
		
		System.arraycopy(a, 0, b, 0, 4);
		
		for(int i = 0;i < b.length; i++) {
			System.out.print(b[i]+" ");
		}

	}

}

结果是
1 2 3 4

  1. 冒泡排序
    拿个数组举例将下列数组升序排序
    第一次排序
    数组剖析_第1张图片
    第二次排序
    数组剖析_第2张图片
    依次排序排列成3 4 5 7 9

设置一个方法接受参数int[]类型的数组将顺序排好再返回(升序排列)

public class BubbleSortTest {
	
	public static int[] bubbleSort(int[] a) {
		for(int i = 0;i < a.length; i++) {
			for(int j = 1;j < a.length-i; j++) {
				if(a[j-1] > a[j]) {
					int temp = a[j-1];
					a[j-1] = a[j];
					a[j] = temp;
				}
			}
			System.out.print("第" + (i + 1) + "趟排序");
			for(int k = 0; k < a.length; k++) {
				System.out.print(a[k] + " ");
			}
			System.out.println();
			//提升效率,如果没有发生比较直接返回数组
		}
		return a;
	}

	public static void main(String[] args) {
		int[] a = new int[5];
		a[0] = 5;
		a[1] = 4;
		a[2] = 7;
		a[3] = 9;
		a[4] = 3;
		
		System.out.print("排序之前:");		
		for(int i = 0;i < a.length; i++) {
			System.out.print(a[i] + " ");
		}
		System.out.println();
		a = bubbleSort(a);
		
		System.out.print("排序之后:");
		for(int i = 0;i < a.length; i++) {
			System.out.print(a[i] + " ");
		}

	}

}

排序之前:5 4 7 9 3
第1趟排序4 5 7 3 9
第2趟排序4 5 3 7 9
第3趟排序4 3 5 7 9
第4趟排序3 4 5 7 9
第5趟排序3 4 5 7 9
排序之后:3 4 5 7 9

优化之后

public class BubbleSortTest {
	
	public static int[] bubbleSort(int[] a) {
		boolean x = true;
		for(int i = 0;i < a.length; i++) {
			x = true;
			for(int j = 1;j < a.length-i; j++) {
				if(a[j-1] > a[j]) {
					int temp = a[j-1];
					a[j-1] = a[j];
					a[j] = temp;
					x = false;
				}

			}
			System.out.print("第" + (i + 1) + "趟排序");
			for(int k = 0; k < a.length; k++) {
				System.out.print(a[k] + " ");
			}
			System.out.println();
			if(x) {             //提升效率,如果没有发生比较直接返回数组
				return a;
			}
		}
		return a;
	}

	public static void main(String[] args) {
		int[] a = new int[10];
		a[0] = 5;
		a[1] = 4;
		a[2] = 7;
		a[3] = 9;
		a[4] = 3;
		a[5] = 45;
		a[6] = 1;
		a[7] = 4;
		a[8] = 8;
		a[9] = 3;
		
		System.out.print("排序之前:");		
		for(int i = 0;i < a.length; i++) {
			System.out.print(a[i] + " ");
		}
		System.out.println();
		a = bubbleSort(a);
		
		System.out.print("排序之后:");
		for(int i = 0;i < a.length; i++) {
			System.out.print(a[i] + " ");
		}

	}

}

结果是
排序之前:5 4 7 9 3 45 1 4 8 3
第1趟排序4 5 7 3 9 1 4 8 3 45
第2趟排序4 5 3 7 1 4 8 3 9 45
第3趟排序4 3 5 1 4 7 3 8 9 45
第4趟排序3 4 1 4 5 3 7 8 9 45
第5趟排序3 1 4 4 3 5 7 8 9 45
第6趟排序1 3 4 3 4 5 7 8 9 45
第7趟排序1 3 3 4 4 5 7 8 9 45
第8趟排序1 3 3 4 4 5 7 8 9 45
排序之后:1 3 3 4 4 5 7 8 9 45

快速排序也是交换排序的一种,在后面介绍。

二分查找(Binary Search)

待查找的数组要有序。

public class ArraySearchTest {
   
   public static int search(int[] array, int value) {
   	int low = 0;
   	int high = array.length - 1;
   	int middle;
   	
   	while(low <= high) {
   		
   		middle = (low + high) / 2;
   		
   		if(array[middle] == value) {
   			return middle;
   		}
   		
   		if(value < array[middle]) {
   			high = middle - 1;
   		}
   		
   		if(value > array[middle]) {
   			low = middle + 1;
   		}

   	}
   	
   	return -1;
   }

   public static void main(String[] args) {
   	int[] a = new int[] {1, 2, 3, 4, 5, 6, 7, 8};
   	
   	int value = 8;
   	
   	int index = search(a, value);
   	
   	System.out.println(index);

   }

}

数组的一道应用题

随机生成 50 个数字(整数),每个数字的范围是[10, 50],统计每个数字出现的次数以及出现次数最多的数字与它的个数,最后将每个数字及其出现次数打印出来,如果某个数字出现次数为 0,则不要打印它。打印时按照数字的升序排列。
注意:Random()函数生成的是[0,1)之间的数,也就是说不包含1,但是包含0

public class Example {

	public static void main(String[] args) {
		int[] random = new int[50];
		int[][] number = new int[2][41];
		
		for(int i = 0; i < 50 ; i++) {
			random[i] = (int)(Math.random() * 41) + 10;
		}

		for(int a = 0; a <= 40; a++) {
			number[0][a] = 0;
			number[1][a] = a + 10;
		}
		
		for(int b = 0; b < 50 ; b++) {
			for(int c = 0; c <= 40; c++) {
				if(random[b] == number[1][c]) {
					number[0][c]++;
				}
			}
		}
		
		for(int d = 0; d <= 40; d++) {
			if(number[0][d] != 0) {
				System.out.print("数字为" + number[1][d]);
				System.out.println("  出现的次数为" + number[0][d]);
			}
		}

	}

}

结果为
数字为10 出现的次数为1
数字为11 出现的次数为1
数字为12 出现的次数为2
数字为13 出现的次数为1
数字为14 出现的次数为1
数字为15 出现的次数为1
数字为16 出现的次数为2
数字为18 出现的次数为1
数字为20 出现的次数为1
数字为22 出现的次数为1
数字为23 出现的次数为3
数字为25 出现的次数为2
数字为26 出现的次数为2
数字为27 出现的次数为2
数字为29 出现的次数为1
数字为30 出现的次数为3
数字为32 出现的次数为1
数字为33 出现的次数为2
数字为34 出现的次数为1
数字为35 出现的次数为3
数字为37 出现的次数为2
数字为38 出现的次数为1
数字为39 出现的次数为1
数字为40 出现的次数为1
数字为41 出现的次数为4
数字为42 出现的次数为2
数字为43 出现的次数为1
数字为45 出现的次数为2
数字为46 出现的次数为1
数字为47 出现的次数为2
数字为50 出现的次数为1

另一种方法

import java.util.Random;

public class RandomTest2 {

	public static void main(String[] args) {
		
		int[] count = new int[41];
		
		Random random = new Random();
		
		for(int i = 0; i < 50; i++) {
			int number = random.nextInt(41) + 10;//[10,50]
			
			count[number - 10]++;
		}
		
		for(int i = 0; i <count.length; i++) {
			if(0 == count[i]) {
				continue;
			}
			
			System.out.println((10 + i) + "出现的次数" + count[i]);
		}
		
		int max = count[0];
		
		for(int i = 0; i < count.length; i++) {
			if(max < count[i]) {
				max = count[i];
			}
		}
		
		System.out.println("出现的最大次数为:" + max + "次");
		
		for(int i = 0; i < count.length; i++) {
			if(max == count[i]) {
				System.out.println(i + 10);
			}
		}

	}

}

结果是
11出现的次数1
12出现的次数2
13出现的次数2
14出现的次数1
15出现的次数2
17出现的次数2
19出现的次数2
20出现的次数4
22出现的次数1
23出现的次数1
24出现的次数2
25出现的次数2
26出现的次数1
27出现的次数1
28出现的次数1
30出现的次数1
31出现的次数1
34出现的次数2
35出现的次数1
36出现的次数3
37出现的次数1
39出现的次数2
40出现的次数2
41出现的次数2
42出现的次数2
43出现的次数1
45出现的次数1
46出现的次数2
48出现的次数1
49出现的次数1
50出现的次数2
出现的最大次数为:4次
20

获取随机数的两种方法

Random类中的nextInt方法

java.util
Class Random
public int nextInt(int n)

Parameters:
n - the bound on the random number to be returned. Must be positive.
(返回随机数的边界值)
Returns:
the next pseudorandom, uniformly distributed int value between 0 (inclusive) and n (exclusive) from this random number
(返回下一个随机数,包含0,排除n,所以返回的数是[0,n))

import java.util.Random;

public class RandomTest {

	public static void main(String[] args) {
		Random random = new Random();
		
		for(int i = 0; i < 50; i++) {
			System.out.println(random.nextInt(41)+10);
		}

	}

}

Math类中的random方法

java.lang
Class Math
public static double random()

Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0. Returned values are chosen pseudorandomly with (approximately) uniform distribution from that range.

import java.util.Random;

public class RandomTest {

	public static void main(String[] args) {
		Random random = new Random();
		
		for(int i = 0; i < 50; i++) {
		double result = Math.random();
		
		result *= 41;
		
		int result2 = (int)result;
		
		result2 += 10;
		
		System.out.println(result2);
		}

	}

}

你可能感兴趣的:(Java的学习之路)