尚硅谷Java第 4、5 章IDEA,数组

第 4 章:IDEA的使用

第 5 章:数组

5.1 数组的概述

数组(Array):就可以理解为多个数据的组合。

程序中的容器:数组、集合框架(List、Set、Map)。

数组中的概念:

  • 数组名

  • 下标(或索引)

  • 元素

  • 数组的长度

数组存储的数据的特点:

  • 依次紧密排列的、有序的、可以重复的。

  • 数组的其它特点:

    • 一旦初始化,其长度就是确定的、不可更改的。

    • 数组的下标是从0开始的

5.2 一维数组

5.2.1 数组的声明和初始化

代码示例:

复制代码
 int[] arr1 = new int[10];
 String[] arr2 = new String[]{"Tom","Jerry"};

5.2.2 数组的使用

  • 调用数组的指定元素:使用角标、索引、index。

  • index 从 0 开始。

  • 数组的属性:length,表示数组的长度。

  • 数组的遍历。

  • 数组元素的默认初始化值。

5.2.3 一维数组内存分析

  • 虚拟机栈:main() 作为一个栈帧,压入栈空间中。在 main() 栈帧中,存储着 arr 变量。arr 记录着数组实体的首地址值。

  • 堆:数组实体存储在堆空间中。

  • Java 虚拟机的内存划分:

5.3 二维数组

二维数组本质上是元素类型是一维数组的一维数组。

5.4 数组的常用算法

  • 数值型数组的特征值的计算:最大值、最小值、总和、平均值等。

  • 数组元素的赋值。

  • 数组的复制、赋值。

  • 数组的反转。

  • 数组的扩容、缩容。

  • 数组的查找:

    • 线性查找。

    • 二分法查找(前提:数组有序)。

  • 数组的排序:

    • 冒泡排序(最简单)。

    • 快速排序(最常用)。

5.5 Arrays 工具类的使用

  • java.util.Arrays 类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。

  • toString() 、 sort()、 binarySearch()。

5.6 数组中的常见异常

  • 下标越界异常:ArrayIndexOutOfBoundsException

  • 空指针异常:NullPointerException

5.7、企业真题

  1. 数组有没有 length()这个方法? String 有没有 length()这个方法? 答: 数组没有 length(),有 length 属性。 String 有 length()。

  2. 有数组 int[] arr,用 Java 代码将数组元素顺序颠倒? 答: 可以使用两个指针,一个指向数组的第一个元素,另一个指向数组的最后一个元素,交换它们的值,然后继续向中间靠拢,直到两个指针相遇。

    复制代码
     public static void reverseArray(int[] arr)
     {
         int left = 0;
         int right = arr.length - 1;
     ​
         while (left < right)
         {
             int temp = arr[left];
     ​
             arr[left] = arr[right];
             arr[right] = temp;
             left++;
             right--;
         }
     }
     ​
     public static void main(String[] args)
     {
         int[] arr = {1, 2, 3, 4, 5};    // 定义一个数组
     ​
         System.out.println("原数组:" + Arrays.toString(arr));    // 输出原数组
         reverseArray(arr);    // 调用方法将数组元素顺序颠倒
         System.out.println("颠倒后的数组:" + Arrays.toString(arr));    // 输出颠倒后的数组
     }

    运行该主函数,输出结果如下:

    复制代码
     原数组:[1, 2, 3, 4, 5]
     颠倒后的数组:[5, 4, 3, 2, 1]
  3. 为什么数组要从 0 开始编号,而不是 1? 答: 数组的索引,表示了数组元素距离首地址的偏离量。因为第 1 个元素的地址与首地址相同,所以偏移量就是 0,所以数组要从 0 开始。

  4. 数组有什么排序的方式,手写一下? 答: 常见的数组排序方式有冒泡排序、选择排序、插入排序、快速排序、归并排序等。

    冒泡排序: 冒泡排序的思路是从第一个元素开始,依次比较相邻的两个元素,如果前一个元素比后一个元素大,则交换它们的位置。这样一轮下来,最大的元素就会被移动到最后一个位置。然后再从第一个元素开始,继续进行比较和交换,直到所有元素都被排序。

    复制代码
     public class BubbleSort
     {
         public static void main(String[] args)
         {
             int[] arr = {3, 9, 1, 8, 2, 5, 7};
     ​
             bubbleSort(arr);
     ​
             for(int i = 0; i < arr.length; i++)
             {
                 System.out.print(arr[i] + " ");
             }
         }
     ​
         public static void bubbleSort(int[] arr)
         {
             int n = arr.length;
     ​
              for(int i = 0; i < n - 1; i++)
              {
                  for(int j = 0; j < n - i - 1; j++)
                  {
                      if(arr[j] > arr[j + 1])
                      {
                          int temp = arr[j];
                          arr[j] = arr[j + 1];
                          arr[j + 1] = temp;
                      }
                  }
              }
         }
     }

    冒泡排序的时间复杂度为 O(n^2),空间复杂度为 O(1)。

    快速排序: 快速排序的思路是选取一个基准元素,将数组分为左右两部分,左半部分的元素均小于等于基准元素,右半部分的元素均大于等于基准元素。然后对左右两部分分别进行快速排序,直到整个数组有序。在上面的代码中,partition 方法用于实现分区,将数组分为左右两部分。quickSort 方法用于实现快速排序,递归调用自身对左右两部分进行排序。

    复制代码
     public class QuickSort
     {
         public static void main(String[] args)
         {
             int[] arr = {5, 2, 9, 3, 7, 6, 1, 8, 4};
     ​
             quickSort(arr, 0, arr.length - 1);
     ​
             for (int i : arr)
             {
                 System.out.print(i + " ");
             }
         }
     ​
         public static void quickSort(int[] arr, int left, int right)
         {
             if (left < right)
             {
                 int pivot = partition(arr, left, right);
     ​
                 quickSort(arr, left, pivot - 1);
                 quickSort(arr, pivot + 1, right);
             }
         }
     ​
         public static int partition(int[] arr, int left, int right)
         {
             int pivot = arr[left];
     ​
             while (left < right)
             {
                 while (left < right && arr[right] >= pivot)
                 {
                     right--;
                 }
     ​
                 arr[left] = arr[right];
     ​
                 while (left < right && arr[left] <= pivot)
                 {
                     left++;
                 }
     ​
                 arr[right] = arr[left];
             }
     ​
             arr[left] = pivot;
     ​
             return left;
         }
     }

    快速排序的时间复杂度为 O(nlogn),空间复杂度为 O(logn)。

  5. 二分算法实现数组的查找? 答: 二分查找思路: ① 首先确定要查找的数组的范围,即左右边界; ② 计算中间位置,即中间索引值; ③ 判断中间值是否等于要查找的值,如果是,则返回中间索引值; ④ 如果中间值大于要查找的值,则在左半部分继续查找,即将右边界设为中间索引值减一; ⑤ 如果中间值小于要查找的值,则在右半部分继续查找,即将左边界设为中间索引值加一; ⑥ 重复 ②-⑤ 步骤,直到找到要查找的值或左右边界重合,此时返回-1 表示未找到。

    复制代码
     public class BinarySearch
     {
         public static int binarySearch(int[] arr, int key)
         {
             int low = 0;
             int high = arr.length - 1;
     ​
             while (low <= high)
             {
                 int mid = (low + high) / 2;
     ​
                 if (key < arr[mid])
                 {
                     high = mid - 1;
                 }
                 else if (key > arr[mid])
                 {
                     low = mid + 1;
                 }
                 else
                 {
                     return mid;
                 }
             }
     ​
             return -1;
         }
     ​
         public static void main(String[] args)
         {
             int[] arr = {1, 3, 5, 7, 9};
             int key = 3;
             int index = binarySearch(arr, key);
     ​
             if (index == -1)
             {
                 System.out.println("找不到指定的元素");
             }
             else
             {
                 System.out.println("指定元素的索引为:" + index);
             }
         }
     }

    复杂度分析: 时间复杂度为 O(log n),因为每次查找都将查找范围缩小一半,最坏情况下需要查找 log n 次,其中 n 为数组长度。 空间复杂度为 O(1),因为只需要常数个额外变量存储查找范围的左右边界和中间索引值。

  6. 怎么求数组的最大子序列和? 答: 以下是一个使用 Java 实现的求解最大子序列和的示例代码:

    这个算法的思路是使用动态规划的思想。

    我们从左到右遍历整个数组,使用两个变量 maxSum 和 currentSum 来记录最大子序列和和当前子序列和。

    对于当前遍历到的元素 nums[i],我们可以有两种选择: 将 nums[i] 加入当前子序列中,即 currentSum = currentSum + nums[i]; 以 nums[i] 作为新的起点开始一个新的子序列,即 currentSum = nums[i]。

    我们需要比较这两种选择哪个更优,即选择 currentSum + nums[i] 或选择 nums[i] 中的较大值作为当前子序列的和 currentSum。同时,我们需要比较当前子序列的和 currentSum 和最大子序列和 maxSum 哪个更大,即选择 Math.max(maxSum, currentSum)作为新的最大子序列和 maxSum。

    最后,遍历完成后 maxSum 就是最大子序列和。

    复制代码
     public class MaxSubArraySum
     {
         public static int maxSubArraySum(int[] nums)
         {
             int maxSum = nums[0];
             int currentSum = nums[0];
     ​
             for (int i = 1; i < nums.length; i++)
             {
                 currentSum = Math.max(currentSum + nums[i], nums[i]);
                 maxSum = Math.max(maxSum, currentSum);
             }
     ​
             return maxSum;
         }
     ​
         public static void main(String[] args)
         {
             int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
             int maxSum = maxSubArraySum(nums);
     ​
             System.out.println("最大子序列和为:" + maxSum);
         }
     }

    输出:

    复制代码
     最大子序列和为:6

    解释:最大子序列为[4, -1, 2, 1],和为 6。

  7. Arrays 类的排序方法是什么?如何实现排序的? 答: Arrays 类提供了多种排序方法,包括: ① sort(Object[] a):对数组 a 进行升序排序,元素类型必须实现 Comparable 接口。 ② sort(Object[] a, Comparator c):对数组 a 进行排序,使用自定义的 Comparator 比较器进行比较。 ③ parallelSort(Object[] a):对数组 a 进行并行排序,效率更高。

    排序的实现原理主要是基于快速排序和归并排序,具体实现方式根据元素类型和排序方法不同而不同。

    在 sort(Object[] a) 方法中,对于实现了 Comparable 接口的元素类型,通过 compareTo() 方法进行比较,并且使用快速排序实现;对于未实现 Comparable 接口的元素类型,则会抛出 ClassCastException 异常。

    在 sort(Object[] a, Comparator c) 方法中,通过传入自定义的 Comparator 比较器进行比较,也使用快速排序实现。 在 parallelSort(Object[] a) 方法中,使用 Fork/Join 框架实现并行排序,将数组拆分成多个小数组进行排序,最后再合并起来。

相关推荐
xin007hoyo2 分钟前
算法笔记.求约数
c++·笔记·算法
阿黄学技术13 分钟前
ReentrantLock实现公平锁和非公平锁
java·开发语言·算法
汤姆_51117 分钟前
【c语言】字符串函数
c语言·算法
_Itachi__25 分钟前
LeetCode 热题 100 54. 螺旋矩阵
算法·leetcode·矩阵
柏木乃一36 分钟前
平衡二叉搜索树模拟实现1-------AVL树(插入,删除,查找)
c++·学习·程序人生·算法·二叉搜索树·avl树·平衡二叉搜索树
钢铁男儿37 分钟前
C# 类成员与访问修饰符:面向对象编程的核心概念解析
java·javascript·c#
智者知已应修善业1 小时前
【51单片机6位数码管显示时间与秒表】2022-5-8
c语言·c++·经验分享·笔记·单片机·算法·51单片机
八股文领域大手子1 小时前
第 7 篇:跳表 (Skip List):简单务实的概率性选手
java·数据结构·windows·算法·leetcode·链表·动态规划
小O的算法实验室1 小时前
2019年SEVC SCI1区TOP:维度学习粒子群算法TSLPSO,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
阿四啊1 小时前
【Redis】Java操作Redis之SpringDataRedis
java·redis