对数器验证算法的正确性
对数器介绍
1.有一个你想要测的方法a;
2.实现一个绝对正确但是复杂度不好的方法b;
3.实现一个随机样本产生器;
4.实现对比算法a和b的方法;
5.把方法a和方法b比对多次来验证方法a是否正确;
6.如果有一个样本使得比对出错,打印样本分析是哪个方法出错;
7.当样本数量很多时比对测试依然正确,可以确定方法a已经正确。
我们在写算法的时候很多情况下可能是应为没有案例测试而找不到bug,而通过对数器我们可以很方便的进行大量的样本测试,在这些样本中找到算法中不正确的案例,通过这些案例我们就能够发现我们的的程序出错在哪?如果大样本我们的程序都没有出错那么我们的程序也就可以理解为是正确的了。
/**
* 生成一个长度为 0-maxLength 的 int 数组,范围是 [minValue,maxValue)<br/>
* 只有正数 无负数<br/><br/>
* <p>
* 用法:<br/>
* int[] array = ArrayTools.randomArray(20, 5, 10);<br/>
* for (int i : array) {<br/>
* System.out.print(i + " ");<br/>
* }<br/>
* 结果如下:<br/>
* 8 7 7 8 9 7 5 5 9 9 6 5 8 8 7 6 9 7 8 5<br/>
*
* @param maxLength 数组长度
* @param minValue 生成的数值都大于等于 minValue
* @param maxValue 生成的数值都小于 maxValue
* @return 生成一个长度为 0-maxLength 的 int 数组,范围是 [minValue,maxValue)
* @throws IndexOutOfBoundsException 左边界不能大于右边界
*/
public static int[] randomArray(int maxLength, int minValue, int maxValue) {
int[] array = new int[random(0, maxLength + 1)];
if (minValue > maxValue) {
throw new IllegalArgumentException("左边界不能大于右边界");
}
int range = maxValue - minValue;
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * range) + minValue;
}
return array;
}
/**
* 生成一个 在 [minValue,maxValue) 的随机整数
* @param minValue 最小值
* @param maxValue 最大值
* @return 在 [minValue,maxValue) 的随机整数
*/
public static int random(int minValue, int maxValue) {
if (minValue > maxValue) {
throw new IllegalArgumentException("左边界不能大于右边界");
}
int rang = maxValue - minValue;
return (int) (Math.random() * rang) + minValue;
}
/**
* 检验数组是否是升序排列
* @param arr 待检查数组
* @return 检查结果
*/
public static boolean isSorted(int[] arr) {
if (arr.length < 2) {
return true;
}
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max > arr[i]) {
return false;
}
max = Math.max(max, arr[i]);
}
return true;
}
/**
* 交换 arr 数组当中 i 位置和 j 位置的元素
* @param arr 待交换数组
* @param i 第一个元素位置
* @param j 第二个元素位置
*/
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
/**
* 选择排序
* @param arr 待排序数组
*/
public static void selectionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
int N = arr.length;
for (int i = 0; i < N; i++) {
int minValueIndex = i;
for (int j = i + 1; j < N; j++) {
minValueIndex = arr[j] < arr[minValueIndex] ? j : minValueIndex;
}
swap(arr, i, minValueIndex);
}
}
public static void main(String[] args) {
int maxLength = 50;
int maxValue = 1000;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
int[] arr1 = randomArray(maxLength, 0, maxValue);
int[] arr2 = arr1.clone();
selectionSort(arr1);
if (!isSorted(arr1)) {
printArray(arr2);
System.out.println("选择排序错了");
break;
}
}
}
对数器模板
介绍:
该对数器会对我们写的 target() 函数 进行 500000 ,每次目标数组是最大长度为 maxLength 最大值为maxValue 的整数数组, 目标值是生成一个最大值为maxValue 的整数,通过检验两个函数的计算结果来比对我们写的函数是否正确的方法。
如果我们的函数在高达 50万次 的测试中都正确,那么就可以说明我们的函数是正确的。
- testTimes 函数的测试次数
- randomArray(maxLength, maxValue) 生成一个 最大长度为 maxLength 最大值为maxValue 的整数数组
- random(0, maxValue); 生成一个最大值为maxValue 的整数
- test(arr, num) 通过暴力方法写的低效率函数,但是保证正确率是100%
- target(arr, num) 我们自己写的高效率的函数,不保证100%正确,通过对数器进行检验模板的正确性
public static void main(String[] args) {
int testTimes = 500000;
int maxLength = 50;
int maxValue = 100;
boolean success = true;
for (int i = 0; i < testTimes; i++) {
int[] arr = randomArray(maxLength, maxValue);
Arrays.sort(arr);
int num = random(0, maxValue);
if (target(arr, num) != test(arr, num)) {
success = false;
printArray(arr);
System.out.println(num);
System.out.println("判断出错");
System.out.println("目标函数结果 = " + target(arr, num));
System.out.println("测试函数结果 = " + test(arr, num));
break;
}
}
System.out.println(success ? "LUCK" : "Fucking fucked");
}