IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 利用对数器验证算法代码程序 -> 正文阅读

[数据结构与算法]利用对数器验证算法代码程序

一、什么是对数器?

通常我们在笔试的时候或者参加编程大赛的时候,自己实现了一个算法,但是不能够判断该算法是否完全没问题,如果在比赛平台上验证,通常只会告诉你有没有错误,出了错不会告诉你哪里有问题,对于排错来说是非常坑爹的,所以对数器就横空出世了,对数器就是用一个绝对OK的方法和随机器生成的样本数据进行合体,如果你的算法是没问题的,那么和对数器的这个百分之百正确的方法一个元素一个元素的比较,也一定是equals的。如果返回false,说明你的算法有问题。

简单来说,就是自己编写一个时间复杂度较低的算法和一个时间复杂度较高的算法进行结果的比对,因为时间复杂度低的算法比较容易实现,当然一定要确保时间复杂度低的算法是流程和结果是对的。再用对数器比较时间复杂度低和时间复杂度高的算法的结果,如果两算法的结果不同,就说明时间复杂度低的算法的实现是错误的。(对数器能保证在不同的情况下、多次进行实验)。

二、对数器的定义

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

三、利用案例理解对数器的作用

看下面这个例子:
题目要求:在一个数组中,只有一种数出现了k次,而其它的数都出现了m次,试找出这个出现了k次的数字。

首先,按照题目要求…出现了几次,并找出该数,则时间复杂度高的可以使用哈希表来进行存储与记录。此处直接贴代码:

public static int test(int[] arr,int k,int m) {
        Map<Integer,Integer> map = new HashMap<>();
        for(int num:arr) {
            if(map.containsKey(num)) {
                map.put(num,map.get(num)+1);
            }else {
                map.put(num,1);
            }
        }
        for(int num:map.keySet()) {
            if(map.get(num)==k) {
                return num;
            }
        }
        return -1;
    }

再接着,实现一个自己要测的实现该题目的算法代码,相对于上面的代码时间复杂度要低。

简单来描述下面代码的操作:
因为只有一种数出现了k次,而其它数都出现了m次,那么从int的角度,有32位,用ans来记录k在某一位上的1,只要出现了k次的数,则在某个位置上一定存在1。就用数组来记录全部数字每一位的1,某个数出现了m次的,在某一位一定是有t[i]%m==0 ;否则就不能被k整除。

public static int FindInitNum(int[] arr,int k,int m) {
        int[] t = new int[32];
        for(int i=0;i<arr.length;i++) {
            for(int j=0;j<=31;j++) {
                t[j]+=(arr[i]>>j)&1;
            }
        }
        int ans =  0;
        for(int i=0;i<32;i++) {
            if(t[i]%m!=0) {
                if(t[i]%m==k) {
                    ans|=(1<<i);
                }
            }
        }
        return ans;
    }

为了验证上面的算法是否正确,就要使用到对数器

1.先准备好一个main方法,指定好要利用什么条件来产生一个数组和数组中包含的数字。因为要保证数字是随机的,会用到大量的产生随机数的方法。我们可以先设置数字的种类数、数字的大小范围、测试的次数。

2.根据本题要求,k一定是要小于m的,因此要保证这个前提条件,有了k和m之后,目标就是要创建一个数组包含某个数出现了k次,其它数出现m次的前提条件,只要该数组创建出来就完成任务了。

3.数组中种类数要确保大于等于2,若只有一种数就不行了。并且可以根据种类数来确定出数组的长度。每填入一种数后,要控制数的种类要-- ,当然,在随机创造出现m次的数时,不可避免的是可能会出现跟出现k次的数是相等的。为了避免这个问题就在下面代码的do while循环中解决了,并且要使用一个Set来保存记录。

4.最后,数组的数填完了,但是我们是每种数依次填入的,为了打乱顺序,可以使用随机生成的下标与遍历到的下面进行交换。最后返回该数组就完成任务了。

    public static int[] randomArray(int maxKinds, int range, int k, int m) {
        //随机一个设置出现k次的数
        int ktimeNum = rangeNumber(range);
        //至少是两种数
        int numKinds = (int)(Math.random()*maxKinds)+2;
        //数组长度知道了
        int[] arr = new int[k+(numKinds-1)*m];
        int index = 0;
        for (;index<k;index++) {
            arr[index]=ktimeNum;
        }
        numKinds--;
        Set<Integer> set = new HashSet<>();
        set.add(ktimeNum);
        while (numKinds!=0) {
            int curNum = 0;
            do {
                curNum = rangeNumber(range);
            }while (set.contains(curNum));
            set.add(curNum);
            numKinds--;
            for(int i=0;i<m;i++) {
                arr[index++]=curNum;
            }
        }
        //arr已经填好了,但是是有顺序的,下面打乱顺序
        for(int i=0;i<arr.length;i++) {
            int j = (int)(Math.random()*arr.length);
            int tmp = arr[i];
            arr[i]=arr[j];
            arr[j]=tmp;
        }
        return arr;
    }

    //[-range,range] ,求随机数
    public static int rangeNumber(int range) {
        return ((int)(Math.random()*range)+1) - ((int)(Math.random()*range)+1);
    }

    public static void main(String[] args) {
        int kinds  = 10; //数的种数
        int range = 200; //数的范围
        int testTime = 100000; //测试的次数
        int max = 9;//设置数的大小
        System.out.println("测试开始");
        for (int i = 0; i < testTime; i++) {
            int a = (int)(Math.random()*max)+1; //a 1~9
            int b = (int)(Math.random()*max)+1;
            int k = Math.min(a,b);
            int m = Math.max(a,b);
            //但有可能随机的数相同,不符合题目要求(k<m)
            if(k==m) {
                m++;
            }
            int[] arr = randomArray(kinds,range,k,m);
            int ans1 = test(arr,k,m);
            int ans2 = FindInitNum(arr,k,m);
            if(ans1!=ans2) {
                System.out.println(ans1);
                System.out.println(ans2);
                System.out.println("测试错误");
            }
        }
        System.out.println("测试结束");
    }
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-05 23:40:24  更:2022-07-05 23:41:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:13:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码