第4章 数组
4.1 什么是数组?
数组:
简单的说,就是一组数。
所谓数组(array),就是相同数据类型的元素按一定顺序排列的集合,
就是把有限个类型相同的变量用一个名字命名,以便统一管理他们,
然后用“编号”区分他们,这个名字称为数组名,
编号称为下标或索引(index)。
组成数组的各个变量/数据称为数组的元素(element)。
数组中元素的个数称为数组的长度(length)。
举例:
如下一组成绩:
89,68,79,100,99
使用数组的好处:
方便,简洁
数组是一种容器,它用来存储一组相同数据类型的数据。
代码:
class TestArray{
public static void main(String[] args){
/*
int score1 = 89;
int score2 = 68;
int score3 = 79;
int score4 = 100;
int score5 = 99;
//输出这些数据的时候
System.out.println("第1个学员的成绩:" + score1);
System.out.println("第2个学员的成绩:" + score2);
System.out.println("第3个学员的成绩:" + score3);
System.out.println("第4个学员的成绩:" + score4);
System.out.println("第5个学员的成绩:" + score5);
//找出最高分
int max = score1 >= score2 ? score1 : score2;
max = max >= score3 ? max : score3;
max = max >= score4 ? max : score4;
max = max >= score5 ? max : score5;
System.out.println("最高分:" + max);*/
/*
思路:
(1)要是100个数呢?
(2)要是需要对它们进行排序:从小到大排序
**/
//需要用数组
int[] scores = {89,68,79,100,99,96,75,15,86,83};
//输出这些数据的时候
for(int i=0; i<scores.length; i++){
System.out.println("第" +(i+1)+"个学员的成绩:" + scores[i]);
}
//找出最高分
int max = scores[0];
for(int i=1; i<scores.length; i++){
if(scores[i] > max){
max = scores[i];
}
}
System.out.println("最高分:" + max);
System.out.println("第5个学员的成绩:" + scores[4]);
}
}
4.2 数组的声明
1、数组如何声明/定义?
格式:
元素的数据类型[] 数组名1;
//表示这个数组1要存储一组数据
//这个称为一维数组
元素的数据类型[][] 数组名2;
//表示这个数组2要存储n组数据
//这个称为二维数组
理论上可以有三维数组、四维数组...,但是实际开发中,用到二维就差不多了。
先讨论存储一组数据的情况。
一维数组的标记是1个[]。
数组名是程序员自己命名的,它也是变量名,也是标识符之一。
只不过数组名这个变量是引用数据类型的变量。
Java的数据类型:
(1)8种基本数据类型:byte,short,int,long,float,double,char,boolean
(2)引用数据类型:类(例如:String、System、Scanner)、数组等
如果要存储一组int的整数:
int[] nums;
如果要存储一组double的小数,例如商品的价格:
double[] prices;
如果要存储一组字符:
char[] letters;
如果要存储一组姓名:
String[] names;
.....
代码:
class ArrayDefine{
public static void main(String[] args){//args也是一维数组
//如果要存储一组int的整数:
int[] nums;
//System.out.println(nums);
//如果要存储一组字符:
char[] letters;
}
}
4.3 一维数组的初始化
1、静态初始化
2、数组的初始化
int a;它的初始化,是给a赋一个初始化值
a = 5;
int[] arr;它的初始化,
(1)确定arr的元素的个数
(2)每一个元素什么值
数组的初始化方式有2种:
(1)静态初始化
数组名 = new 元素的数据类型[]{元素值1,元素值2,元素值3,....};
当静态初始化和声明在一个语句完成时,
可以写成这样:
元素的数据类型[] 数组名 = new 元素的数据类型[]{元素值1,元素值2,元素值3,....};
或简化为:
元素的数据类型[] 数组名 = {元素值1,元素值2,元素值3,....};
(2)动态初始化
数组的特点:
(1)数组名这个变量是引用数据类型,要用到new关键字,
new关键字是表示向JVM申请一整块连续内存空间用来存储一组数据
(2)数组名中存储这一整块连续存储空间的首地址
代码:
class ArrayInitialize{
public static void main(String[] args){
//如果要存储一组int的整数:
int[] nums;//声明
nums = new int[]{2,4,6,8,10};//静态初始化
//int[] nums = new int[]{2,4,6,8,10};//声明并静态初始化
//int[] nums = {2,4,6,8,10};//声明并静态初始化
System.out.println(nums);//[I@15db9742
/*
[I@15db9742它是不是就是首地址值?
初学者可以暂时这么认为。
但是本质上,它不能和首地址值划等号。
因为JVM不对外暴露内存地址,
它会返回对象的类型@对象的hashCode值的十六进制形式
[I:代表int[]类型
15db9742:代表nums这个数组对象的hashCode值的十六进制形式
*/
System.out.println(nums.toString());
System.out.println("数组的长度(即元素的个数:" + nums.length);
System.out.println("第1个元素是:" + nums[0]);
}
}
2、动态初始化
数组的初始化方式有2种:
(1)静态初始化
(2)动态初始化
数组名 = new 元素的数据类型[长度];
代码:
class ArrayInitialize2{
public static void main(String[] args){
//要存储5个整数
int[] nums = new int[5];//此时[5]是代表有5个元素
System.out.println(nums);//[I@15db9742
System.out.println("数组的长度:" + nums.length);//5
//指定nums这个数组的第2个元素的值为66
nums[1] = 66;
//此时i代表下标
//范围是[0, 数组的长度-1]
for(int i=0; i<nums.length; i++){
System.out.println("第" +(i+1)+"个元素:" + nums[i]);
}
}
}
4.4 数组元素的访问和遍历
4、数组的元素遍历问题
数组名是代表一组数,每一个元素需要用到“下标/索引”来区分。
下标的范围是[0, 数组的长度-1]
数组的元素表示方式: 数组名[下标]
借助循环遍历的元素:
for(int i=0; i<数组名.length; i++){
//i是下标
元素是数组名[i]
}
代码:
class ArrayElementIterate{
public static void main(String[] args){
int[] nums = {2,4,6,8,10};//声明并静态初始化
System.out.println("第1个元素:" + nums[0]);//[0]是下标,代表第1个元素
System.out.println("第2个元素:" + nums[1]);//[1]是下标,代表第2个元素
System.out.println("第3个元素:" + nums[2]);
System.out.println("第4个元素:" + nums[3]);
System.out.println("第5个元素:" + nums[4]);
//System.out.println("第5个元素:" + nums[5]);
//java.lang.ArrayIndexOutOfBoundsException: 5运行报错,[5]下标越界了
System.out.println("--------------");
//此时i代表下标
//范围是[0, 数组的长度-1]
for(int i=0; i<nums.length; i++){
System.out.println("第" +(i+1)+"个元素:" + nums[i]);
}
System.out.println("--------------");
//此时i代表第几个元素
for(int i=1; i<=nums.length; i++){
System.out.println("第" + i +"个元素:" + nums[i-1]);
}
}
}
4.5 数组的特点
数组的特点:
(1)数组名这个变量是引用数据类型,要用到new关键字,
new关键字是表示向JVM申请一整块连续内存空间用来存储一组数据
(2)数组名中存储这一整块连续存储空间的首地址
(3)数组的元素有默认值
整数系列:byte,short,int,long 都是0
小数系列:float,double 都是0.0
char系列:编码值为0的空字符
boolean系列:false
引用数据类型系列:null
(4)数组的长度一旦确定就不能修改了
4.6 数组的内存分析
数组的内存分析:
1、JVM的运行时内存
JVM有自动内存管理机制,它把运行时内存分为5个区域:
(1)方法区
用来存储加载的类信息、常量信息、静态变量等
方法区的信息:稳定、全局
(2)虚拟机栈
Java方法运行时存储局部变量等信息
方法运行结束,自动释放内存
(3)本地方法栈
调用底层的C的函数存储局部变量等信息
(4)堆
用来存储new出来的实例对象的信息
对象称为垃圾之后,或者对象死亡之后,由GC(垃圾收集器)来回收内存
(5)程序计数器
记录每一个线程当前运行到哪个指令,下一次轮到我时运行什么指令。
2、虚拟机栈和堆
(1)new关键字:代表像JVM申请一整块连续的存储空间,
用来存储对象的信息,数组也是对象。
(2)这块连续存储空间的总大小由
数组的元素的类型和数组的长度决定。
例如:int类型,长度为5,至少5*4=20个字节
long类型,长度为5,至少5*8=40个字节
....
(3)JVM中每一个字节的内存都有一个地址编号,
数组名里面只记录第一个字节的地址,称为首地址。
但是因为它们是连续的,所以有了首地址,就可以找到后面的其他地址。
(4)Java对象分为3个部分:
A:对象头
包含了一些标志位(GC标记位、锁标记等)
以及这个对象的类型指针
如果是数组对象,还有一个数组的长度
B:实例变量
对于数组来说,就是元素。
C:填充空白
这个部分不是所有对象都有的
只有当对象占的总的内存大小不是byte(8位)的整数倍时,
才需要填充空白。
例如:boolean[] bs = {true,true,false,false};
(5)数组的元素访问要通过数组名 + 下标的方式来访问
数组名:有首地址
下标:跨过几个元素的宽度取当前元素
数组名[0]:表示跨过0个元素的宽度取第1个元素
数组名[1]:表示跨过1个元素的宽度取第2个元素
即可以根据下标,快速的计算出取这个元素的起始地址
结论:
(1)数组名中存储数组对象的首地址
(2)数组的下标从0开始,表示取第1个元素不需要跨过任何元素
代码:
class ArrayMemory{
public static void main(String[] args){
int[] arr = {2,4,6,8,10};//右边省略了new int[]
System.out.println(arr);//[I@15db9742
System.out.println(arr.toString());//[I@15db9742
}
}
4.7 数组的算法
4.7.1 数组元素的统计
1、数组的元素的统计分析相关算法
(1)统计数组的元素中偶数的个数有几个
(2)统计数组的元素中素数的个数有几个
(3)累加数组的所有元素的和
(4)统计数组的所有元素的平均值
.....
代码:
public class TestArrayAnalyze {
public static void main(String[] args) {
/*
随机产生10个[0,100)范围内的偶数放到数组中,
统计它们的总和,平均值,是6的倍数的个数
*/
//(1)先声明并创建一个长度为10的数组
int[] nums = new int[10];
//(2) 随机产生10个[0,100)范围内的偶数放到数组中
/*
思路:
A:随机产生一个[0,100)范围内的整数,然后如果它是偶数,再放到数组中
缺点:循环的次数>=10,大部分情况下都是远远超过10
因为不是偶数的,需要重新产生
B:随机产生一个[0,100)范围内的偶数(一定是偶数),直接放到数组中
可以产生[0,50)的整数,然后*2,就一定是偶数
*//*
for(int i=0; i<10;){
// Math.random():[0,1)的小数
// Math.random()*100:[0,100)的小数
// (int)(Math.random()*100):[0,100)的整数
int randNum = (int)(Math.random()*100);
if(randNum % 2 == 0){
nums[i] = randNum;
i++;
}
}*/
int sum = 0;
int count = 0;
for (int i = 0; i < 10; i++) {
//随机产生1个一个[0,100)范围内的偶数
nums[i] = (int) (Math.random() * 50) * 2;
//输出元素值
System.out.println(nums[i]);
//累加元素的值
sum += nums[i];
//判断是否是6的倍数
if (nums[i] % 6 == 0) {
count++;
}
}
System.out.println("总和:" + sum);
System.out.println("平均值:" + (double)sum/nums.length);
System.out.println("6的倍数的个数:" + count);
}
}
4.7.2 查找元素的最大值
代码:
public class TestMax {
public static void main(String[] args) {
/*
随机产生10个[0,100)的整数,
然后找出最大的一个。
*/
//(1)先声明并创建一个长度为10的数组
int[] nums = new int[10];
//(2)随机产生10个[0,100)的整数放到数组中
for(int i=0; i<nums.length; i++){
nums[i] = (int)(Math.random()*100);
System.out.println(nums[i]);
}
//(3)然后用max找最大值
//max一开始等于第1个元素
/* int max = nums[0];
//int i=0,结果也是对的,就是会出现 if(nums[0] > max)比较,自己和自己也比较了一次
//多比较一次
for (int i = 0; i < nums.length; i++) {
if(nums[i] > max){
max = nums[i];
}
}*/
int max = nums[0];
//int i=1,和后面的元素比较就可以了
for (int i = 1; i < nums.length; i++) {
if(nums[i] > max){
max = nums[i];
}
}
System.out.println("最大值是:" + max);
}
}
简化代码:
public class TestMax2 {
public static void main(String[] args) {
/*
随机产生10个[0,100)的整数,
然后找出最大的一个。
*/
//(1)先声明并创建一个长度为10的数组
int[] nums = new int[10];
//(2)随机产生10个[0,100)的整数放到数组中
//同时找最大值
int max = 0;//初始化为当前元素可能的最小值
// int max = -1;//初始化为比当前所有元素都小的值
// int max = Integer.MIN_VALUE;//初始化为比当前所有元素都小的值
for(int i=0; i<nums.length; i++){
nums[i] = (int)(Math.random()*100);
System.out.println(nums[i]);
if(nums[i] > max){
max = nums[i];
}
}
System.out.println("最大值是:" + max);
}
}
4..7.3 查找最大值及其下标
3、找出数组的元素中的最大值及其下标
(1)元素没有重复
设计两个变量,一个表示最大值,例如:max,一个表示最大值的下标,例如:index。
循环遍历数组,用max和元素比较,如果元素有比max大,修改max和index
(2)元素有重复
先找出最大值,再遍历数组,看哪些元素和最大值一样,输出它们的下标
1、元素不重复:
public class TestMaxIndex {
public static void main(String[] args) {
/*
找出如下数组中的最大值及其下标
*/
int[] arr = {5, 7, 8, 3, 1};
int max = arr[0];
int index = 0;//这个0是下标
for(int i=1; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
index = i;
}
}
System.out.println("最大值是:" + max);
System.out.println("最大值的下标是:[" + index +"]");
}
}
另一种写法:
public class TestMaxIndex3 {
public static void main(String[] args) {
/*
找出如下数组中的最大值及其下标
*/
int[] arr = {5, 7, 8, 3, 1};
int index = 0;//这个0是下标
for(int i=1; i<arr.length; i++){
if(arr[i] > arr[index]){
index = i;
}
}
System.out.println("最大值是:" + arr[index]);
System.out.println("最大值的下标是:[" + index +"]");
}
}
2、元素重复
public class TestMaxIndex2 {
public static void main(String[] args) {
/*
找出如下数组中的最大值及其下标
*/
int[] arr = {5, 7, 8, 3, 8};
int max = arr[0];
for(int i=1; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
}
System.out.println("最大值是:" + max);
System.out.println("最大值的下标有:");
for(int i=0; i<arr.length; i++){
if(arr[i] == max){
System.out.println("[" + i + "]");
}
}
}
}
4.7.4 数组元素反转
public class TestReverse {
public static void main(String[] args) {
int[] arr = {2,5,1,4,3};
//交换之前
System.out.println("元素是:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+ " ");
}
//写法一:
//循环的次数是数组长度的一半
//循环的次数代表元素交换的次数
for(int i=0; i<arr.length/2; i++){
//arr[i] ~ arr[arr.length-1-i];
//arr[0] ~ arr[arr.length-1]
//arr[1] ~ arr[arr.length-2]
int temp = arr[i];
arr[i] = arr[arr.length-1-i];
arr[arr.length-1-i] = temp;
}
//遍历输出
System.out.println("\n反转之后:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
//写法二:
for(int left=0, right=arr.length-1; left < right; left++,right--){
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
System.out.println("\n再次反转之后:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
4.7.5 元素查找
5、数组的元素查找
(1)顺序查找:
用目标值 和 数组的元素一一比较,从头开始按照顺序比较
基本数据类型的值比较用 == ,
引用数据类型的值比较用 值1.equals(值2) (提前了解一下)
(2)二分查找:
要求:
A:数组的元素必须是有序的,要么从小到大,要么从大到小
B:元素必须支持比较大小
1、顺序查找
案例1:
import java.util.Scanner;
public class TestFind {
public static void main(String[] args) {
/*
随机产生10个[0,100)的整数,
然后从键盘输入一个整数,看它是否在这个数组中
*/
//(1)先声明并创建一个长度为10的int[]
int[] nums = new int[10];
//(2)随机产生10个[0,100)的整数
for(int i=0; i<nums.length; i++){
nums[i] = (int)(Math.random()*100);
}
//(3)从键盘输入一个整数
Scanner input = new Scanner(System.in);
System.out.print("请输入一个整数:");
int target = input.nextInt();
//(4)查找个目标target的值在数组中是否存在
boolean flag = false;//假设不存在,false代表不存在
//用target和nums的每一个元素一一比较
for(int i=0; i<nums.length; i++){
if(target == nums[i]){
flag = true;
break;
}
}
//输出结果
if(flag){
System.out.println("存在");
}else{
System.out.println("不存在");
}
//元素有:
System.out.println("数组的元素有:");
for(int i=0; i<nums.length; i++){
System.out.print(nums[i] +" ");
}
}
}
案例2:
import java.util.Scanner;
public class TestFind2 {
public static void main(String[] args) {
/*
从键盘输入5个单词,存到数组中,
然后再输入一个单词,查找它是否在数组中。
*/
//(1)先声明并创建一个长度为5的String[]
String[] words = new String[5];
//(2)从键盘输入5个单词
Scanner input = new Scanner(System.in);
for(int i=0; i< words.length; i++) {
System.out.print("请输入第" + (i+1) +"个单词,共" + words.length+"个:");
words[i] = input.next();
}
//(3)再输入一个要查找的单词
System.out.print("请输入你要查找的单词:");
String target = input.next();
//(4)查找个目标target的值在数组中是否存在
boolean flag = false;//假设不存在,false代表不存在
//用target和nums的每一个元素一一比较
for(int i=0; i<words.length; i++){
if( target.equals(words[i]) ){
flag = true;
break;
}
}
//输出结果
if(flag){
System.out.println("存在");
}else{
System.out.println("不存在");
}
//元素有:
System.out.println("数组的元素有:");
for(int i=0; i<words.length; i++){
System.out.print(words[i] +" ");
}
}
}
2、二分查找
public class TestFind3 {
public static void main(String[] args) {
//元素必须是有序的,这里是从小到大
int[] arr = {8, 15, 23, 35, 45, 56, 75, 85};
int target = 76;
int index = -1;//正常的下标是不会为-1
for(int left=0, right = arr.length-1; left<=right; ){
int mid = (left+right)/2;
if(target == arr[mid]){
index = mid;
break;
}else if(target < arr[mid]){
//去左边,修改right
right = mid - 1;
}else{
//去右边,修改left
left = mid + 1;
}
}
if(index == -1){
System.out.println("不存在");
}else{
System.out.println("存在,它的下标是" + index);
}
}
}
3、二分查找优化
public class TestFind4 {
public static void main(String[] args) {
//元素必须是有序的,这里是从小到大
int[] arr = {8, 15, 23, 35, 45, 56, 75, 85};
int target = 75;
//int target = 76; //不存在
int index = -1;//正常的下标是不会为-1
for(int left=0, right = arr.length-1; left<=right; ){
// int mid = (left+right)/2;
int mid = left + (right-left)/2;
/*
当数组特别大时(元素特别多)
如果要查找的目标靠数组的后面,那么left和right都会很大
left+right有超过int的风险,发生溢出。
*/
if(target == arr[mid]){
index = mid;
break;
}else if(target == arr[left]) {
index = left;
break;
}else if(target == arr[right]) {
index = right;
break;
}else if(target < arr[mid]){
//去左边,修改right
right = mid - 1;
left++;
}else{
//去右边,修改left
left = mid + 1;
right--;
}
}
if(index == -1){
System.out.println("不存在");
}else{
System.out.println("存在,它的下标是" + index);
}
}
}
4.7.6 元素排序
1、排序算法概述
排序算法有很多,实现方式也不同,其中有几个因素觉得算法的优劣
如:时间复杂度、空间复杂度、稳定性,这里不做详细说明,有兴趣的可以去搜索引擎搜索相关知识。
时间复杂度:
常见的算法时间复杂度由小到大依次为:
Ο(1)<Ο(log~2~n)<Ο(n)<Ο(nlog~2~n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
2、直接选择排序:
(1)选择排序
思路:
每一轮从当前未排序元素中找出最小值/最大值,并且要确定这个最大值/最小值的位置。
如果这个位置正好是它应该在的位置,就不动它,
如果这个位置不是它应该在的位置,就和它应该在的位置的元素交换。
例如:arr{6,9,2,9,1}
第一轮:未排序元素{6,9,2,9,1},找出最小值是1,它的下标[4],它应该在[0]
交换arr[4]和arr[0]
arr{1,9,2,9,6}
第二轮:未 排序元素 {?,9,2,9,6} ,找出最小值是2,它的下标[2],它应该在[1]
交换arr[2]和arr[1]
arr{1,2,9,9',6}
第三轮:未排序元素{?,?, 9,9,6} ,找出最小值是6,它的下标[4],它应该在[2]
交换arr[4]和arr[2]
arr{1,2, 6,9',9} 两个9发生了位置的交换,不稳定
第四轮: 未 排序元素{?,?, ?,9',9} ,找出最小值是9,它的下标[3],它应该在[3]
不用动
代码:
public class TestSelectSort {
public static void main(String[] args) {
int[] arr = {6,9,2,9,1};
/*
每一轮从当前未排序元素中找出最小值/最大值,并且要确定这个最大值/最小值的位置。
如果这个位置正好是它应该在的位置,就不动它,
如果这个位置不是它应该在的位置,就和它应该在的位置的元素交换。
轮数:5个元素需要4轮,确定了4个元素的位置,就相当于排好序了
*/
for(int i=0; i<arr.length-1; i++){//轮数
/*
当i=0时,未排序:[0, arr.length-1]
当i=1时,未排序:[1, arr.length-1]
当i=2时,未排序:[2, arr.length-1]
当i=3时,未排序:[3, arr.length-1]
先假设i位置的元素最小,再和后面的元素比较
*/
int index = i;
for(int j=i+1; j<arr.length; j++){
if(arr[j] < arr[index]){
index = j;
}
}
//最小值:arr[index]
//最小值现在在[index],应该在[i]
if(index != i){
//交换arr[i] 和arr[index]
int temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
}
//输出排序结果
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
3、冒泡排序
(2)冒泡排序
思想:
每一轮未排序元素从左往右,“相邻”元素比较,如果“相邻”元素不满足最终排序的顺序,就交换。
例如:arr{6,9,2,9,1},目标:从小到大
每一轮会把大的元素往右移动,每一轮确定一个“最大值”
第一轮:未排序元素{6,9,2,9,1}
第1次:arr[0]和arr[1],就是6和9,if(arr[0] > arr[1]),即if(6>9)不成立,不交换
第2次:arr[1]和arr[2],就是9和2,if(arr[1] > arr[2]),即if(9>2)成立,交换 arr[1]和arr[2]
{6, 2,9, 9,1}
第3次:arr[2]和arr[3],就是9和9,if(arr[2] > arr[3]),即if(9>9)不成立,不交换
第4次:arr[3]和arr[4],就是9和1,if(arr[3]>arr[4]),即if(9>1)成立,交换arr[3]和arr[4]
{6, 2,9, 1,9}
第一轮结束,最大值9到达正确位置
第二轮: {6, 2,9, 1, ?}
第1次: arr[0]和arr[1],就是6和2,if(arr[0]>arr[1]),即if(6>2)成立,交换arr[0]和arr[1]
{2, 6,9, 1, ?}
第2次:arr[1]和arr[2],就是6和9,if(arr[1] > arr[2]),即if(6>9)不成立,不交换
第3次:arr[2]和arr[3],就是9和1,if(arr[2] > arr[3]),即if(9>1)成立,交换arr[2]和arr[3]
{2, 6,1, 9, ?}
第2轮结束,倒数第二个位置确定是9
第三轮:{2, 6,1, ?, ?}
第1次:arr[0]和arr[1],就是2和6,if(arr[0]>arr[1]),即if(2>6)不成立,不交换
第2次:arr[1]和arr[2],就是6和1,if(arr[1]>arr[2]),即if(6>1)成立,不交换arr[1]和arr[2]
{2, 1,6, ?, ?}
第四轮: {2, 1,?, ?, ?}
第1次:arr[0]和arr[1],就是2和1,if(arr[0]>arr[1]),即if(2>1)成立,交换arr[0]和arr[1]
{1, 2,?, ?, ?}
代码:
public class TestBubbleSort {
public static void main(String[] args) {
int[] arr = {6,9,2,9,1};
//每一轮未排序元素从左往右,“相邻”元素比较,如果“相邻”元素不满足最终排序的顺序,就交换。
//外循环控制轮数,5个元素4轮
//i=1,2,3,4, i<5
for(int i=1; i<arr.length; i++){
/*
相邻元素比较
当i=1:
arr[0]和arr[1]
arr[1]和arr[2]
arr[2]和arr[3]
arr[3]和arr[4]
j=0,1,2,3 j<arr.length-1 j<4
当i=2
arr[0]和arr[1]
arr[1]和arr[2]
arr[2]和arr[3]
j=0,1,2 j<arr.length-2 j<3
当i=3
arr[0]和arr[1]
arr[1]和arr[2]
j=0,1 j<arr.length-3 j<2
当i=4
arr[0]和arr[1]
j=0 j<arr.length-4 j<1
arr[j] 和 arr[j+1]
*/
for(int j=0; j<arr.length-i; j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println("排序后:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
//i=0,1,2,3, i<4
/*for(int i=0; i<arr.length-1; i++){
//....
}*/
}
}
4、冒泡排序优化
public class TestBubbleSort2 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
/*
如何优化?
当数组已经排好序了,就不用再继续比较了
怎么证明它已经有序了?
只要没有进入内部的 if(arr[j] > arr[j+1])就是有序的了
*/
int lun = 0;
int count = 0;
for(int i=1; i<arr.length; i++){
lun++;
boolean flag = true;//假设已经有序,本轮未排序元素已经有序了
for(int j=0; j<arr.length-i; j++){
count++;
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag =false;//说明还没有完全调整好
}
}
//一轮下来
if(flag) {
break;
}
}
System.out.println("轮数:" + lun);
System.out.println("比较的总次数:" + count);
}
}