JavaSE - 数组的相关算法

本文详细介绍了JavaSE中数组相关的算法,包括随机数生成(Math.random()、Random类、System.currentTimeMillis())、数组赋值(复制、反转、杨辉三角)、查找(数值最值、线性查找、二分查找)以及排序(冒泡排序、直接插入排序、快速排序)。文章探讨了算法的特性、时间和空间复杂度,并给出了具体的示例代码。
摘要由CSDN通过智能技术生成

JavaSE - 数组的相关算法

本节学习目标:

  • 了解并掌握Java中随机数的生成方式;
  • 了解常用的数组赋值算法;
  • 了解并掌握浅拷贝与深拷贝的区别与理解
  • 了解并掌握常用的数组查找算法;
  • 了解并掌握常用的数组排序算法。

1. 算法简述

算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。

算法 - 百度百科

算法的特征:

  • 有穷性(Finiteness):算法的有穷性是指算法必须能在执行有限个步骤之后终止;
  • 确切性(Definiteness):算法的每一个步骤必须有确切的定义;
  • 输入项(Input):一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件;
  • 输出项(Output):一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;
  • 可行性(Effectiveness):算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步骤,即每个计算步骤都可以在有限时间内完成(也称之为有效性)。

算法的指标:

  • 时间复杂度

    算法的时间复杂度是指执行算法所需要的计算工作量。一般来说,计算机算法是问题规模的函数,算法的时间复杂度也因此记做:
    时间复杂度
    因此,问题的规模越大,算法执行的时间的增长率与的增长率正相关,称作渐进时间复杂度(Asymptotic Time Complexity)。

  • 空间复杂度:算法的空间复杂度是指算法需要消耗的内存空间。其计算和表示方法与时间复杂度类似,一般都用复杂度的渐近性来表示。同时间复杂度相比,空间复杂度的分析要简单得多。

  • 正确性:算法的正确性是评价一个算法优劣的最重要的标准。

  • 可读性:算法的可读性是指一个算法可供人们阅读的容易程度。

  • 鲁棒性:鲁棒性是指一个算法对不合理数据输入的反应能力和处理能力,也称为容错性。

2. 随机数

Java一共有三种方式生成随机数:

  • 使用Math.random()方法;
  • 使用Random类;
  • 使用System.currentTimeMillis()方法。

2.1 Math.random()方法

位于java.lang包下的Math类提供的random()方法产生的是范围在[0.0, 1.0)内的double型数值,由于double类型的精度很高,可以在一定程度下看做随机数。可以强制类型转换为int类型。

获取任意区间的的随机数:

public class JavaRandom {
   
    public static void main(String[] args) {
   
        int x = (int) (Math.random() * (75 - 25) + 25); // 生成区间[25, 75)内的随机整数
        System.out.println(x);
    }
}

2.2 Random类

位于java.util包下的Random类提供了更多产生随机数的方法。它有两个构造方法:

  1. Random():此方法使用当前时间为默认种子生成随机数;
  2. Random(long seed):此方法使用提供的种子生成随机数。

种子是产生随机数时的第一次使用值,一般计算机的随机数都是伪随机数,以一个真随机数(种子)作为初始条件,然后用一定的算法不停迭代产生随机数。
以相同的种子使用相同的方法产生的随机数是相同的。

获取任意区间的整数(只提供了int型和long型随机数生成方法):

import java.util.Random;
public class JavaRandom {
   
    public static void main(String[] args) {
   
        Random random = new Random(); // 使用当前时间作为种子
        int y = random.nextInt(50 - 25) + 25;    // 产生区间[25, 50)内的随机整数
        System.out.println(y);
    }
}

获取任意区间的其他类型数据(boolean型、float型和double型):

import java.util.Random;
public class JavaRandom {
   
    public static void main(String[] args) {
   
        Random random = new Random(12345L);              // 使用12345作为种子
        double d = random.nextDouble() * (98 - 57) + 57; // 生成区间[57.0, 98.0)内的随机数
        System.out.println(d);
    }
}

2.3 System.currentTimeMillis()方法

位于java.lang包下的System类提供的currentTimeMillis()方法可以获取系统当前时间戳(从1970年1月1日0时0点0分到现在所经过的毫秒数)。

用法和Math.random()方法相同,但一般不用currentTimeMillis()方法产生随机数,推荐使用前两种方法。

3. 数组赋值算法

3.1 数组的复制

Object类的clone()方法可以执行特定的克隆(复制)操作。

  • clone()方法是面向引用数据类型(对象)变量的,基本数据类型变量无法使用
  • 使用clone()方法的对象的类必须实现Cloneable接口,否则这个类的对象调用clone()方法会抛出CloneNotSupportedException异常;
  • Object类虽然提供了clone方法,但自身并未实现Cloneable接口。所以尝试在类为Object的对象上调用clone()方法会抛出异常。
  • 所有的数组默认实现了Cloneable接口。

以数组的克隆操作为例,理解浅拷贝深拷贝

编写代码:

import java.util.Arrays;
public class ArrayCopy {
   
    public static void main(String[] args) {
   
        int[][] arr1 = new int[][]{
   {
   87, 62, -39}, {
   75, 69}};
        int[][] arr2 = arr1.clone();
        arr2[0][1] = 0;
        System.out.println(Arrays.toString(arr1[0]));
        System.out.println(arr1 + " " + arr2);
        System.out.println(arr1[0] + " " + arr2[0]);
    }
}

运行结果:

[87, 0, -39]
[[I@1b6d3586 [[I@4554617c
[I@74a14482 [I@74a14482

可以看到我们修改了arr2数组的内容,但是输出arr1时却发现也被修改了;arr1arr2引用的数组对象不同,但arr1[0]arr2[0]引用的数组对象却相同。

  • 浅拷贝
    • 对于成员变量的数据类型为基本数据类型的对象(比如一维数组),浅拷贝为直接进行值传递,拷贝得到的副本和原变量的引用的对象是不同的。
    • 当对象中有引用数据类型的成员变量(比如二维数组),浅拷贝只会拷贝对象本身,副本和原对象的成员变量引用的对象是同一个

浅拷贝内存示意图

  • 深拷贝
    • 深拷贝是相对于浅拷贝来说的,深拷贝就是将对象完全拷贝为一个副本对象,这个对象引用的所有数据都将拷贝一份副本给副本对象引用。

深拷贝内存示意图

如何实现深拷贝?

  • 对于我们编写的类,只需要重写clone()方法,指明要拷贝所有成员变量即可。
  • 对于Java已经定义了的类和数组,将所有引用数据类型的成员变量(二维数组的第二维)全部进行拷贝即可。

浅拷贝只拷贝地址,深拷贝则拷贝数据。

对于引用数据类型变量,类似A = B;这样的操作只会把B所引用的地址赋给A,两者指向的是同一个引用,和拷贝没有关系。

3.2 数组的反转

将一个数组的数据顺序先后颠倒(比如{1, 2, 3}反转为{3, 2, 1})。

示例代码:

import java.util.Arrays;
import java.util.Random;
public class ArrayReverse {
   
    public static void main(String[] args) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值