数组,方法结合底层逻辑代码分析,返回值选择问题【-1在数组中的重要思想】

文章详细介绍了针对数组的一系列操作,包括查找最大值和最小值的下标、计算最大元素个数、存储最大值的下标、查找元素首次和最后一次出现的下标、数组子集、数组复制、数组反转、元素添加与删除以及选择排序和冒泡排序的实现。这些代码示例展示了基础的数组处理和排序算法的底层逻辑。
摘要由CSDN通过智能技术生成

数组方法结合底层逻辑代码分析

1. 数组相关操作
1.1 指定数组找出数组中最大值下标位置

int[] arr = {1, 3, 5, 7, 9, 21, 4, 6, 8, 10};
找出数值中最大值下标位置:
maxIndex = 5;

	/**
     * 找出数值中最大值下标位置:
     * @param arr 目标数组 int 类型数组
     * @return 返回数组中最大值的下标 int 类型
     */
    public static int getMaxIndex(int[] arr) {
        // 假设 maxIndex  = 0 为最大下标位置
        int maxIndex = 0;

        // 从下标为 1 开始遍历
        for (int i = 1; i < arr.length; i++) {

            // 遇到比 maxIndex 对应数组元素大的,将 i 赋值给 maxIndex
            if (arr[maxIndex] < arr[i]){
                maxIndex = i;
            }
        }

        // 返回最大值下标
        return maxIndex;
    }	
1.2 指定数组找出数组中最小值下标位置

int[] arr = {1, 3, 5, 7, 9, 21, 4, 6, 8, 10};
找出数组中最小值下标位置:
minIndex = 0;

	/**
     * 找出数组中最小值下标位置
     * @param arr 目标数组 int 类型数组
     * @return 返回数组中最小元素的下标 int 类型
     */
    public static int getMinIndex(int[] arr) {
        // 假设下标为 0 的元素是数组中最小值
        int minIndex = 0;

        // 从下标为 1 的元素开始遍历
        for (int i = 1; i < arr.length; i++) {

            // 遇到比 minIndex 对应数组元素小的,将 i 赋值给 minIndex
            if (arr[minIndex] > arr[i]){
                minIndex = i;
            }
        }

        // 返回最小值对应下标
        return minIndex;
    }
1.3 指定数组中最大元素个数

int[] arr = {0, 21, 5, 21, 9, 21, 4, 6, 21, 10};
最大值个数
maxValueCount = 5;

	/**
     * 找出数组中最大值个数
     * @param arr int 类型目标数组
     * @return int 类型返回数组中最大值的个数
     */
    public static int getMaxValueCount(int[] arr) {
        // 假设数组中下标为 0 的元素是最大值
        int maxValeue = arr[0];
        // count 用于记录最大值的个数
        int count = 1;

        // 从下标 = 1 开始遍历
        for (int i = 1; i < arr.length; i++) {

            // 如果遇到比假设最大值大的数 将当前元素赋值给 maxValue 并且 count 重置为 1
            if (maxValeue < arr[i]){
                maxValeue = arr[i];
                count = 1;
            }else if (maxValeue == arr[i]){

                // 如果遇到跟假设最大值相等的数 count 自增
                count += 1;
            }
        }

        return count;
    }
1.4 指定数组中最大值元素所有对应下标位置,要求存储到另一个数组中

int[] arr = {21, 21, 5, 21, 9, 21, 4, 6, 21, 10};
其他数组:
int[] indexArray = {0, 1, 3, 5, 8};

核心知识点

  1. 尾插法
  2. 空间效率和时间效率问题

int[] arr = {21, 21, 5, 21, 9, 21, 4, 6, 21, 10};
其他数组:
int[] indexArray = {0, 1, 3, 5, 8};

// 【方案一】 存储下标的数组容量与源数组容量一致 (牺牲空间换时间)
/**
     * 指定数组中最大值元素所有对应下标位置,存储到另一个数组中
     * @param arr 目标数组 int 类型
     * @return 返回目标数组对应最大元素的下标值数组 int 类型
     */
    public static int[] getMaxIndexArrOf(int[] arr) {
        /*
           常规思路 1. 找出最大值
                    2. 创建新数组
                    3. 将最大值元素下标存入新数组中
         */

        // 假设数组最大值 maxValue = arr[0];
        int maxValue = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (maxValue < arr[i]){
                maxValue = arr[i];
            }
        }

        // 创建新数组
        int[] maxIndexArr = new int[arr.length];

        /*
            尾插法使用的计数器 1. 用于记录数组有效元素个数
                              2. 用于记录下次存入数据的下标位置
         */
        int count = 0;

        for (int i = 0; i < arr.length; i++) {
            if (maxValue == arr[i]){
                // 找到与最大值相等的元素将元素对应下标存入新数组中然后 count++
                maxIndexArr[count++] = i;
            }
        }

        return maxIndexArr;
    }
// 【方案二】 存储下标的数组容量与源数组容量一致 单循环形式
/**
     * 指定数组中最大值元素所有对应下标位置,存储到另一个数组中
     * @param arr 目标数组 int 类型
     * @return 返回目标数组对应最大元素的下标值数组 int 类型
     */
    public static int[] getMaxIndexArrOf2(int[] arr) {
        // 假设 arr[0] 为数组最大值
        // 尾插法 count 计数器 1. 用于记录数组中有效元素个数
        //                    2. 用于记录下次存入数组的下标位置
        int maxValue = arr[0];
        int count = 0;

        // 新建一个数组长度等于源数组长度的新数组
        int[] maxIndexArr = new int[arr.length];

        for (int i = 0; i < arr.length; i++) {
            // 判断目前最大值是否小于 arr[i]
            if (maxValue < arr[i]){
                // 为真 则变更 最大值 maxValue = arr[i]
                // 将 count 重置为0
                // 将 i 插入到新数组中 count++
                maxValue = arr[i];
                count = 0;
                maxIndexArr[count++] = i;
            } else if (maxValue == arr[i]) {
                // 目前最大值等与 arr[i] 将新数组对应 count 元素赋值为 i 并且 count++
                maxIndexArr[count++] = i;
            }
        }

        return maxIndexArr;
    }
// 【方案三】 存储下标的新数组容量等于源数组最大元素个数 (牺牲时间换空间)
/**
     * 指定数组中最大值元素所有对应下标位置,存储到另一个数组中
     * @param arr 目标数组 int 类型
     * @return 返回目标数组对应最大元素的下标值数组 int 类型
     */
    public static int[] getMaxIndexArrOf3(int[] arr) {
        /*
            思路:1. 找出源数组最大值的个数
                  2. 根数个数创建新数组
                  3. 将源数组最大值元素对应下标存入新数组
         */

        // 假定 arr[0] 为源数组中最大值
        int maxValue = arr[0];
        // count 记录最大值的个数
        int count = 1;
        for (int i = 1; i < arr.length; i++) {
            if (maxValue < arr[i]){
                maxValue = arr[i];
                count = 1;
            }else if (maxValue == arr[i]){
                count += 1;
            }
        }

        // 创建新数组
        int[] maxIndexArr = new int[count];

        count = 0;
        for (int i = 0; i < arr.length; i++) {
            if (maxValue == arr[i]){
                maxIndexArr[count++] = i;
            }
        }

        return maxIndexArr;
    }
1.5 找出指定元素在指定数值中第一次出现的下标位置 【 重要 -1 在源码中的思想 】
找出指定元素在指定数值中第一次出现的下标位置
int[] arr = {1, 3, 5, 7, 9, 21, 3, 7, 8, 10};
3 在数组中第一次出现的位置下标位置 1
/**
     * 找出指定元素在指定数值中第一次出现的下标位置
     * @param arr   目标数组 int类型
     * @param value 用户提供的指定数组 int 类型
     * @return 返回 value 在目标数组中第一次出现的下标如果为 -1 表示数组中没有此元素
     */
    public static int getFirstIndex(int[] arr, int value) {
        /* 初始化找的下标为 index = -1
            【注意重点】 -1 思想,此方法要求返回的是下标,而 -1 见名知意
            一定是一个非法下标,用来告知数组中没有找到此元素,如果找到对应
            元素下标则正常返回下标。
        */
        int index = -1;

        for (int i = 0; i < arr.length; i++) {
            if (value == arr[i]){
                index = i;
                // 方法要求返回第一个找到的下标位置 所以一旦找到直接 break 退出循环
                break;
            }
        }

        return index;
    }
1.6 找出指定元素在指定数组中最后一次出现的下标位置

找出指定元素在指定数组中最后一次出现的下标位置
int[] arr = {1, 3, 5, 7, 9, 21, 3, 7, 8, 10};
3 在数组中最后一次出现的位置下标位置 6

思想一样只要当着循环找到直接退出就可以

/**
     * 找出指定元素在指定数值中最后一次出现的下标位置
     * @param arr   目标数组 int类型
     * @param value 用户提供的指定数组 int 类型
     * @return 返回 value 在目标数组中最后一次出现的下标 如果为 -1 表示数组中没有此元素
     */
    public static int getLastIndex(int[] arr, int value) {
        int index = -1;

        for (int i = arr.length - 1; i >= 0; i--) {
            if (value == arr[i]){
                index = i;
                break;
            }
        }

        return index;
    }
1.7 从数组中指定下标开始,到指定下标结束,获取数据存储到新数组中 【重要思想,条件整合与边界思想】
/**
     * 从数组中指定下标开始,到指定下标结束,获取数据存储到新数组中
     * @param arr    int 类型目标数组
     * @param start  int 类型指定的开始下标位置
     * @param end    int 类型指定的结束下标位置
     * @return 返回从指定下标到结束下标位置所有元素对应的 int 类型数组
     */
    public static int[] subArray(int[] arr, int start, int end) {
        
        /*
          判断用户输入下标是否合法,首先不合法的条件 1. start > end
                                                   2. start < 0
                                                   3. end > arr.length - 1
                                                   4. start > arr.length - 1
                                                   5. end < 0
          【仔细分析】 当 start < end 这个先决条件出现时加上 end < arr.length - 1 时是不会出现 end < 0 这种情况的
                       相同的 start > arr.length - 1 也不会出现,这就是条件出现了【冗余】现象,所以我们要有【边界思想】
        */
        
        if (start > end || start < 0 || end > arr.length - 1){
            // 此时 返回值要求返回 int 类型数组,所以我们不能再返回 -1 来表示输入下标不合法,所以要引入【异常】
            throw new IllegalArgumentException("下标范围不合法");
        }

        // 【Java 源码思想】在 Java 中一般出先范围下标要遵循【含头不含尾】原则
        // 所以在定义新数组长度时可以是 end - start
        int[] subArray = new int[end - start];

        // 尾插法计数器 count 1. 用来记录数组中有效元素个数 2. 用来记录下次存入数组的下标
        int count = 0;
        // 遍历源数组 从下标 start 开始到 end 结束
        for (int i = start; i < end; i++) {
            subArray[count++] = arr[i];
        }

        return subArray;
    } 

【深入剖析】返回值是引用数据,比如此题中的数组,在内存中的情况

在这里插入图片描述

1.8 复制指定数组数据内容到新数组 【保护数据】

【重要思想】此操作带给我们的作用看似毫无卵用,但是在后期的数据操作中,对于数据的保护是非常重要的,因为数据一点损毁将不可逆,造成的损失将不可估量,所以可以先复制一份数据,保留源数据。

/**
     * 复制指定数组数据内容到新数组
     * @param arr 指定 int 类型目标数组
     * @return 返回复制数据后的新数组 int 类型
     */
    public static int[] copyOf(int[] arr) {
        // 新建一个数组
        int[] newArr = new int[arr.length];

        for (int i = 0; i < arr.length; i++) {
            newArr[i] = arr[i];
        }

        return newArr;
    }
1.9 指定数组内容逆序
	/**
     * 指定数组内容逆序
     * @param arr 指定的 int 类型目标数组
     */
    public static void reverse(int[] arr) {

        for (int i = 0, j = arr.length - 1; i < j; i++,  j--) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
1.10 在数组指定下标位置添加元素 【选择合适的返回值类型】

目标数组:
int[] arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 0};
注意:

  1. 0 无效元素,仅占位使用
  2. 插入数据下标的位置必须在合法范围以内
  例如:
  	添加指定元素 20 到下标为 5 的位置
  	{1, 3, 5, 7, 9, 20, 11, 13, 15, 17};

在这里插入图片描述

	/**
     * 在数组指定下标位置添加元素
     * @param arr   int 类型目标数组
     * @param index int 类型目标下标位置
     * @param value int 目标元素
     * @return boolean 类型 true 表示添加成功 false 表示添加失败
     */
    public static boolean add(int[] arr, int index, int value) {
        // 判断下标是否合法
        if (index < 0 || index > arr.length - 1){
            return false;
        }

        /*
            细节:从插入元素的下标开始所有元素后移,因此我们需要从数组后边开始遍历每个元素后移
            到指定下标位置为止,最后在指定下标位置 赋值 value
         */

        for (int i = arr.length - 1; i > index; i--) {
            arr[i] = arr[i - 1];
        }

        // 最后将指定数据添加到指定下标位置
        arr[index] = value;
        return true;
    }	
1.11 删除数组中指定下标元素内容

目标数组:
int[] arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
注意:

  1. 0 是无效元素,仅占位使用
  2. 删除之后,要求数组元素向前移动
  3. 删除数据下标的位置必须在合法范围以内
  	ArrayIndexOutOfBoundsException 
  	例如:
  	删除指定下标 5 的元素
      	{1, 3, 5, 7, 9, 13, 15, 17, 19, 0}

【注意】此题看似和上题类似,但是实则不然,考虑到对**【数据的保护】**在选择返回值的时候,我们需要考虑 int 类型

​ 因为用户在删除指定下标的元素时,用户只知道下标数据,对元素一无所知,我们需要在删除成功时对调用者返回一个 int 类型的所删除的数据

​ 这样调用者可以看到删除的数据是什么,如果调用者误删除也可以给调用者一个反悔的机会。

​ 同样的我们会面对另一个问题,删除失败时返回什么呢? 这是我们就要引入异常,可以抛出异常

在这里插入图片描述

/**
     * 删除数组中指定下标元素内容
     * @param arr   int 类型目标数组
     * @param index int 类型指定下标
     * @return int 类型删除成功返回删除的元素值
     */
    public static int remove(int[] arr, int index){
        // 判断下标是否合法
        if (index < 0 || index > arr.length - 1){
            throw new IllegalArgumentException("下标不合法");
        }

        /*
            细节:从删除元素开始所有元素向前移,因此我们需要从前开始遍历数组到指定下标位置
                  最后在有效元素后一位的位置插入 0 充当占位符
         */

        // 为了保护数据提前将要删除的元素赋值给 temp
        int temp = arr[index];

        for (int i = index; i < arr.length - 1; i++) {
            arr[i] = arr[i + 1];
        }
		// 在有效元素后一位的位置插入 0 充当占位符
        arr[arr.length - 1] = 0;
         // 返回删除的数据
        return temp;
    }
1.12 选择排序算法

选择排序算法核心

  1. 找极值( 极大值, 极小值)
  2. 换位置
/**
     * 选择排序算法
     * @param arr int 类型需要排序的数组
     */
    public static void selectSortDesc(int[] arr) {
        // 排序到倒数第二个时就已经全部有序所以 i < arr.length - 1
        for (int i = 0; i < arr.length - 1; i++) {

            //假设 i 为极值对应下标
            int index = i;

            // i + 1 之前的元素已经排序好 不在需要遍历
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[index] < arr[j]){
                    index = j;
                }
            }

            // 如果 index != i 说明发现了新的极值那么交换位置
            if (index != i){
                int temp = arr[index];
                arr[index] = arr[i];
                arr[i] = temp;
            }
        }
    }
1.13 冒泡排序

在这里插入图片描述

/**
     * 冒泡排序
     * @param arr 需要排序的 int 类型数组
     */
    public static void bubbleSortDesc(int[] arr) {
        // 排序到倒数第二个时就已经全部有序所以 i < arr.length - 1
        for (int i = 0; i < arr.length - 1; i++) {

            // 每轮排序完毕数组的末尾位置元素时有序的所以要 - i 而需要遍历到 arr[j + 1] 防止指针越界 所以需要 -1
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] < arr[j + 1]){
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值