堆的算法在重复C++?

Heap's algorithm in C++ repeating?

本文关键字:C++ 算法      更新时间:2023-10-16

我正在尝试在c++中实现堆的算法。
然而,如果要置换的字符串长度达到4,算法就会开始重复。下面是代码:

void permute(int n, string str, int *total,string array[]){
    if (n==0){
        
        array[*total] = str;
        *total += 1;
    
    }
    else{
    
        for(int c=0; c<=n;c++){
            
            permute(n-1,str,total, array);
            if (n % 2 == 0){
                char tmpstr=str[c];
                str[c]=str[n];
                str[n]=tmpstr; 
                }
            else{
                char tmpstr=str[0];
                str[0]=str[n];
                str[n]=tmpstr;
            }
        }
    }
}
int main() {
    int total = 0;
    string array[24];
    permute(3,"abcd",&total, array);
    cout << total << endl;
    return 0;
}

这是输出。在第13行

处重复
24
abcd
bacd
cbad
bcad
cabd
acbd
dbca
bdca
cbda
bcda
cdba
dcba
abcd <-- right here
bacd
cbad
bcad
cabd
acbd
dbca
bdca
cbda
bcda
cdba
dcba

谢谢大家,欢迎任何帮助!

虽然使用PaulMcKenzie推荐的标准函数总是一个很好的主意,但您已经发布了一个关于为什么它不起作用的问题的代码。

在for循环中,去掉if (n%2 ==0)行及其else部分:

  for(int c=0; c<=n;c++){
        permute(n-1,str,total, array);
        char tmpstr=str[c];
        str[c]=str[n];
        str[n]=tmpstr; 
        }

它应该工作。

看起来您正在尝试实现wikipedia中所述的堆置换生成算法的递归版本,并且最初在这里给出。如果你想保持接近它(例如,在生成排列时具有相同的顺序),你所要做的就是传递str参数作为引用(你必须改变调用permute()函数的行,以传递一个可变字符串而不是字符串常量),并保留If -那么else子句原来在你的程序中。

然而,@Christophe给出的版本很有趣。我已经尝试了n=6(7个元素的排列),并且仍然给出了所有的排列。如果能证明这对任何自然数都成立,那就很有趣了。然而,这一点可能是没有意义的,因为我引用的两个参考文献中给出的递归版本也没有实现Heap给出的原始版本,而且据我所知,也没有被证明可以给出所有排列。Heap在1963年编写的原始版本甚至没有使用结构化编程。给出了用goto实现的流程图。

这里是我的递归和迭代版本的实现:

//recursive
int perm_num = 0;
void heappermute(int v[], int n) {
    int i;
    if (n == 1) {
        //print(v);
        ++perm_num;
    }
    else {
        for (i = 0; i < n; i++) {
            heappermute(v, n - 1);
            if (n % 2 == 1) {
                swap(&v[0], &v[n - 1]);
            }
            else {
                swap(&v[i], &v[n - 1]);
            }
        }
    }
}
int perm_num_iter = 0;
void heappermuteiterative(int v[], int n) {
    int c[30];
    for (int i = 0; i <= n; ++i) {
        c[i] = 0;
    }
    ++perm_num_iter;
    //print(v);
    int i = 1;
    while (i < n) {
        if (c[i] < i) {
            if (i % 2 == 0) {
                swap(&v[0], &v[i]); // or i-1
            }
            else {
                swap(&v[c[i]], &v[i]); // or i-1
            }
            ++perm_num_iter;
            //print(v);
            ++c[i];
            i = 1;
        }
        else {
            c[i] = 0;
            ++i;
        }
    }
}

我从网上抄了递归的那个,迭代的那个是维基百科用c写的。