对数器都不准备那笔试什么的就凉透了!要打有准备的仗

本文由左程云老师讲授个人整理总结

对数器

在没法OJ,或OJ也有毛病的时候,我们的算法可能大致是正确的,能简单的通过几个样例,但遇到复杂庞大的样例时抛锚,我们对着冗长的代码,去调试,用人工写样例的方式去测试是愚蠢的,这时候我们需要对数器出场了

什么是对数器

对数器是通过用大量测试数据来验证算法是否正确的一种方式

对数器需要两样东西:

  • 绝对正确的方法
  • 能产生大量随机样例的随机发生器

问题来了,有绝对正确的方法了为什么不用呢,我们不要求绝对正确的算法的时间复杂度和空间复杂度,我们希望用它来证明我们的算法是正确的,这样我们才能确保如何找出我们自己的算法所出现的错误

对数器的使用

  • 有一个你想要测的方法a
  • 实现一个绝对正确但是复杂度不好的方法b
  • 实现一个随机样本产生器
  • 实现比对的方法
  • 把方法a和方法b比对很多次来验证方法a是否正确
  • 如果有一个样本使得比对出错,打印样本分析是哪个方法出错
  • 当样本数量很多时比对测试依然正确,可以确定方法a已经正确

注意事项:通常想要测试的方法a是时间复杂度低的优秀的算法,随机样本发生器产生的样本量应可能100000+,这样才能保证样本状况的全覆盖,样本大小要小,这样出错时才会好比对查出错误。

对数器编写

按步骤

第一步: 有一个你想要测试的方法a
以上一篇书写的插入排序为例:

function InsertionSort(arr){
	if(arr==null||arr.length<2){return;}
	for(var i=1;i<arr.length;i++){
		for(var j=i-1;j>=0&&arr[j]>arr[j+1];j--){
			swap(arr,j,j+1);
		}
	}
	return arr;
}

function swap(arr,i,j){
	arr[i]=arr[i]^arr[j];
	arr[j]=arr[i]^arr[j];
	arr[i]=arr[i]^arr[j];
}

第二步: 实现一个绝对正确但是复杂度不好的方法b
选择编程语言自带的数组排序方法
在这里插入图片描述

sort方法如果不传入参数要求,则数组是按照字符编码的顺序进行排序。

例如:

var arr = new Array(6)
arr[0] = "10"
arr[1] = "5"
arr[2] = "40"
arr[3] = "25"
arr[4] = "1000"
arr[5] = "1"
document.write(arr + "<br />")
document.write(arr.sort())

输出结果是
10,5,40,25,1000,1
1,10,1000,25,40,5

因此如果想按照数值大小排序的话则需要使用一个排序函数:

function sortNumber(a,b){
return a - b
}
document.write(arr.sort(sortNumber))

输出结果是 1,5,10,25,40,1000

最终我们书写一个绝对正确的方法:

function sortNumber(a,b){
return a - b
}
function rightMethod(arr) {
    arr.sort(sortNumber);
}

备注:arr是随机样本生成器产生的随机数组

第三步: 实现一个随机样本产生器

function generateRandomArray(maxSize, maxValue) {
    var arr = new Array(Math.floor((maxSize + 1) * Math.random()));
    for (var i = 0; i < arr.length; i++) {
        arr[i] = Math.floor((maxValue + 1) * Math.random())-Math.floor(maxValue * Math.random());
    }
    return arr;
}

在这里插入图片描述
在这里插入图片描述
代码说明

  • 生成长度随机[0, size]的数组
  • 一个随机数减去另一个随机数,生成[-value, value]的随机数

综上将生成长度随机值也随机的数组

第四步: 把方法a和方法b比对很多次来验证方法a是否正确
比对方法

function isEqual(arr1, 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 (let i = 0; i < arr1.length; i++) {
        if (arr1[i] != arr2[i]) {
            return false
        }
    }
    return true;
}

拷贝数组

function copyArray(arr) {
    if (arr == null) {
        return null;
    }
    return [].concat(arr);
}

大样本量测试

function Test() {
    var testTimes = 100000;
    var maxSize = 10;
    var maxValue = 100;
    var succeed = true;
    for (var i = 0; i < testTimes; i++) {
        var arr1 = generateRandomArray(maxSize,maxValue);
        var arr2 = copyArray(arr1);
        var arr3 = copyArray(arr1);
        InsertionSort(arr1);
        rightMethod(arr2);
        if (!isEqual(arr1, arr2)) {
            succeed = false;
            console.log(arr3);
            break;
        }
    }
    console.log(succeed ? "Good job!" : "Damn it!");
}
Test();

代码说明
testTimes为我们将要进行测试的样本数量,100000次几乎穷尽了可能出现的可能
arr1是随机样本生成器生成的数组,通过拷贝为三份,它们大小数值都相等,但它们是不同的数组
arr1用来测试写的插入排序,arr2用来进行绝对正确检测
如果十万组样本arr1和arr2相等,并且打印出Good job说明arr1完全正确

测试结果

在这里插入图片描述
通过测试!!哇哦

对数器完整代码(测试插入排序为例)

function InsertionSort(arr){
	if(arr==null||arr.length<2){return;}
	for(var i=1;i<arr.length;i++){
		for(var j=i-1;j>=0&&arr[j]>arr[j+1];j--){
			swap(arr,j,j+1);
		}
	}
	return arr;
}

function swap(arr,i,j){
	arr[i]=arr[i]^arr[j];
	arr[j]=arr[i]^arr[j];
	arr[i]=arr[i]^arr[j];
}

function sortNumber(a,b){
return a - b
}

function rightMethod(arr) {
    arr.sort(sortNumber);
}

function generateRandomArray(maxSize, maxValue) {
    var arr = new Array(Math.floor((maxSize + 1) * Math.random()));
    for (var i = 0; i < arr.length; i++) {
        arr[i] = Math.floor((maxValue + 1) * Math.random())-Math.floor(maxValue * Math.random());
    }
    return arr;
}

function isEqual(arr1, 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 (let i = 0; i < arr1.length; i++) {
        if (arr1[i] != arr2[i]) {
            return false
        }
    }
    return true;
}

function copyArray(arr) {
    if (arr == null) {
        return null;
    }
    return [].concat(arr);
}

function Test() {
    var testTimes = 10000;
    var maxmaxSize = 10;
    var maxValue = 100;
    var succeed = true;
    for (var i = 0; i < testTimes; i++) {
        var arr1 = generateRandomArray(maxmaxSize,maxValue);
        var arr2 = copyArray(arr1);
        var arr3 = copyArray(arr1);
        InsertionSort(arr1);
        rightMethod(arr2);
        if (!isEqual(arr1, arr2)) {
            succeed = false;
            console.log(arr3);
            break;
        }
    }
    console.log(succeed ? "Good job!" : "Damn it!");
}
Test();

猜你喜欢

转载自blog.csdn.net/weixin_42507756/article/details/84034921
今日推荐