對數器都不準備那筆試什麼的就涼透了!要打有準備的仗
本文由左程雲老師講授個人整理總結
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();