本文的网课内容学习自B站左程云老师的算法详解课程,旨在对其中的知识进行整理和分享~
一、概念
- 定义
- 在算法学习和验证中,对数器是一种用于检验自己编写的算法是否正确的工具。通常用于比较自己实现的算法(比如排序算法、查找算法等)和已知正确的算法(例如标准库中的算法)的结果是否一致。
- 作用原理
- 对数器会生成多组随机测试数据,然后分别用自己编写的算法和正确的算法对这些数据进行处理,最后对比两组结果。如果对于大量的随机测试数据,两组结果都相同,那么就有较大的把握认为自己编写的算法是正确的。
二、实现步骤(以检验自定义排序算法为例)
- 生成随机测试数据
- 在很多编程语言中,可以使用随机数生成函数来创建随机的数组。例如在Java中,可以使用java.util.Random类来生成随机数填充数组。
- 代码示例(Java):
import java.util.Random;
public class LogarithmChecker {
public static int[] generateRandomArray(int n) {
int[] arr = new int[n];
Random random = new Random();
for (int i = 0; i < n; i++) {
arr[i]=random.nextInt(100);
}
return arr;
}
}
- 调用自己编写的算法和正确算法(如Java中的Arrays.sort)
- 假设我们自己编写了一个排序算法mySort。
- 代码示例(Java):
import java.util.Arrays;
public class LogarithmChecker {
// 假设这是自己编写的排序算法
public static void mySort(int[] arr) {
// 这里是排序算法的具体实现
}
public static boolean checkSort() {
int testTimes = 100;
int maxSize = 100;
int maxValue = 100;
for (int i = 0; i < testTimes; i++) {
int[] arr1 = generateRandomArray(maxSize);
int[] arr2 = arr1.clone();
mySort(arr1);
Arrays.sort(arr2);
boolean equal = true;
for (int j = 0; j < arr1.length; j++) {
if (arr1[j]!= arr2[j]) {
equal = false;
break;
}
}
if (!equal) {
return false;
}
}
return true;
}
}
三.举例说明(用于测试自己写的insertionSort函数是否正确)
算法原理
一、总体思路
- 目标:这段代码主要是实现了插入排序算法,并通过与Java内置的
Arrays.sort
函数对比来验证自己实现的插入排序算法的正确性。同时,代码还包含了一些用于生成随机数组、复制数组、比较数组是否相等以及打印数组的辅助函数。
二、插入排序(insertionSort)原理
- 首先进行边界条件判断,如果数组为空或者长度小于2,直接返回,因为长度小于2的数组本身就是有序的。
- 外层循环
for(int i = 1; i < arr.length; i++)
:从数组的第二个元素(索引为1)开始,逐步将每个元素插入到已排序的部分中。这里假设0 ~ i - 1
的部分已经是有序的,现在要将arr[i]
插入到合适的位置。 - 内层循环
for(int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--)
:在已排序的部分(0 ~ i - 1
)中,从后向前扫描。如果当前元素arr[j]
大于下一个元素arr[j + 1]
,则交换这两个元素(通过swap
函数),继续向前扫描,直到找到合适的位置使得arr[j] <= arr[j + 1]
或者已经扫描到数组的开头(j = 0
)。
三、辅助函数原理
1.交换函数(swap):这个函数用于交换数组中的两个元素。它通过一个临时变量temp
,将arr[i]
和arr[j]
的值进行交换。
2.内置排序比较函数(comparator):这个函数调用了Arrays.sort
函数,它是Java内置的排序函数,这里将其作为一个标准来对比自己实现的排序算法的正确性。
3.随机数组生成函数(generateRandomArray):这个函数用于生成一个随机长度和随机元素值的数组
- 首先,通过
(int) ((maxSize + 1) * Math.random())
计算随机数组的长度,使得长度在0到maxSize
之间(包含0)。 - 然后,对于数组中的每个元素,通过
(int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random())
计算随机值,这个表达式的目的是生成一个在-maxValue
到maxValue
之间(包含两端)的随机整数。
4.数组复制函数(copyArray):这个函数用于复制一个数组。它创建一个新的数组res
,其长度与输入数组arr
相同,然后将arr
中的每个元素依次复制到res
中。
5.数组相等判断函数(isEqual):这个函数用于判断两个数组是否相等。
- 首先进行一些边界情况判断,如两个数组一个为
null
一个不为null
,则直接返回false
;如果两个数组都为null
,则返回true
。 - 如果两个数组长度不同,则返回
false
。 - 最后,通过遍历数组中的每个元素,如果有任何一个元素不相等,则返回
false
;如果所有元素都相等,则返回true
。
6.数组打印函数(printArray):这个函数用于打印数组中的元素。如果数组为null
则直接返回,否则遍历数组并逐个打印元素,最后换行。
四、测试部分原理
- 在
main
函数中:- 定义了测试次数
testTime
为5000000,数组最大长度maxSize
为100,数组元素最大值maxValue
为100。 - 用一个布尔变量
succeed
来表示测试是否成功,初始化为true
。 - 通过一个大循环进行多次测试,每次测试:
- 生成一个随机数组
arr1
,然后复制一份得到arr2
。 - 对
arr1
使用自己实现的插入排序insertionSort
,对arr2
使用内置的排序函数comparator
。 - 如果
arr1
和arr2
不相等(通过isEqual
函数判断),则将succeed
设置为false
并跳出循环。
- 生成一个随机数组
- 最后根据
succeed
的值打印测试结果。然后再生成一个随机数组并进行排序,打印原始数组和排序后的数组。
- 定义了测试次数
代码实现
package com.itheima.demo;
import java.util.Arrays;
public class demo
{
public static void insertionSort(int[] arr)
{
if(arr == null || arr.length < 2)
{
return;
}
// 0~0 有序的
// 0~i 想有序
for(int i = 1; i < arr.length; i++)
{
// 0~i做到有序
for(int j = i-1; j >= 0 && arr[j] > arr[j+1]; j--)
{
swap(arr,j,j+1);
}
}
}
public static void swap(int[] arr, int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//电脑内置的排序函数
public static void comparator(int[] arr)
{
Arrays.sort(arr);
}
//生成一个随机数组
public static int[] generateRandomArray(int maxSize, int maxValue)
{
//Math.random() -> [0,1) 所有的小数,等概率返回一个
//Math.random() * N -> [0,N) 所有小数,等概率返回一个
//(int)(Math.random() *N) -> [0,N-1] 所有的整数,等概率返回一个
int[] arr = new int[(int) ((maxSize + 1) * Math.random())];// 长度随机
for(int i = 0; i < arr.length; i++)
{
arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
}
return arr;
}
//复制数组
public static int[] copyArray(int[] arr)
{
if(arr == null)
{
return null;
}
int[] res = new int[arr.length];
for(int i = 0; i < arr.length; i++)
{
res[i] = arr[i];
}
return res;
}
//判断结果是否相等
public static boolean isEqual(int[] arr1, int[] arr2)
{
if((arr1 == null && arr2 !=null) || (arr1 != null && arr2 == null))
{
return false;
}
if(arr1 ==null && arr2 == null)
{
return true;
}
if(arr1.length != arr2.length)
{
return false;
}
for(int i = 0; i < arr1.length; i++)
{
if(arr1[i] != arr2[i])
{
return false;
}
}
return true;
}
//打印数组
public static void printArray(int[] arr)
{
if(arr == null)
{
return;
}
for(int i = 0; i < arr.length; i++)
{
System.out.print(arr[i] + " ");
}
System.out.println();
}
//测试样例
public static void main(String[] args)
{
int testTime = 5000000;
int maxSize = 100;
int maxValue = 100;
boolean succeed = true;
for(int i = 0; i < testTime; i++)
{
int[] arr1 = generateRandomArray(maxSize, maxValue);
int[] arr2 = copyArray(arr1);
insertionSort(arr1);//自己写的函数(用来测试)
comparator(arr2);//已经确定正确的函数(用来对比)
if(!isEqual(arr1, arr2))
{
succeed = false;
break;
}
}
System.out.println(succeed ? "Nice!" : "Fucking fucked!");
int[] arr = generateRandomArray(maxSize, maxValue);
printArray(arr);
insertionSort(arr);
printArray(arr);
}
}