对数器
- 当你碰到一个题,写好代码以后,你想验证是否正确,那么我们应该怎么办呢?
- 可以自己多举几个例子,但是自己举例子考虑得可能不够周全.
- 去找OJ(Online Judge在线评测),但是可能我们不知道这个题在哪个平台上有.
- 自己写一个对数器进行验证,说白了对数器的作用就是给定一组样本,在你的算法和对数器上跑,跑出来结果永远一样的话,那就说明算法是正确的.
- 对数器是什么:
- 说到底,对数器就是一个对应于你的算法所写的绝对正确的(或者直接调用的绝对正确的方法)方法,这个方法和你写的算法可以达到相同效果的方法,例如,你自己写的
冒泡排序
和java
中系统给的Arrays.sort()
方法.这个Arrays.sort()
方法就可以作为对数器标准使用,而且,这个绝对正确的方法不需要在乎复杂度,只需要保证绝对正确就行.
- 对数器的使用步骤:
- 有一个你想要测的方法a;
- 实现一个绝对正确但是复杂度不好的方法b;
- 实现一个随机样本产生器;
- 实现比对的方法;
- 把方法a和方法b比对很对此来验证方法a是否正确;
- 如果有一个样本使得比对出错,打印样本,分析是哪个方法出错;
- 当样本数量很多时比对测试依旧正确,我们就可以确定方法a是正确的.
例子: 以冒泡排序为例
//自己写的冒泡排序算法
private static void bubbleSort(int[] array) {
//首先判断array对象是否为空
//然后判断array是否是单个元素数组
if (array == null || array.length < 2) {
//是就直接退出
return;
}
//控制次数(第一个~最后一个--第一个~倒数第二个--以此类推)
//array.length - 1才是最后一个元素的下标,因为下标是从0开始的
for (int end = array.length - 1; end > 0; end--) {
//j只能指向倒数第二个元素,防止越界
for (int j = 0; j < end; j++) {
//前一个比后一个元素值大,交换位置
if (array[j] > array[j + 1]) {
swap(j, j + 1, array);
}
}
}
}
//交换位置
private static void swap(int i, int j, int[] array) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
//for test
//一个绝对正确的排序算法
public static void rightMethod(int[] array) {
//调用Arrays的sort()方法进行排序,这是绝对正确的
Arrays.sort(array);
}
//for test
/**
* @param length 表示数组的长度
* @param maxValue 表示数组中元素的最大值
* @return 返回一个长度随机, 元素随机的数组
*/
public static int[] createRandomArray(int length, int maxValue) {
//生成[0,length]范围的随机数使得randomArray的长度随机,因为Math.random()是不能到达右边界的,所以需要加1使它取到length这个数
int[] randomArray = new int[(int) (Math.random() * (length + 1))];
// 给随机数组赋值
for (int i = 0; i < randomArray.length; i++) {
//因为Math.random()方法是不会产生负数的,为了更好的模拟真实情况,我们采用两个随机数相减,就有可能产生负数了
randomArray[i] = (int) ((Math.random() * (maxValue + 1)) - (Math.random() * (maxValue + 1)));
}
return randomArray;
}
//for test
/**
* 用于对比两个算法跑出来结果是否相同
*
* @param array1 表示自己写的算法跑出来的结果
* @param array2 表示对数器中的算法跑出来的结果
* @return 返回true表示两者完全相同, false就打印错误样本
*/
public static boolean comparator(int[] array1, int[] array2) {
int len = array1.length;
//如果两个数组长度不相同一定不相同
if (array1.length != array2.length) {
return false;
}
//一个为空一个不为空,一定不相同
if ((array1 == null && array2 != null) || (array2 == null && array1 != null)) {
return false;
}
//遍历数组,进行比较
for (int i = 0; i < len; i++) {
if (array1[i] != array2[i]) {
System.out.println("出错了!,此时自定义算法的数据为 : " + Arrays.toString(array1) +
", 对数器样本数据为 : " + Arrays.toString(array2));
System.out.println(array1[i]);
System.out.println(array2[i]);
return false;
}
}
return true;
}
// for test
/**
*
* @param array 表示要复制的样本
*/
private static int[] copyArray(int[] array) {
int[] copyArray = new int[array.length];
for (int i = 0; i < array.length; i++) {
copyArray[i] = array[i];
}
return copyArray;
}
// for test
public static void main(String[] args) {
int[] a = new int[0];
int[] b = null;
System.out.println(a.length);
System.out.println(b.length);
boolean flag = true;
//产生样本
for (int i = 0; i < 10000; i++) {
int[] array = createRandomArray(10, 1000);
//复制样本
int[] array2 = copyArray(array);
//通过两种算法排序
bubbleSort(array);
rightMethod(array2);
//判断两个数组此时是否相同
flag = comparator(array,array2);
//一旦有不相同,就退出循环
if (flag != true) {
break;
}
}
System.out.println(flag == true ? "恭喜你,你的算法是正确的!" : "继续努力!");
}
- 注意事项:
- 对于
Math.random()
和Random类
不懂的话,我在网上找了一篇很详细的文章,大家可以看看,我就不自己写了,超链接 : 关于生成随机数的两个方法. - 区别一下
int[] a = new int[0];
和int[] b = null;
这两条语句,后者不是长度为0,它不赋值去调用任何东西都是报错. - 我的github博客地址: fanfan999的github博客,可以通过github博客联系我哈哈哈.
- 代码我放我github仓库了,有需自取 : BubbleSort.java