文章目录
-
-
- JAVA语言语法
-
- 四、数组
-
- 1、数组的概述
- 2、一维数组的使用
-
- 2.1 一维数组的内存解析
- 3、数组练习
- 4、二维数组的定义和遍历
-
- 4.1、二维数组的内存解析
- 4.2、二维数组的练习
- 5、数组中涉及到的常见算法
-
- 5.1、数组元素的赋值
- 5.2、数组元素的基本操作
- 5.3、数组元素的基本操作 2
- 5.4、数组的复制、反转、查找
- 5.5、数组元素的排序算法
- 6、Arrays 工具类的使用
- 7、数组使用中的常见异常
-
JAVA语言语法
四、数组
1、数组的概述
数组的概述:
(1)、数组的理解: 数组Array,是多个相同类型的数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
(2)、数组的相关概念:> 数组名> 元素> 角标、下标、索引> 数组的长度,元素的个数
(3)、数组的特点:1)、数组属于引用数据类型的变量,数组的元素,既可以是基本数据类型,也可以是引用数据类型。2)、创建数组对象会在内存中开辟一整块连续的空间。3)、数组的长度一旦确定,就不能修改了。4)、数组是有序排列的。
(4)、数组的分类:①.按照维数: 可划分为 一维数组、二维数组、三维数组。②.按照数组的元素类型: 可划分为 基本数据类型、引用类型元素的数组
2、一维数组的使用
数组讨论学习点:
(1)、数组的声明和初始化;
(2)、如何调用数组的指定位置的元素;
(3)、如何获取数组的长度;
(4)、如何遍历数组;
(5)、数组元素的默认值初始值;
(6)、数组的内存解析。
代码演示(针对上述的6个学习点):
package com.rucoding.d7;/*** @author LiuYiXin**/
public class ArrayDemo01 {
public static void main(String[] args) {
/** (1)、数组的声明和初始化; 引用数据类型:数组的声明和初始化*/// 回顾基本数据类型的声明和初始化int i1; // 声明变量类型i1 = 10; // 初始化int i2 = 10; // 声明和初始化// 类比int[] arr; // 数组声明// 静态初始化: 数组的初始化和数组元素的赋值同时进行arr = new int[] {
1, 2, 3, 4 }; // 初始化: 静态初始化// 动态初始化: 数组的初始化和数组元素的赋值操作分开进行String[] names = new String[5];/** (2)、如何调用数组的指定位置的元素; 通过角标、下标、索引(一个意思)方式调用 数组的角标索引从0开始,到数组的长度 - 1结束的*/// names数组元素进行赋值操作names[0] = "张三";names[1] = "李四";names[2] = "王五";names[3] = "赵六";names[4] = "田七";// names[5] = "老八";//如果数组超过角标会通过编译,但是运行的时候会失败。java.lang.ArrayIndexOutOfBoundsException/** (3)、如何获取数组的长度;*///属性,不是方法,length属性System.out.println(arr.length); //4System.out.println(names.length); //5/** (4)、如何遍历数组;*///遍历数组元素,循环输出即可for(int i = 0;i < names.length;i++){
System.out.println(names[i]);}/** (5)、数组元素的默认值初始值;* 总结:* 1)、数组整型的默认初始化值为0* 2)、浮点型的默认初始化值为0.0* 3)、布尔类型的默认初始化值为false* 4)、char字符类型的默认初始化值为0,而非'0'* 5)、引用数据类型数组(比如String类型)的默认初始化值为null*///数组的默认初始化值int[] arrInt = new int[4];for(int i = 0;i < arrInt.length;i++){
System.out.println(arrInt[i]); //整型默认初始化的值为0}short[] arrShort = new short[4];for(int i = 0;i < arrShort.length;i++){
System.out.println(arrShort[i]);//整型默认初始化的值为0}//浮点型float[] arrFloat = new float[4];for(int i = 0;i < arrFloat.length;i++){
System.out.println(arrFloat[i]);//浮点型默认初始化的值为0.0}//布尔类型boolean[] arrBoolean = new boolean[4];for(int i = 0;i < arrBoolean.length;i++){
System.out.println(arrBoolean[i]);//布尔类型默认初始化的值为false}//char类型char[] arrChar = new char[4];for(int i = 0;i < arrChar.length;i++){
System.out.println(arrChar[i]);//char类型默认初始化的值为0,而非'0'}//验证if(arrChar[0] == 0){
System.out.println("Hi");}//String类型String[] arrString = new String[4];for(int i = 0;i < arrString.length;i++){
System.out.println(arrString[i]);//String类型(引用数据类型)默认初始化的值为null}//Verifyif(arrString[0] == null){
System.out.println("Rucoding");}}
}
第(6)个学习点:
(6)、数组的内存解析。
内存的简化结构:
2.1 一维数组的内存解析
分析以下代码的内存结构图:int[] arr = new int[]{
1,2,3}; //静态声明一个int类型的arr数组,并赋值1,2,3 三个元素
String[] arr1 = new String[4]; //动态声明一个引用类型的arr1数组,并初始化长度为4
arr1[1] = “刘德华”; //给动态声明长度为4的arr数组,赋值操作
arr1[2] = “张学友”; //给动态声明长度为4的arr数组,赋值操作
arr1 = new String[3]; //重新创建一个开辟连续空间的,初始化长度为3的数组给arr1
System.out.println(arr1[1]);//null //此时打印输出的,引用类型默认的初始化值为null
内存解析图(大概意思):
按照图示内容,最终数组的内存解析完成,数组内部值为null。
3、数组练习
? 练习1:通过数组来打印个人的手机号码(调皮一下)。
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class ArrayPrintTelDemo01 {
//通过数组来打印个人的手机号码 13620167671(随机生成的,请勿拨打!)public static void main(String[] args) {
//定义一个数组,并静态赋值手机号出现的数字int[] telNum = new int[]{
7,3,6,2,0,6,1};//手机号码是11位的,遍历11次,取上面telNum数组对应的索引值, 组成手机号码int[] arr1 = {
6,1,2,3,4,6,5,0,5,0,6};//定义我的号码变量String myTel = ""; for(int i = 0;i < arr1.length;i++){
myTel += telNum[arr1[i]];}System.out.print("我的联系方式:" + myTel);}
}
来源于:
/** 升景坊单间短期出租4个月,550元/月(水电煤公摊,网费35元/月),空调、卫生间、厨房齐全。* 屋内均是IT行业人士,喜欢安静。所以要求来租者最好是同行或者刚毕业的年轻人,爱干净、安静。* eclipse代码一键格式规范化:Ctrl+Shift+F*/
public class ArrayDemo {
public static void main(String[] args) {
int[] arr = new int[] {
8, 2, 1, 0, 3 };int[] index = new int[] {
2, 0, 3, 2, 4, 0, 1, 3, 2, 3, 3 };String tel = "";for (int i = 0; i < index.length; i++) {
tel += arr[index[i]];}System.out.println("联系方式:" + tel);}
}
? 练习2:
/** 2. 从键盘读入学生成绩,找出最高分,并输出学生成绩等级。?* 成绩>=最高分-10 等级为’A’ ?* 成绩>=最高分-20 等级为’B’?* 成绩>=最高分-30 等级为’C’ ?* 其余等级为’D’* 提示:先读入学生人数,根据人数创建int数组,存放学生成绩。*/
代码演示:
package com.rucoding.d7.exer;import java.util.Scanner;/*** @author LiuYiXin**/
public class ArrayStuScoreDemo02 {
/** 2. 从键盘读入学生成绩,找出最高分,并输出学生成绩等级。* 成绩>=最高分-10 等级为’A’ * 成绩>=最高分-20 等级为’B’* 成绩>=最高分-30 等级为’C’ * 其余等级为’D’* 提示:先读入学生人数,根据人数创建int数组,存放学生成绩。*/public static void main(String[] args) {
//声明一个可以接收键盘输入的Scanner类Scanner scanner = new Scanner(System.in);//此时可以创建数组, 动态初始化System.out.println("请输入学生人数:");int num = scanner.nextInt();int[] stuNum = new int[num];//定义一个最高分的变量int maxScore = 0;//录入学生成绩System.out.println("请输入" + stuNum.length + "个成绩:");for(int i = 0;i < stuNum.length;i++){
stuNum[i] = scanner.nextInt();//录入的成绩的同时,比较录入的最高分if(maxScore < stuNum[i]){
maxScore = stuNum[i]; }}//打印最高分System.out.println("最高分是:" + maxScore);//定义一个等级的变量char level;//遍历学生成绩,并判断登记for(int i = 0;i < stuNum.length;i++){
if(maxScore - stuNum[i] <= 10){
//level = 'A';}else if(maxScore - stuNum[i] <= 20){
level = 'B';}else if(maxScore - stuNum[i] <= 30){
level = 'C';}else{
level = 'D';}System.out.println("student " + i + " score is " + stuNum[i] + " grade is " + level);}}}
?
4、二维数组的定义和遍历
? 二维数组从底层的运行机制来看也是一维数组,以一维数组的6个讨论要点来分析二维数组。
二维数组的使用:
格式1(动态初始化): int[][] arr = new int[3][2];
定义了一个名称为arr的二维数组
二维数组中有3个一维数组
每个一维数组中有2个元素
一维数组的名称分别为,arr[0]、arr[1]、arr[2]
假如给一个一维数组1下标赋值66的写法,arr[0][1] = 66。格式2(动态初始化): int[][] arr = new int[3][];
二维数组中有3个一维数组。
每个一维数组都是默认的初始化值null (注意区别于格式1)
可以对这个三个一维数组分别进行初始化。
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
代码演示:
package com.rucoding.d7;/*** @author LiuYiXin**/
public class ArrayDemo02 {
/** 二维数组的使用* ①.理解* 对于二维数组的理解, 可以看成是一维数组arr1又作为另一个一维数组arr2的元素* 其实,从数组底层的运行机制来看,没有多维数组的概念* * ②.* a.二维数组的声明和初始化* b.获取数组指定位置的元素* c.获取数组的长度* d.遍历数组* e.数组元素的默认初始值* f.数组的内存解析*/public static void main(String[] args) {
//a.二维数组的声明和初始化//静态初始化int[][] arr = new int[][]{
{
1,2,3},{
2,3,4},{
5,6},{
7,8}};
// int[][] arr = {
{1,2,3},{2,3,4},{5,6}}; 这种写法也可以的//动态初始化1int[][] arr1 = new int[3][2];//动态初始化2int[][] arr2 = new int[3][];//这里与 “e.数组元素的默认初始值” 讨论大体相同,跳过忽略也可。System.out.println(arr[2][1]); //打印数组arr的6System.out.println(arr1[0][0]); //打印数组arr1中的arr[0]一维数组中的0索引元素System.out.println(arr2[0]); //每个一维数组都是默认的初始化值null (数组是引用类型,默认为null)arr2[0] = new int[3];arr2[1] = new int[1];arr2[2] = new int[2];System.out.println(arr2[0][0]); //此时默认为一维数组的元素已经进行初始化,int类型默认为0System.out.println(arr2[0]); //arr2[0] 此时是一个地址值[I@15db9742 [表示一维数组,I表示int类型//b.如何调用指定位置的元素String[][] names = new String[3][2];System.out.println(arr[2][0]); //打印5System.out.println(names[2][1]); //null//c.获取数组的长度System.out.println(names.length); //3System.out.println(names[0].length); //2System.out.println(arr.length); //3System.out.println("**********************");//d.遍历数组for(int i = 0;i < arr.length;i++){
for(int j = 0;j < arr[i].length;j++){
System.out.print(arr[i][j] + " ");}System.out.println();}System.out.println("**********************");//e.数组元素的默认初始值 (重点理解)/** 二维数组的使用:* 规定:二维数组分为外层数组的元素,内层数组的元素* int[][] arr = new int[4][3];* 外层元素: arr[0]、arr[1]、arr[2]、arr[3]* 内层元素: arr[0][0]、arr[0][1]、arr[0][2]等* * 数组元素的默认初始化值* 针对于初始化方式一:比如:int[][] arr = new int[4][3];* 外层元素的初始化值为:地址值* 内层元素的初始化值为:与一维数组初始化情况相同* 针对于初始化方式而:比如:int[][] arr = new int[4][];* 外层元素的初始化值为:null* 内层元素的初始化值为:不能调用,否则报错。*/int[][] arrInt = new int[4][3];System.out.println(arrInt[0]); //[I@6d06d69c 地址值System.out.println(arrInt[0][0]); //0float[][] arrFloat = new float[4][3];System.out.println(arrFloat[0]); //[F@7852e922 地址值System.out.println(arrFloat[0][0]); //0.0short[][] arrShort = new short[4][3];System.out.println(arrShort[0]); //[S@4e25154f 地址值System.out.println(arrShort[0][0]); //0System.out.println("**********************");char[][] arrChar = new char[4][3];System.out.println(arrChar[0]); // 地址值 System.out.println(arrChar[0][0]); //String[][] arrString = new String[4][3];System.out.println(arrString[0]); //[Ljava.lang.String;@70dea4e 地址值System.out.println(arrString[0][0]); //nullSystem.out.println("**********************");double[][] arrDouble = new double[4][3];System.out.println(arrDouble[0]); // [D@5c647e05 地址值 System.out.println(arrDouble[0][0]); //0.0arrDouble = new double[4][];System.out.println(arrDouble[0][0]);//报错 空指针异常NullPointerException}
}
4.1、二维数组的内存解析
①、分析以下代码的内存结构图:int[][] arr1 = new int[4][];
arr1[1] = new int[]{
1,2,3};
arr1[2] = new int[4];
arr1[2][1] = 30;
②、分析以下代码的内存结构图:int[][] arr4= new int[3][];
System.out.println(arr4[0]);//null
System.out.println(arr4[0][0]);//报错
arr4[0] = new int[3];
arr4[0][1] = 5;
arr4[1] = new int[]{
1,2};
?
③、分析以下代码的内存结构图:int[][] arr = new int[3][];
arr[1] = new int[]{
1,2,3};
arr[2] = new int[3];
System.out.println(arr[0]);//null
System.out.println(arr[0][0]);//报异常
④、分析以下代码的内存结构图:int[][] arr1= newint[4][];
arr1[0] = new int[3];
arr1[1] = new int[]{
1,2,3};
arr1[0][2] = 5;
arr1 = new int[2][];
4.2、二维数组的练习
? 练习1:
代码演示:
package com.rucoding.d7;/*** @author LiuYiXin**/
public class ArraySumDemo03 {
public static void main(String[] args) {
//按照图示求和int sum = 0;int[][] arr = new int[][]{
{
3,5,8},{
12,9},{
7,0,6,4}};for(int i = 0;i < arr.length;i++){
for(int j = 0;j < arr[i].length;j++){
sum += arr[i][j];}}System.out.println("总和为:" + sum);}
}
练习2:
int[] x 这是一个一维数组,int[] y[] 这是一个二维数组,即int[][] y
tips: 同一类型或者自下而上的转型。
练习3:
/* 使用二维数组打印一个 10 行杨辉三角。** 【提示】* 1. 第一行有 1 个元素, 第 n 行有 n 个元素* 2. 每一行的第一个元素和最后一个元素都是 1* 3. 从第三行开始, 对于非第一个元素和最后一个元素的元素。* 即:yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];*/
先输出整体的框架,创建一个长度为10的二维数组 new int[10][],默认每个位置的初始化值都是0 ,此时再一一进行赋值,先确定赋值的是:每行的首尾都是1。
填充好每行首尾的1,其他位置再根据提示的公式,进行赋值即可。
示例代码:
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class YangHuiArrayDemo01 {
// 使用二维数组打印一个 10 行杨辉三角。public static void main(String[] args) {
//确定了数组长度int[][] arr = new int[10][];for(int i = 0;i < arr.length;i++){
//初始化一维数组长度arr[i] = new int[i + 1];//首尾元素赋值arr[i][0] = 1;arr[i][i] = 1;//给非首尾元素赋值for(int j = 1;j < i;j++){
//循环条件 j < arr[i].length-1; arr[i][j] = arr[i-1][j] + arr[i-1][j-1];}}//遍历输出数组for(int i = 0;i < arr.length;i++){
for(int j = 0;j < arr[i].length;j++){
System.out.print(arr[i][j] + "\t");}System.out.println();}}
}
练习4(面试题目):
创建一个长度为 6 的 int 型数组,要求取值为 1-30,同时元素值各不相同。
代码演示:
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class ArrayRandomDemo04 {
public static void main(String[] args) {
/*创建一个长度为6的int型数组,要求数组元素的值都在1-30之间,且是随机赋值。* 同时,要求元素的值各不相同。**///定义长度为6的数组int[] arr = new int[6];for(int i = 0;i < arr.length;i++){
arr[i] = (int) ((Math.random()*30) + 1);System.out.println(arr[i]);//判断每次随机生成的数 在数组中是否重复for(int j = 0;j < i;j++){
if(arr[i] == arr[j]){
// i = i - 1; //此时是重复的,不让继续下一个,继续执行当前i的赋值i--; //换种写法
// continue lable;break;} } }//遍历for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");}System.out.println();}
}
5、数组中涉及到的常见算法
(1)、数组元素的赋值(杨辉三角、回形数等)
(2)、求数值型数组中元素的最大值、最小值、平均数、总和等
(3)、数组的复制、反转、查找(线性查找、二分法查找)
(4)、数组元素的排序算法
5.1、数组元素的赋值
? 查看上述练习3<杨辉三角的打印>
5.2、数组元素的基本操作
代码演示:
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class ArrayBasicOperationDemo01 {
/** 算法的考察:求数值型数组中元素的最大值、最小值、平均数、总和等* * 定义一个 int 型的一维数组,包含 10 个元素,分别赋一些随机整数,* 然后求出所有元素的最大值,最小值,和值,平均值,并输出出来。* 要求:所有随机数都是两位数。* * [10,99]* 公式:(int)(Math.random() * (99 - 10 + 1) + 10)*/public static void main(String[] args) {
//定义长度为10的数组int[] arr = new int[10];//定义变量int maxNum = 0;int minNum = 0;int sum = 0;double aveNum = 0.0;int len = arr.length;//数组进行赋值for(int i = 0;i < arr.length;i++){
//输出10到99之间的随机数arr[i] = (int) (Math.random()*(99 - 10 + 1) + 10);}//求最大值for(int i = 0;i < arr.length;i++){
if(maxNum < arr[i]){
maxNum = arr[i];}}//求最小值minNum = arr[0];for(int i = 0;i < arr.length;i++){
if(minNum > arr[i]){
minNum = arr[i];}}//求总和for(int i = 0;i < arr.length;i++){
sum += arr[i];}//求平均值aveNum = sum / len;//遍历数组for(int i = 0;i < arr.length;i++){
if(i != arr.length -1){
System.out.print(arr[i] + ",");}else{
System.out.print(arr[i]);}}System.out.println();System.out.println("最大值" + maxNum);System.out.println("最小值" + minNum);System.out.println("总和" + sum);System.out.println("平均值" + aveNum);}
}
5.3、数组元素的基本操作 2
代码演示:
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class ArrayBasicOperationDemo02 {
/** 使用简单数组* (1)创建一个名为 ArrayTest 的类,在 main()方法中声明 array1 和 array2 两个变量,他们是 int[]类型的数组。* (2)使用大括号{},把 array1 初始化为 8 个素数:2,3,5,7,11,13,17,19。* (3)显示 array1 的内容。* (4)赋值 array2 变量等于 array1,修改 array2 中的偶索引元素,使其等于索引值(如 array[0]=0,array[2]=2)。打印出 array1。*/public static void main(String[] args) {
int[] array1,array2;array1 = new int[]{
2,3,5,7,11,13,17,19};//显示 array1 的内容for(int i = 0;i < array1.length;i++){
System.out.print(array1[i] + "\t");}//赋值 array2 变量等于 array1array2 = array1; //此处是数组的赋值,不是复制!//修改 array2 中的偶索引元素,使其等于索引值(如 array[0]=0,array[2]=2)for(int i = 0;i < array2.length;i++){
if(i % 2 == 0){
array2[i] = i;}}System.out.println();//打印出 array1。for(int i = 0;i < array1.length;i++){
System.out.print(array1[i] + "\t");}}}
针对此题,停下来思考一下:
思考1:上述 array1 和 array2 是什么关系?
//array1 和 array2 地址值相同,都指向了堆空间的唯一的一个数组实体。
int[] array1,array2;
array1 = new int[]{
2,3,5,7,11,13,17,19};
array2 = array1; //赋值 ,实际还是指向堆空间同一地址值
for(int i = 0;i < array2.length;i++){
if(i % 2 == 0){
array2[i] = i;}
}
内存结构分析图:
思考2: 如何实现 array2 对 array1 数组的复制
int[] array1,array2;
array1 = new int[]{
2,3,5,7,11,13,17,19};
//数组的复制
array2 = new int[array1.length]; //new关键字是创建对象,开辟新空间
for(int i = 0;i < array2.length;i++){
array2[i] = array1[i];
}
内存结构分析图:
5.4、数组的复制、反转、查找
代码演示:
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class ArrayBasicOperationDemo04 {
/** 算法的考察:数组的复制、反转、查找(线性查找、二分法查找)*/public static void main(String[] args) {
//数组的复制String[] arr = new String[]{
"CC","FF","SS","QQ","YY","XX","TT","KK","EE","GG"};String[] arr1 = new String[arr.length];for(int i = 0;i< arr1.length;i++){
arr1[i] = arr[i];}//遍历for(int i = 0;i< arr1.length;i++){
System.out.print(arr1[i] + "\t");}System.out.println();//数组的反转 考虑首尾对调
// int index = 0;
// int endIndex = arr1.length -1;
// while(index < endIndex){
// //交换两个数,之前写过的, 定义一个临时变量
// String temp = arr1[index];
// arr1[index] = arr1[endIndex];
// arr1[endIndex] = temp;
// index++;
// endIndex--;
// }//优化写法for(int i = 0,j = arr1.length - 1;i < j;i++,j--){
String temp = arr1[i];arr1[i] = arr[j];arr[j] = temp;}//遍历输出for(int i = 0;i< arr1.length;i++){
System.out.print(arr1[i] + "\t");}System.out.println();//查找(即是搜索) //线性查找boolean isFlag = true;String target = "HH";for(int i = 0 ;i < arr1.length;i++){
if(target.equals(arr1[i])){
//字符串是利用equals()方法isFlag = false;System.out.println("找到了");break;}}if(isFlag){
System.out.println("很遗憾,没找到对应的");} }
}
查找之二分法查找(折半查找)
图解:
代码演示:
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class ArrayBasicOperationDemo04 {
/** 算法的考察:数组的复制、反转、查找(线性查找、二分法查找)*/public static void main(String[] args) {
//二分法查找(折半查找) : 前提是所要查找的数组是有序的int[] arr2 = new int[]{
-8,-314,22,24,53,66,79,105,98,123};int targetNum = 12;int headIndex = 0; //初始的首所索引int endIndex = arr2.length - 1; //初始的末索引boolean isFlag2 = true;while(headIndex <= endIndex){
int middleIndex = (headIndex + endIndex) / 2; if(targetNum == arr2[middleIndex]){
System.out.println("找到了");isFlag2 = false;break;}else if(targetNum > arr2[middleIndex]){
headIndex = middleIndex + 1; }else{
endIndex = middleIndex - 1;} }if(isFlag2){
System.out.println("很遗憾,没找到对应的");}}
}
5.5、数组元素的排序算法
(1)、排序:假设含有 n 个记录的序列为{R1,R2,…,Rn},其相应的关键字序列为{K1,K2,…,Kn}。将这些记录重新排序为{Ri1,Ri2,…,Rin},使得相应的关键字值满足条 Ki1<=Ki2<=…<=Kin,这样的一种操作称为排序。
通常来说,排序的目的是快速查找。
(2)、衡量排序算法的优劣:时间复杂度:分析关键字的比较次数和记录的移动次数空间复杂度:分析排序算法中需要多少辅助内存稳定性:若两个记录 A 和 B 的关键字值相等,但排序后 A、B 的先后次序保持不变,则称这种排序算法是稳定的。
(3)、排序算法分类:内部排序和外部排序。内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序操作都在内存中完成。外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成。
5.5.1、十大内部排序算法
(1)、选择排序直接选择排序、堆排序
(2)、交换排序冒泡排序(重点掌握)、快速排序(暂时了解即可)
(3)、插入排序直接插入排序、折半插入排序、Shell 排序
(4)、归并排序
(5)、桶式排序
(6)、基数排序温馨提示: 以上算法,重点掌握手写冒泡排序,快速排序暂时了解, 其他有兴趣有时间再去研究。
5.5.2、算法的 5 大特征
在这里插入图片描述
5.5.3、冒泡排序(重要)
冒泡排序的基本思想:
通过对待排序序列从前向后,依次比较相邻元素的排序码,若发现逆序则交换,使排序码较大的元素逐渐从前部移向后部。
因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序, 因此要在排序过程中设置一个标志swap判断元素是否进行过交换。从而减少不必要的比较。
图解示范
代码演示(要求会手写):
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class BubbleArrayDemo {
public static void main(String[] args) {
//经典排序: 冒泡排序int[] arr = new int[]{
12,-34,4,18,40,-2,0,78}; //len 8//for(int i = 0;i < arr.length - 1;i++){
//注意循环的条件部分for(int j = 0;j < arr.length - 1 - i;j++){
//注意循环的条件部分//两个数互相交换if(arr[j] > arr[j+1]){
int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");}}
}
5.5.4、快速排序(初学Java,仅作了解)
排序思想:从数列中挑出一个元素,称为"基准"(pivot),
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
图解示范:
5.5.5、排序算法性能对比
各种内部排序方法性能比较:(1)、从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序。
(2)、从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于Shell排序、堆排序、快速排序和归并排序算法,其算法比较复杂,认为是复杂排序。
(3)、从稳定性看:直接插入排序、冒泡排序和归并排序是稳定的;而直接选择排序、快速排序、Shell排序和堆排序是不稳定排序
(4)、从待排序的记录数n的大小看,n较小时,宜采用简单排序;而n较大时宜采用改进排序。排序算法的选择:
(1)、 若n较小(如n≤50),可采用直接插入或直接选择排序。当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接 插入,应选直接选择排序为宜。
(2)、 若文件初始状态基本有序(指正序),则应选用直接插入、冒泡或随机的快速排序为宜;
(3)、 若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
6、Arrays 工具类的使用
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。
boolean equals(int[] a,int[] b) | 判断两个数组是否相等 |
---|---|
String toString(int[] a) | 输出数组信息 |
void fill(int[] a,int val) | 将指定值填充到数组之中 |
void sort(int[] a) | 对数组进行排序 |
int binarySearch(int[] a,int key) | 对排序后的数组进行二分法检索指定的值 |
代码演示:
package com.rucoding.d7.exer;import java.util.Arrays;/*** @author LiuYiXin**/
public class ArraysUtilDemo {
public static void main(String[] args) {
//1.boolean equals(int[] a,int[] b) 判断两个数组是否相等int[] arr1 = new int[]{
1,2,3,4};int[] arr2 = new int[]{
1,2,4,3};boolean isEquals = Arrays.equals(arr1, arr2);System.out.println(isEquals);//2.String toString(int[] a) 输出数组元素信息System.out.println(Arrays.toString(arr1)); //[1, 2, 3, 4]System.out.println(Arrays.toString(arr2)); //[1, 2, 4, 3]//3.void fill(int[] a,int val) 将指定值填充到数组之中Arrays.fill(arr1, 2);System.out.println(Arrays.toString(arr1)); //[2, 2, 2, 2]//4.void sort(int[] a) 对数组进行排序Arrays.sort(arr2);System.out.println(Arrays.toString(arr2)); //[1, 2, 3, 4]//5.int binarySearch(int[] a,int key) 对排序后的数组进行二分法检索指定的值。int[] arr = new int[]{
12,-34,4,18,40,-2,0,78};Arrays.sort(arr);System.out.println(Arrays.toString(arr)); //默认升序int index = Arrays.binarySearch(arr, 24);if(index >= 0){
//看底层key找不到的情况下,是返回负数的System.out.println(index);}else{
System.out.println("很遗憾, 没有找到! " + index);}}
}
7、数组使用中的常见异常
数组中的常见异常:
(1)、数组角标越界的异常:ArrayIndexOutOfBoundsException
(2)、空指针异常:NullPointerException
代码演示:
package com.rucoding.d7.exer;/*** @author LiuYiXin**/
public class ArrayExceptionDemo {
/** 数组中的常见异常:* 1.数组角标越界的异常:ArrayIndexOutOfBoundsException* * 2.空指针异常:NullPointerException* */public static void main(String[] args) {
//1.数组角标越界的异常:ArrayIndexOutOfBoundsExceptionint[] arr = new int[]{
1,2,3,4};//错误场景1for(int i = 0;i <= arr.length;i++){
// System.out.println(arr[i]); //java.lang.ArrayIndexOutOfBoundsException}//错误场景2
// System.out.println(arr[-2]);//2.空指针异常:NullPointerExceptionint[] arr1 = new int[]{
1,2,3,4};arr1 = null;//错误场景1
// System.out.println(arr1[0]); //java.lang.NullPointerException//错误场景2int[][] arr2 = new int[4][];
// System.out.println(arr2[0][0]);//错误场景3String[] arr3 = new String[]{
"AA","QQ","YY","XX","TT","KK"};arr3[0] = null;System.out.println(arr3[0].toString());}
}
本文到此结束,感谢浏览~