有时候做算法题可能无法短时间内,或者很难推导出正确的数学式子(比如贪心算法),来验证自己算法的正确,这时候就需要大量的随机样本进行测试验证。
对数器能够产生大量的随机数据
对数器的实现要素
1 比如你要测试冒泡排序bubbleSort方法的正确性
1,实现一个绝对正确的但是时间或空间复杂度不好的方法比如库函数sort
2,实现一个随机样本产生器
3,实现比对的方法
4,把方法bubbleSort和方法sort比对很多次来验证方法bubbleSort是否正确
5,如果有一个样本使得比对出错,打印样本分析是哪个方法出错
6,当样本数量很多时比对测试依然正确,可以确定方法bubbleSort已经正确
对数器
生成一个长度范围在[0, size]的任意长度并且任意位置是随机值的数组
/随机值的范围在:(-value, value]
//对数器: 生成一个长度范围在[0, size]的任意长度并且任意位置是随机值的数组
//随机值的范围在:(-value, value]
public static int[] generateRandomArray(int size, int value) {
//Math.random() 返回[0, 1)范围中的随机小数
//Math.random() [0, size+1)-->[0, size]
int[] arr = new int[(int)((size+1)* Math.random())]; //(size+1)* Math.random()是[0, size]范围中的随机小数
for(int i=0; i<arr.length; ++i) {
arr[i] = (int) ((value+1)* Math.random() - (value)* Math.random());
}
//(value+1)* Math.random()是[0, value]范围中的随机小数
//(value)* Math.random()是[0, value)范围中的随机小数
//(value+1)* Math.random()-(value)* Math.random() 是(-value, value]范围中的随机小数
return arr;
}
testBubbleSort.bubbleSort(arr1);
testBubbleSort是与当前类testLogarithmMachine在同一个包中的公有类,可以直接通过类名加’.'访问公有静态方法(testBubbleSort.bubbleSort)
公有请看: 封装encapsulation
对类的管理请看: 包
验证: (value+1)* Math.random()-(value)*Math.random() 是(-value,value]范围中的随机小数
int value = 6;
int n = 0;
for(int i=0; i<9999; ++i) {
n = (int) ((value+1)* Math.random() - (value)* Math.random());
if(n == 6 || n == -6)
System.out.println(n);
}
完整代码
package yzy.algorithm;
import java.util.Arrays;
/*
* 测试对数器
*/
public class testLogarithmMachine {
//对数器: 成一个长度范围在[0, size]的任意长度, 并且任意位置是随机值的数组
//随机值的范围在:(-value, value]
public static int[] generateRandomArray(int size, int value) {
//Math.random() 返回[0, 1)范围中的随机小数
//Math.random() [0, size+1)-->[0, size]
int[] arr = new int[(int)((size+1)* Math.random())]; //(size+1)* Math.random()是[0, size]范围中的随机小数
for(int i=0; i<arr.length; ++i) {
arr[i] = (int) ((value+1)* Math.random() - (value)* Math.random());
}
//(value+1)* Math.random()是[0, value]范围中的随机小数
//(value)* Math.random()是[0, value)范围中的随机小数
//(value+1)* Math.random()-(value)* Math.random() 是(-value, value]范围中的随机小数
return arr;
}
//复制数组的方法
public static int[] copyArray(int[] arr) {
if(arr == null)
return null;
int[] res = new int[arr.length];
for(int i=0; i<arr.length; ++i)
res[i] = arr[i];
return res;
}
//绝对正确的方法
public static void rightMethod(int[] arr) {
Arrays.sort(arr);
}
//判断两个数组等价的方法(长度相同, 相同位置索引的元素相同) 相当于arr1.equals(arr2)
public static boolean isEqual(int[] arr1, int[] 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(int i=0; i<arr1.length; ++i) {
if(arr1[i] != arr2[i])
return false;
}
return true;
}
public static void main(String[] args) {
/* 验证:
* (value+1)* Math.random()-(value)* Math.random() 是(-value, value]范围中的随机小数
int value = 6;
int n = 0;
for(int i=0; i<9999; ++i) {
n = (int) ((value+1)* Math.random() - (value)* Math.random());
if(n == 6 || n == -6)
System.out.println(n);
*/
int testTime = 500000; //测试组数
int size = 10; //对数器生成随机数组长度的范围:[0, 10]
int value = 100; //对数器生成随机数组元素值的范围:(-value, value]
boolean succeed = true;
for(int i=0; i<testTime; ++i) {
int[] arr1 = generateRandomArray(size, value);
int[] arr2 = copyArray(arr1);
int[] arr3 = copyArray(arr1);
testBubbleSort.bubbleSort(arr1);
rightMethod(arr2);
if(!isEqual(arr1, arr2)) { //if(!arr1.equals(arr2))
succeed = false;
System.out.println(Arrays.toString(arr3));
break;
}
}
System.out.println(succeed ? "Succeed, nice!" :"Failed, Fucking fucked!");
}
}
贪心算法
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。 贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态
贪婪算法(Greedyalgorithm)是一种对某些求最优解问题的更简单、更迅速的设计技术。用贪婪法设计算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,它省去了为找最优解要穷尽所有可能而必须耗费的大量时间,它采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。
贪婪算法是一种改进了的分级处理方法。其核心是根据题意选取一种量度标准。然后将这多个输入排成这种量度标准所要求的顺序,按这种顺序一次输入一个量。如果这个输入和当前已构成在这种量度意义下的部分最佳解加在一起不能产生一个可行解,则不把此输入加到这部分解中。这种能够得到某种量度意义下最优解的分级处理方法称为贪婪算法。
对于一个给定的问题,往往可能有好几种量度标准。初看起来,这些量度标准似乎都是可取的,但实际上,用其中的大多数量度标准作贪婪处理所得到该量度意义下的最优解并不是问题的最优解,而是次优解。因此,选择能产生问题最优解的最优量度标准是使用贪婪算法的核心。
一般情况下,要选出最优量度标准并不是一件容易的事,但对某问题能选择出最优量度标准后,用贪婪算法求解则特别有效。最优解可以通过一系列局部最优的选择即贪婪选择来达到,根据当前状态做出在当前看来是最好的选择,即局部最优解选择,然后再去解做出这个选择后产生的相应的子问题。每做一次贪婪选择就将所求问题简化为一个规模更小的子问题,最终可得到问题的一个整体最优解。