【程序员养成之路】Java基础篇 3-反手就能写个冒泡排序的数组

以下内容若有误,欢迎私信我或在下方留言,谢谢^_−


数组

1.数组的定义
  • 数组是指一组数据的集合,数组中的每个数据被称作元素
  • 在数组中可以存放任意类型的元素,但同一个数组里存放的元素类型必须一致
  • 每个数组元素可以通过对应下标(索引)进行访问
  • 数组分为一维数组和多维数组。
public class Demo01 {
    public static void main(String[] args) {
        /*
        错误实例:
        int[] num = {1, 2, 3.0};
        报错:
        Required type:int
        Provided:double
        * */
        int[] num = {1, 2, 3};
        // 通过下标访问数组
        System.out.println(num[1]); // 输出结果为:2
    }
}
2.数组的声明与创建
public class Demo02 {
    public static void main(String[] args) {
        // 声明数组
        int[] num;
        // 创建数组:Java使用new创建数组
        num = new int[10];
        /*
         * 与C、C++类似的,声明也可以用如下方式:
         * 数组类型 数组名[] = ……
         * int num[];
         * 即将方括号[]放到数组名后面,这是为了让程序员适应Java语法,不推荐使用
         * */
        // 1.数组类型[] 数组名 = new 数组类型[数组长度];
        double[] num_d = new double[10];
        // 2.数组类型[] 数组名 = new 数组类型[]{数组元素0,数组元素1,...};
        String[] names = new String[]{"小一", "小二", "小三"};
        // 3.数组类型[] 数组名 = {数组元素0,数组元素1,...};
        Object[] info = {"小一", 18};
    }
}
  • 数组索引(index):每一个存储到数组的元素,都会自动的拥有一个编号,从0开始。
  • 获取数组长度:数组名.length
3.使用数组需注意的两种情况
  • 每个数组的索引都有一个范围,即0~length-1。在访问数组的元素时,索引不能超出这个范围,否则程序会报错(ArrayIndexOutOfBoundsException,即数组角标越界异常)。
  • 在使用变量引用一个数组时,变量必须指向一个有效的数组对象,如果该变量的值为null,则意味着没有指向任何数组,此时通过该变量访问数组的元素会出现错误(NullPointerException,即空指针异常)。
4.内存分析

(1)Java内存
在这里插入图片描述
(2)数组内存分析

  1. 声明数组会将num压入JVM的栈中。
  2. 创建数组会在JVM的堆内存中开辟空间,并分成若干块(具体看数组长度),一个数组元素存储一块空间。与此同时,创建的时候会将栈中的num指向这块空间。在未赋值之前,数组会进行默认初始化,即每个块位置的值都是相应数据类型的默认值(0/0.0/false/null)。
  3. 对数组进行赋值,则将元素依次存储到堆内存中的相应位置。

在这里插入图片描述

5.三种初始化方式
public static void main(String[] args) {
        // (1)静态初始化:创建完成之后直接赋值
        int[] arr1 = {1,2,3,4,5,6};

        // (2)动态初始化:创建完成之后后续赋值
        int[] arr2 = new int[10];
        arr2[0] = 1;
        arr2[1] = 2;
        arr2[2] = 3;

        // (3)默认初始化:动态初始化后,对于未赋值的位置会进行默认初始化,值为数据类型的默认值
        System.out.println(arr2[3]);    // 0
        System.out.println(arr2[4]);    // 0
    }

拓展1:case穿透现象

当使用switch case语句进行判断一个变量与一系列值中某个值是否相等时,若语句分支没有使用break,则执行完该语句后不会跳出分支结构,而是继续执行后续语句(无论是否相等),直到所有语句执行完毕或者遇上break,这就是case穿透现象

如下:

当输入为C时,由于case "C"语句未使用break,则会执行后续的21、22行代码。
图一
当输入为A时,由于case "A"语句使用了break,则会跳出switch。图二

public class Demo04 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你的等级:");
        String c = scanner.next();
        switch (c) {
            case "A":
                System.out.println("优秀");
                break;
            case "B":
                System.out.println("良好");
                break;
            case "C":
                System.out.println("及格");
            case "D":
                System.out.println("不及格");
            default:
                System.out.println("输入有误!");
        }
    }
}

拓展2:稀疏数组

定义:在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏数组。

/*
* 稀疏数组的压缩、解压
* */
public class Demo {
    public static void main(String[] args) {
        /*创建二维数组*/
        int[][] array1 = new int[10][10];
        array1[1][2] = 1;
        array1[2][3] = 2;
        System.out.println("原始数组:");
        for (int[] ints : array1) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
        System.out.println("===================================");

        /*压缩:转换为稀疏数组*/
        int count = 0;  // 获取有效值的个数(非0个数)
        for (int[] ints : array1) {
            for (int anInt : ints) {
                if (anInt != 0) {
                    count++;
                }
            }
        }
        System.out.println("二维数组的有效值个数:" + count);
        // 创建稀疏数组
        int[][] array2 = new int[count + 1][3];
        array2[0][0] = 10;
        array2[0][1] = 10;
        array2[0][2] = count;
        // 遍历二维数组,将非0的值存放到稀疏数组
        int sum = 0;
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j] != 0) {
                    sum++;
                    array2[sum][0] = i;
                    array2[sum][1] = j;
                    array2[sum][2] = array1[i][j];
                }
            }
        }
        // 输出稀疏数组
        System.out.println("稀疏数组:");
        for (int[] ints : array2) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
        System.out.println("===================================");
        /*解压:将稀疏数组还原为二维数组*/
        // 创建一个二维数组,用于存放稀疏数组的还原数据
        int[][] array3 = new int[10][10];
        for (int i = 1; i < array2.length; i++) {
            array3[array2[i][0]][array2[i][1]] = array2[i][2];
        }
        for (int[] ints : array3) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
    }
}

拓展3:冒泡排序

冒泡排序是排序算法中一种比较简单的排序方法,主要是对数组中相邻的两个元素进行两两比较,若满足要求则进行下两项比较,如不满足要求则进行交换,以此类推。(关于冒泡排序的原理有很多资料视频,这里不过多赘述。)

以下是实现冒泡排序的代码及一种优化方法:

import java.util.Arrays;

/*
* 冒泡排序:升序
* */
public class BubbleSort {
    public static void main(String[] args) {
        // 为了便于了解优化前和优化后的冒泡排序的区别,这里定义两个一样的数组
        int[] arr1 = {15, 20, 2, 52, 18};
        int[] arr2 = {15, 20, 2, 52, 18};
        sort1(arr1);
        System.out.println("未优化的数组:" + Arrays.toString(arr1));
        sort2(arr2);
        System.out.println("优化的数组:" + Arrays.toString(arr2));
    }

    // 未优化的冒泡排序
    /*
     * 原数组:15 20 2 52 18
     * 第一趟:15 20 2 52 18
     *       15 2 20 52 18
     *       15 2 20 52 18
     *       15 2 20 18 52
     * 第二趟:2 15 20 18 52
     *       2 15 20 18 52
     *       2 15 18 20 52
     * 第三趟:2 15 18 20 52
     *       2 15 18 20 52
     * 第四趟:2 15 18 20 52
     * */
    private static int[] sort1(int[] arr) {
        int k = 0;  // 定义一个变量,用于计算进入第二层循环的次数
        for (int i = 0; i < arr.length; i++) {
            // 遍历数组,进行两两比较
            for (int j = 0; j < arr.length - 1 - i; j++) {
                int temp = 0;   // 定义一个临时变量,用于帮助两个元素值的交换
                // 进行元素的比较与交换
                if (arr[j+1] < arr[j]) {
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
                k++;
            }
        }
        System.out.println("优化的冒泡排序的k值:" + k);
        return arr;
    }

    // 优化的冒泡排序
    /*
     * 原数组:15 20 2 52 18
     * 第一趟:15 20 2 52 18
     *       15 2 20 52 18
     *       15 2 20 52 18
     *       15 2 20 18 52
     * 第二趟:2 15 20 18 52
     *       2 15 20 18 52
     *       2 15 18 20 52
     * 第三趟:2 15 18 20 52
     *       2 15 18 20 52
     * */
    private static int[] sort2(int[] arr) {
        int k = 0;  // 定义一个变量,用于计算进入第二层循环的次数
        for (int i = 0; i < arr.length; i++) {
            boolean flag = false;
            // 遍历数组,进行两两比较
            for (int j = 0; j < arr.length - 1 - i; j++) {
                int temp = 0;   // 定义一个临时变量,用于帮助两个元素值的交换
                // 进行元素的比较与交换
                if (arr[j+1] < arr[j]) {
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    flag = true;
                }
                k++;
            }
            // 若没有进行交换,则说明数组已排序好,可以结束循环了,此时flag=false
            if (!flag) {
                break;
            }
        }
        System.out.println("优化的冒泡排序的k值:" + k);
        return arr;
    }
}

运行结果:

优化的冒泡排序的k值:10
未优化的数组:[2, 15, 18, 20, 52]
优化的冒泡排序的k值:9
优化的数组:[2, 15, 18, 20, 52]

说明:由于进行第三趟后,数组已完成排序,因此优化后的冒泡排序结束循环,未进行第四趟的比较。

【个人理解】
关于优化前与优化后,可以简单这样理解,有两个人想要去旅行,旅游公司都为他们制定了路线,第一个人跟着路线走,无论路线上的景点是否去过,都要再走一遍;而第二个人也是跟着路线走,但旅行到一半他发现后面的景点自己之前都去过了,因此他就去不了,直接结束本次旅行。


【程序员养成之路】Java基础篇 1-聊聊Java那些事

【程序员养成之路】Java基础篇 2-初学Java必知的基础语法

【程序员养成之路】Java基础篇 4-从面向对象里找对象

【程序员养成之路】Java基础篇 5-从异常机制认识常见bug

【程序员养成之路】Java基础篇 6-啥都能“装”的集合

【程序员养成之路】Java基础篇 7-流进流出的IO流(一)

【程序员养成之路】Java基础篇 8-流进流出的IO流(二)

【程序员养成之路】Java基础篇 9-认识一下类加载器与反射


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正则表达式1951

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值