对数器的简单介绍

201 阅读2分钟

对数器的简单介绍

一、什么叫对数器

对数器简单来讲就是一个用一堆的随机数据对你的算法进行测试的工具,相当于一个验算器,在编程比赛或者笔试中,可以更迅速的排错,其用处十分之大。

二、对数器怎么使用

要正确的使用对数器,首先要清楚以下几个步骤:

  1. 有一个你想要测的方法a;
  2. 自己实现一个绝对正确但是复杂度一般的方法b;
  3. 实现一个随机样本产生器;
  4. 实现对比算法的方法;
  5. 把方法a和方法b比对多次来验证方法a是否正确;
  6. 如果有一个样本使比对出错,则打印样本并分析是哪个部分出错
  7. 当样本数量很多,且测试依然全部正确时,则可以确定方法a已经正确。

三、对数器的使用

归并排序为例,我们来实现一个自己的对数器,首先我们要搞清楚对数器的几个重要组成功能:

  1. 绝对正确的方法b(例如要验证一个排序算法a,则可以用系统提供的排序算法当作方法b;如果要验证其他的算法,则方法b可以是一个绝对正确的暴力算法,可以依照情景的不同选取不同的方法b);
  2. 生成随机数组arr1和arr2(用于测试);
  3. 判断arr1和arr2中的每个值是否相等
  4. 拷贝数组
  5. 打印数组(输出正确或错误信息)。

下面通过代码可以更直观的理解对数器的使用方法:

package 苟熊岭熊哒;

import java.util.Arrays;

public class Main {
	// 归并排序
	public static void MergeSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			//当left==right,说明已经分到只有一个数了,故直接返回
			return;
		}

		int left = 0;
		int right = arr.length - 1;

		process(arr, left, right);
	}

	// 归并排序--分组
	public static void process(int[] arr, int left, int right) {
		if (left == right) {
			return;
		}

		int mid = left + ((right - left) >> 1);
		process(arr, left, mid);//分组--左半边
		process(arr, mid + 1, right);//分组--右半边
		merge(arr, left, mid, right);//归并
	}

	// 归并排序--归并
	public static void merge(int[] arr, int left, int mid, int right) {
		// (right-left)+1:传过来的数组内的元素个数
		int[] tmp = new int[(right - left) + 1];

		int p = 0;//临时数组tmp的下标
		int p1 = left;//左半边组的初始下标
		int p2 = mid + 1;//右半边组的初始下标

		while (p1 <= mid && p2 <= right) {
			tmp[p++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
			//如果p1指向的数小于等于p2指向的数 (默认规定) ,则将p1指向的数拷入tmp数组中
			//反之则将p2指向的数拷入tmp数组中
		}

		//当右边的组已经排完后,将左边组剩余的所有数直接拷到tmp数组中
		while (p1 <= mid) {
			tmp[p++] = arr[p1++];
		}

		//当左边的组已经排完后,将右边组剩余的所有数直接拷到tmp数组中
		while (p2 <= right) {
			tmp[p++] = arr[p2++];
		}

		//拷贝数组
		for (int i = 0; i < tmp.length; i++) {
			//注意:arr数组是从i+left开始的
			arr[i + left] = tmp[i];
		}
	}

	// 用系统提供的方法进行排序
	public static void comparator(int[] arr) {
		Arrays.sort(arr);
	}

	// 生成一个随机数组
	public static int[] generateRandomArray(int maxSize, int maxValue) {
		// Math.random() -> 随机在[0,1)范围内返回一个double类型的数(等概率)
		// Math.random()*A -> 随机在[0,A)范围内返回一个double类型的数(等概率)
		// (int)(Math.random()*A) -> 随机在[0,A-1]范围内返回一个int类型的数(等概率)
		int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) ((maxValue + 1) * Math.random());
		}
		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;
	}

	// 判断arr1和arr2中的每个值是否相等
	public static boolean isEqual(int[] arr1, int[] arr2) {
		int i = 0;
		while (i < arr1.length) {
			if (arr1[i] == arr2[i]) {
				i++;
			} else {
				return false;
			}
		}
		return true;
	}

	// 打印数组
	public static void printArray(int[] arr) {
		for (int a : arr) {
			System.out.print(a + " ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		int testTime = 500000;// 测试次数,50万次
		int maxSize = 100;// 数组的规模不大于100
		int maxValue = 100;// 数组中每个值的范围,负100到正100
		boolean succeed = true;
		for (int i = 0; i < testTime; i++) {
			int[] arr1 = generateRandomArray(maxSize, maxValue);
			// 创建一个数组,长度随机,值也随机
			int[] arr2 = copyArray(arr1);
			// 拷贝arr1中的值和长度
			MergeSort(arr1);//用自己写的归并排序,来排arr1
			comparator(arr2);// 用系统提供的排序,来排arr2
			// 排完序后,比较arr1和arr2的每个位置的值都是不是一样
			if (isEqual(arr1, arr2) == false) {
				// 若值不一样,则该次测试失败
				succeed = false;
				printArray(arr1);// 打印arr1排成了什么样
				printArray(arr2);// 打印arr2排成了什么样
				break;// 跳出循环
			}
		}
		System.out.println(succeed ? "方法正确 !" : "有错误!");
	}
}

输出结果:

image.png


对数器的介绍到这里就结束了,如果你觉得本篇文章对你多少有些帮助,可以点个赞或者收藏一波支持一下哦,欢迎各位大佬批评指正,咱们下次再见!