1. 程式人生 > >對數器都不準備那筆試什麼的就涼透了!要打有準備的仗

對數器都不準備那筆試什麼的就涼透了!要打有準備的仗

本文由左程雲老師講授個人整理總結

Js實現排序對數器

對數器

在沒法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();