第四章 数组

一维数组

一维数组的扩容

  • 数组长度一旦确定不可变。
  • 那数组应该如何扩容?
    • 只能创建一个更大的数组将原数组中的数据全部拷贝到新数组中
    • 可以使用System.arraycopy()方法完成数组的拷贝。
  • 数组扩容会影响程序的执行效率,因此尽可能预测数据量,创建一个接近数量的数组,减少扩容次数。

JUnit单元测试

常见注解:

@BeforeAll @AfterAll 主要用于在测试开始之前/之后执行必要的代码。被标注的方法需要是静态的。

@BeforeEach @AfterEach 主要用于在每个测试方法执行前/后执行必要的代码。

// 断言(断言机制)
Assertions.assertEquals(expected, actual);

数据结构与算法

时间复杂度

什么叫做时间复杂度?

我们用T(n)来表示算法中基本操作(例如比较、赋值、运算等)的重复执行次数。n是程序需要处理的数据量(专业术语叫做问题规模n)。若有某个趋势函数f(n)【f(n)代表了时间复杂度的趋势】,使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),我们称O(f(n))为时间复杂度。我们也把它叫做大O表示法。

时间复杂度计算步骤:

1. 计算基本操作的执行次数T(n)

在做算法分析时,一般默认考虑最坏的情况。因为最坏的情况下,基本操作执行的次数是最多的。对算法效率的评估会更加准确。

2. 通过T(n)得到f(n)求T(n)的数量级f(n),只需要将T(n)做两个操作:

(一)忽略常数项、低次幂项和最高次幂项的系数。

(二)例如,在T(n)=4n2+2n+2中,T(n)的数量级函数f(n)=n2。

计算T(n)的数量级f(n),我们只要保证T(n)中的最高次幂正确即可,可以忽略所有常数项、低次幂项和最高次幂的系数。这样能够简化算法分析,将注意力集中在最重要的一点上:增长率。

3. 用大O表示时间复杂度

得到f(n)的结果是n2,所以时间复杂度是:O(n2)。

切记,时间频度不相同,时间复杂度有可能相同,如T(n)=n2+3n+4与T(n)=4n2+2n+1它们的时间频度不同,但时间复杂度相同,都为O(n2)。

常见的时间复杂度

  • 常数阶O(1)

无论代码执行了多少行,只要没有循环等复杂结构,那这个代码的时间复杂度就都是O(1)

int num1 = 3, num2 = 5;

int temp = num1;

num1 = num2;

num2 = temp;

System.out.println("num1:" + num1 + " num2:" + num2);

在上述代码中,没有循环等复杂结构,它消耗的时间并不随着某个变量的增长而增长,那么无论这类代码有多长,即使有几万几十万行,都可以用O(1)来表示它的时间复杂度

  • 对数阶O(log2n)

O(log2n)指的就是:在循环中,每趟循环执行完毕后,循环变量都放大两倍。

int n = 1024;

for(int i = 1; i < n; i *= 2) {

System.out.println("hello powernode");

}

推算过程:假设该循环的执行次数为x次(也就是i的取值为2x),就满足了循环的结束条件,即满足了2x等于n,通过数学公式转换后,即得到了x = log2n,也就是说最多循环log2n次以后,这个代码就结束了,因此这个代码的时间复杂度为:O(log2n) 。

同理,如果每趟循环执行完毕后,循环变量都放大3倍,那么时间复杂度就为:O(log3n) 。

  • 线性阶O(n)

int n = 100;

for(int i = 0; i < n; i++) {

System.out.println("hello powernode");

}

在上述代码中,for循环会执行n趟,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度 。

  • 线性对数阶 O(nlog2n)

int n = 100;

for(int i = 1; i <= n; i++) {

for(int j = 1; j <= n; j *= 2) {

System.out.println("hello powernode");

}

}

线性对数阶O(nlog2n) 其实非常容易理解,将时间复杂度为O(log2n)的代码循环n遍的话,那么它的时间复杂度就是n*O(log2n),也就是了O(nlog2n)。

  • 平方阶 O(n2)

int n = 100;

for(int i = 1; i <= n; i++) {

for(int j = 1; j <= n; j++) {

System.out.println("hello powernode");

}

}

外层i的循环执行一次,内层j的循环就要执行n次。因为外层执行n次,总的就需要执行n*n次,也就是需要执行n2次。因此这个代码时间复杂度为:O(n2)。平方阶的另外一个例子:

int n = 100;

for(int i = 1; i <= n; i++) {

for(int j = i; j <= n; j++) {

System.out.println("hello powernode");

}

}

当i=1的时候,内侧循环执行n次,当i=2的时候,内侧循环执行(n-1)次,......一直这样子下去就可以构造出一个等差数列:n+(n-1)+(n-2)+......+2+1 ≈ (n2)/2。根据大O表示法,去掉最高次幂的系数,就可以得到时间复杂度为:O(n2)。

同理,立方阶 O(n3),参考上面的O(n2)去理解,也就是需要用到3层循环

Arrays工具类

// 凡事自定义的类型要做比较的话,这个自定义类型必须实现一个接口:Comparable接口,并且实现compareTo方法,在这个方法中编写比较规则。

Arrays.toString()方法:将数组转换成字符串
Arrays.deepToString()方法:可以将二维数组转换成字符串
Arrays.equals(int[] arr1, int[] arr2)方法:判断两个数组是否相等
Arrays.equals(Object[] arr1, Object[] arr2)方法
Arrays.deepEquals(Object[] arr1, Object[] arr2)方法:判断两个二维数组是否相等
Arrays.sort(int[] arr)方法:基于快速排序算法,适合小型数据量排序。
Arrays.sort(String[] arr)方法
Arrays.parallelSort(int[] arr)方法:基于分治的归并排序算法,支持多核CPU排序,适合大数据量排序。
int binarySearch(int[] arr, int elt)方法:二分法查找
Arrays.fill(int[] arr, int data)方法:填充数组
Arrays.fill(int[] a, int fromIndex, int toIndex, int val)方法
int[] Arrays.copyOf(int[] original, int newLength)方法:数组拷贝
int[] Arrays.copyOfRange(int[] original, int from, int to)
Arrays.asList(T... data)方法:将一组数据转换成List集合。
//找5的下标
@Test
public void testBinarySearch(){
    int[] arr = {1,2,3,4,5,6,7};
    System.out.println(Arrays.binarySearch(arr, 5));
}
//填充
@Test
public void testFill(){
    int[] arr = new int[5]; // 5个0
    Arrays.fill(arr, 10);
    System.out.println(Arrays.toString(arr));

    // 不包含toIndex
    Arrays.fill(arr, 1, 3, 100);
    System.out.println(Arrays.toString(arr));
}
//拷贝
@Test
public void testCopyOf(){
    // 数组拷贝
    int[] arr = {1,2,3,4,5,6,7,8,9};
    int[] newArr = Arrays.copyOf(arr, 3);
    System.out.println(Arrays.toString(newArr));

    // to不包含
    int[] newArr2 = Arrays.copyOfRange(arr, 2, 4);
    System.out.println(Arrays.toString(newArr2));
}
@Test
public void testAsList(){
    // 将一串数字转换成List集合。
    List list = Arrays.asList(1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7);
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
}
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Java老狗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值