前言
本文内容讲解的是左神的对数器实现,看了很多别人写的左神对数器文章,在代码注释讲解上力度不够狠,今天给大家分享对数器的代码实现,步骤清晰,每一行都有注释!!!
1.对数器是什么
在说对数器是什么之前,相信很多人都去力扣上刷过算法题,在提交代码的时候,系统会给很多组测试用例,这些测试用例全部都通过了你的代码才算是正确的。对数器就是类似于这样的一个检测你的代码是否正确的系统。
2.对数器能做什么
对数器的作用就是:检查你的算法(方法)是否完全正确
3.实现对数器的步骤
我们类比于力扣的做题系统,对数器的实现步骤为:
1.需要测试的方法a(也就是你自己实现的、需要判断正确性的算法)
比如:排序算法
2.百分百正确的方法b(处理与方法a相同的问题,可以时间复杂度很高很高,但是一定要保证正确率)
比如:如果需要测试的方法a是排序算法,那么方法b的功能应该和a一样,也是排序算法,并且正确率百分百保证正确
3.生成随机的测试用例
比如:如果你需要测试的方法的是对一个数组进行排序,那么这个随机生成的测试用例就是一个数组大小、数组元素都完全随机的数组。
4.实现一个判断分别使用了方法a与方法b以后,同一个测试用例是否完全一样的方法
比如:测试排序算法,测试用例为数组。使用方法a对数组进行排序,使用方法b
对同一个数组进行排序,比较对同一个测试用例排序后,两个数组是否完全相
等,如果是,则方法a对这个测试用例就是正确的。
5.自定义测试用例的数量(一般都是很大的数字)
比如:测试排序算法,测试用例为数组。测试用例生成50万个,如果50万个数组
方法a与方法b对其排序结果都相同,那么方法a就是正确的。
4.对数器源码(java实现,每一行都有注释!!!)
说明:需要测试的方法为排序算法,测试用例为数组。
1.方法a(需要测试正确性的算法):自定义的选择排序算法
2.方法b(百分之百正确的算法):数组工具类的排序算法
3.测试用例:数组大小、数组元素的值都完全随机的数组
/**
* 以排序算法为例:
* 实现对数器的核心步骤:
* 1.实现生成随机数组的方法
* 2.实现判断两个数组是否完全相等的方法
* 3.实现一个完全正确的方法b
* 4.实现需要测试的方法a
*/
public class 对数器实现 {
public static void main(String[] args) {
int testTime = 500000;//测试次数,也就是测试案例的个数50万个
int maxSize = 100;//随机数组最大容量
int maxValue = 100;//随即数组元素最大值
boolean succeed = true;//方法a成功的标志,默认方法a可行
//循环测试500000次,但凡有一次方法a行不通就退出
for (int i = 0;i < testTime;i++){
//获取一个随机数组,拿给方法a执行
int[] arr1 = generateRandomArray(maxSize,maxValue);
//将这个随机数组拷贝一份,拿给方法b执行
int[] arr2 = Arrays.copyOf(arr1,arr1.length);
//1.使用方法a对数组进行排序
selectSort(arr1);
//2.使用方法b对数组进行排序
comparator(arr2);
//3.判断排序过后的arr1与arr2是否完全一样
if (!isEqual(arr1,arr2)){
//进入到这里说明某一次比较中,arr1与arr2排序后不一样
succeed = false;//将标记置为false
Arrays.toString(arr1);//使用数组工具类将arr1打印出来,以便于后续的手动查看错误
Arrays.toString(arr2);//使用数组工具类将arr2打印出来,以便于后续的手动查看错误
break;//退出循环比较过程,因为已经没必要继续比较了
}
}
//通过三目运算符输出方法a是否可行
System.out.println(succeed?"方法a可行!":"方法a有错误!");
}
/**
* 1.实现生成随机数组的方法(数组大小随机,数组元素个数随机)
* @param maxSize 生成的随机数组的最大容量
* @param maxValue 生成的随机数组的元素最大值
* @return 返回生成好的随机数组
*/
public static int[] generateRandomArray(int maxSize,int maxValue){
//1.初始化数组的容量,使用随机数的方式
//Math.random()函数生成一个double类型的小数,值在[0,1)之间
int[] arr = new int[(int)(Math.random()*(maxSize + 1))];
//2.给数组赋值,以随机数的方式
//解释为什么要减去一个随机数:
//因为两个随机数不一样,相减是为了产生负数,使我的数组元素正负都有
for (int i = 0;i < arr.length;i++)
arr[i] = (int)(Math.random()*(maxValue + 1)) - (int)(Math.random()*maxValue);
//3.将随机生成的数组返回
return arr;
}
/**
* 2.实现一个比较器(其实就是我的方法b,是一个确保了正确率的方法)
* @arr 待排序的数组
*/
public static void comparator(int[] arr){
//使用数组工具类自带的排序方法,保证是正确的
Arrays.sort(arr);
}
/**
* 3.实现一个方法,判断数组arr1和数组arr2是否完全相等
* @param arr1 数组1
* @param arr2 数组2
* @return 完全相等返回true,但凡有一点不同就返回false
*/
public static boolean isEqual(int[] arr1,int[] arr2){
//1.一个数组为null,一个数组不为null,直接返回false
if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null))
return false;
//2.arr1与arr2数组同为空
if (arr1 == null && arr2 == null)
return true;
//3.arr1与arr2长度不相等,直接返回false
if (arr1.length != arr2.length)
return false;
//4.此时arr1与arr2都不为空且长度相同,循环遍历依次比较,一个元素不一样直接返回false
for (int i = 0;i < arr1.length;i++)
if (arr1[i] != arr2[i])
return false;
//5.程序执行到这里说明arr1与arr2完全相同,直接返回true
return true;
}
/**
* 4.需要测试的方法a,这里以选择排序为例
* @param arr 待排序的数组
*/
public static void selectSort(int[] arr){
//数组为null,或者数组长度小于2,直接返回
if (arr == null || arr.length < 2)
return;
//外层for,控制每一趟在i ~ n - 1范围查找最小值
for (int i = 0;i < arr.length;i++){
int minIndex = i;//最小值下标,默认为每一趟的起始位置i
//内存for,在具体的i~n -1范围内查找最小值1
for (int j = i;j < arr.length;j++)
minIndex = arr[minIndex] > arr[j]?j:minIndex;
//交换每一趟起始位置i与该范围最小值所在的位置
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
}
}
执行结果为:
说明我的方法a选择排序是正确的。
5.对数器小结
本次讲解对数器是以排序算法为例,其实对数器的用途远远不止于排序算法,比如查找算法等方法都可以使用对数器来检验你的方法是否完全正确。对数器的核心无非就是在于:
1.需要测试的方法a
2.完全正确的方法b
3.生成测试案例
4.判断方法a与方法b对同一个测试案例得到的结果是否完全一致
5.自定义测试案例的数量(一般很大,避免偶然,以确保方法a的正确性)
最后:感谢左神大佬让我学到了这么有用的一个东西!!!