第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]);
	}
}

Java学习笔记(五)_二分查找

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个元素不需要跨过任何元素

Java学习笔记(五)_直接选择排序_02

代码:

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 + "]");
            }
        }
    }
}

Java学习笔记(五)_顺序查找_03

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]+" ");
        }
    }
}

Java学习笔记(五)_冒泡排序_04

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] +" ");
        }
    }
}

Java学习笔记(五)_顺序查找_05

案例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] +" ");
        }
    }
}

Java学习笔记(五)_顺序查找_06

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);
        }
    }
}

Java学习笔记(五)_直接选择排序_07

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);
        }
    }
}

Java学习笔记(五)_冒泡排序_08

Java学习笔记(五)_直接选择排序_09

Java学习笔记(五)_冒泡排序_10

4.7.6 元素排序

1、排序算法概述

排序算法有很多,实现方式也不同,其中有几个因素觉得算法的优劣

如:时间复杂度、空间复杂度、稳定性,这里不做详细说明,有兴趣的可以去搜索引擎搜索相关知识。

Java学习笔记(五)_顺序查找_11

时间复杂度:

常见的算法时间复杂度由小到大依次为:

Ο(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]+" ");
        }
    }
}

Java学习笔记(五)_二分查找_12

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++){
            //....
        }*/
    }
}

Java学习笔记(五)_数组_13

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);
    }
}