【问题标题】:Is there a way to iterate over order?有没有办法迭代订单?
【发布时间】:2017-05-11 03:41:58
【问题描述】:

如何遍历执行顺序?

我正在开发一个软件,它有几个步骤来计算一些数据,我正在考虑可能会务实地改变这些步骤的顺序,以便我可以检查一些数据的最佳顺序。

让我举例说明:我假设 3 个步骤(实际上更多):

stepA(data);
stepB(data);
stepC(data);

我想要一个装置,让我能够思考这些步骤的每一个排列,然后检查结果。类似的东西:

data = originalData; i=0;
while (someMagic(&data,[stepA,stepB,stepC],i++)){
   checkResults(data);
   data = originalData;
}

然后 someMagic 在 i==0 上执行 A,B 然后 C。 A,C 然后 B 在 i == 1 上。 B、A 然后 C 在 i==2 上等等。

【问题讨论】:

  • 这是一个关于如何编写置换函数的问题吗?

标签: c syntax logic


【解决方案1】:

您可以使用函数指针,可能类似于以下内容:

typedef void (*func)(void *data);

int someMagic(void *data, func *func_list, int i) {
    switch (i) {
    case 0:
        func_list[0](data);
        func_list[1](data);
        func_list[2](data);
        break;
    case 1:
        func_list[0](data);
        func_list[2](data);
        func_list[1](data);
        break;
    case 2:
        func_list[1](data);
        func_list[0](data);
        func_list[2](data);
        break;
    default: return 0;
    }
    return 1;
}

func steps[3] = {
    stepA,
    stepB,
    stepC
}

while (someMagic(&data, steps, i++)) {
    ....
}

【讨论】:

  • 这只会按顺序执行它们,我需要一些排列/交换和多次执行
  • 当然可以交换,只要在函数列表中设置实际函数即可。例如,step[1] = stepC;步骤 [2] = 步骤 B;将交换 B 和 C。
  • @emiliopedrollo 嘿,我已经编辑了我的帖子,现在可以了吗
  • 它适用于只有 3 个功能的情况,但不能很好地扩展。我的实际代码有 7 个函数。
  • 为什么会这样?为什么不置换steps 数组,然后简单地按(置换)顺序执行这些步骤?因此,您有一个简单的 for 循环来执行这些步骤,而不是随着步骤数量的增加,在快速增长的 switch 语句中写出所有排列。
【解决方案2】:

关键是要找到一种方法来迭代[0, n[整数区间的permutations集合。

排列(在数学意义上)可以看作是[0, n[ 到自身的双射,并且可以用这个排列的图像来表示,应用于[0, n[

例如,考虑[0, 3[的排列:

  0 -> 1
  1 -> 2
  2 -> 0

它可以看作是元组(1, 2, 0),在C语言中,它自然地转换为整数数组permutation = (int []){1, 2, 0};

假设您有一个函数指针数组steps,那么对于每个排列,您将需要为[0, n[i 的每个值调用steps[permutation[i]]

下面的代码实现了这个算法:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

static void stepA(int data) { printf("%d: %s\n", data, __func__); }
static void stepB(int data) { printf("%d: %s\n", data, __func__); }
static void stepC(int data) { printf("%d: %s\n", data, __func__); }
static void (* const steps[])(int) = {stepA, stepB, stepC,};
static int fact(int n) { return n == 0 ? 1 : fact(n - 1) * n; }

static int compare_int(const void *pa, const void *pb)
{
    return *(const int *)pa - *(const int *)pb;
}

static void get_next_permutation(int tab[], size_t n)
{
    int tmp;
    unsigned i;
    unsigned j;
    unsigned k;

    /* to find the next permutation in the lexicographic order
     *   source: question 4 (in french, sorry ^^) of
     *   https://liris.cnrs.fr/~aparreau/Teaching/INF233/TP2-permutation.pdf
.    */
    /* 1. find the biggest index i for which tab[i] < tab[i+1] */
    for (k = 0; k < n - 1; k++)
        if (tab[k] < tab[k + 1])
            i = k;

    /* 2. Find the index j of the smallest element, bigger than tab[i],
     *   located after i */
    j = i + 1;
    for (k = i + 1; k < n; k++)
        if (tab[k] > tab[i] && tab[k] < tab[j])
            j = k;

    /* 3. Swap the elements of index i and j */
    tmp = tab[i];
    tab[i] = tab[j];
    tab[j] = tmp;

    /* 4. Sort the array in ascending order, after index i */
    qsort(tab + i + 1, n - (i + 1), sizeof(*tab), compare_int);
}

int main(void)
{
    int n = sizeof(steps) / sizeof(*steps);
    int j;
    int i;
    int permutation[n];
    int f = fact(n);

    /* first permutation is identity */
    for (i = 0; i < n; i++)
        permutation[i] = i;

    for (j = 0; j < f; j++) {
        for (i = 0; i < n; i++)
            steps[permutation[i]](i);
        if (j != f - 1)
            get_next_permutation(permutation, n);
    }

    return EXIT_SUCCESS;
}

main 中的外层循环,由j 索引,遍历所有n! 排列,而由i 索引的内层循环遍历n 步骤。

get_next_permutation 修改了 permutation 数组,以获得字典顺序中的下一个排列。

请注意,当输入中的排列是最后一个 (n - 1, ..., 1, 0) 时,它不起作用,因此是 if (j != f - 1) 测试。 可以增强它以检测这种情况(我没有设置)并将第一个排列 (0, 1, ..., n - 1) 放入 permutation 数组中。

代码可以编译为:

    gcc main.c -o main -Wall -Wextra -Werror -O0 -g3

我强烈建议使用valgrind 作为一种检测非一个错误的方法。

编辑:我刚刚意识到我没有准确回答 OP 的问题。 someMagic() 函数将允许直接访问第 i 个排列,而我的算法只允许按字典顺序计算后继。但如果目标是迭代所有排列,它会正常工作。否则,也许像this one 这样的答案应该符合要求。

【讨论】:

  • 我喜欢你的回答,但今天早上我带来了更好的东西,而且更简单。我会在几个小时后将其发布在这里作为回复。
【解决方案3】:

我找到了一个足够简单的解决方案:

void stepA(STRUCT_NAME *data);
void stepB(STRUCT_NAME *data);
void stepC(STRUCT_NAME *data);

typedef void (*check)(STRUCT_NAME *data);

void swap(check *x, check *y) {    
    check temp;

    temp = *x;
    *x = *y;
    *y = temp;    
}

void permute(check *a, int l, int r,STRUCT_NAME *data) {    
    int i, j = 0, score;
    HAND_T *copy, *copy2, *best_order = NULL;

    if (l == r) {
        j = 0;
        while (j <= r) a[j++](data);
    } else {
        for (i = l; i <= r; i++) {
            swap((a + l), (a + i));
            permute(a, l + 1, r, data);
            swap((a + l), (a + i));
        }
    }    
} 

check checks[3] = {
    stepA,
    stepB,
    stepC,
};

int main(void){
    ...
    permute(checks,0,2,data)
}

【讨论】:

    猜你喜欢
    • 2016-09-23
    • 2020-02-24
    • 2014-03-23
    • 2021-09-13
    • 1970-01-01
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多