程序对拍

有些时候,我们不知道写出的程序是否正确,或者明确地知道有错误,但不清楚问题在哪里,手工试了多组测试数据都没问题,这时可以考虑对拍。

对拍有三个要素:待验证程序、参考程序和随机数据生成器。

参考程序可以是通过暴力方法求解代码或者别人的正确代码,而随机数生成器则需根据实际要求定制,但有些基础函数还是可以复用的。

生成随机数必须先初始化种子:

#include <sys/time.h>
#include <stdlib.h>
void init() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    srand(tv.tv_usec);
}

生成一个范围在[lo, hi]内的随机正整数:

int randn(int lo, int hi) {
    return lo + rand() % (hi - lo + 1);
}

生成n(nlo<=n<=nhi)个范围在[lo, hi]内的随机数:

void nrandn(int nlo, int nhi, int lo, int hi) {
    int i, n = randn(nlo, nhi);
    printf("%d\n", n);
    for (i = 1; i <= n; i++)
        printf("%d%c", randn(lo, hi), i == n ? '\n' : ' ');
}

随机打乱顺序:

void shuffle(int a[], int n) {
    int i, j, k;
    for (i = 0; i < n; i++) {
        j = i + rand() % (n - i);
        k = a[i]; a[i] = a[j]; a[j] = k;
    }
}

生成lo~hi的一个排列:

void permutation(int lo, int hi) {
    int i, *a = malloc(sizeof(int) * (hi - lo + 1));
    for (i = lo; i <= hi; i++)
        a[i-lo] = i;
    shuffle(a, hi - lo + 1);
    for (i = lo; i <= hi; i++)
        printf("%d%c", a[i-lo], i == hi ? '\n' : ' ');
    free(a);
}

随机生成字符串:

void randstr(char *str, int llo, int lhi) {
    int llen = randn(llo, lhi), slen = strlen(str);
    while (llen--) {
        int x = rand() % slen;
        putchar(str[x]);
    }
}

随机生成一棵树:

void randtree(int n) {
    int *a = malloc(sizeof(int) * n);
    int *p = malloc(sizeof(int) * n);
    int i, pn = 0, q;
    printf("%d\n", n);
    for (i = 0; i < n; i++) a[i] = i + 1;
    shuffle(a, n);
    p[pn++] = a[0];
    for (i = 1; i < n; i++) {
        q = rand() % pn;
        printf("%d %d\n", p[q], a[i]);
        p[pn++] = a[i];
    }
    free(a); free(p);
}

假设待验证程序为x,参考程序为b,随机数生成器为gen,可循环调用比较输出是否一致,直到找出输出不一样的输入数据为止。

#!/bin/bash
idx=1
while true; do
    echo "Case $idx:"
    ./gen >data
    ./x <data >x.out
    ./b <data >b.out
    diff x.out b.out &>/dev/null
    if [ $? -ne 0 ]; then
        cat data
        echo "Your Answer:"
        cat x.out
        echo "Expect Answer:"
        cat b.out
        break
    fi
    let idx++
done
Table of Contents