C语言高级进阶 - 字符串的全排列

本文介绍了如何使用C语言生成已排序字符数组的所有排列。通过递归和迭代两种方法实现,详细展示了代码实现过程,包括避免重复排列的处理。

输入一个已经升序的字符数组,打印出该字符串数组中字符串的所有排列。例如:

input: ab cd

output:  ab cd

             cd  ab         

其实这个问题等同于例如输入字符串abc,则输出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba

解决这类问题最简单的方法就是采用递归函数:

如果能生成n-1个元素的全排列,就能生成n个元素的全排列。对于只有一个元素的集合,可以直接生成全排列。所以全排列的递归终止条件很明确,只有一个元素时。 基本的代码实现的框架如下所示:

void permute(char *a,int i,int n)

{

        int j;

        if (i == n)

                printf("%s\n",a);

        else

        {

                for (j = i; j <= n; j++)

                {

                        if(a[i] == a[j] && j != i) //为避免生成重复排列,当不同位置的字符相同时不再交换

                               continue;

                        swap((a+i),(a+j));

                        permute(a,i+1,n);

                        swap((a+i),(a+j)); //backtrack

                }

}

同时我们也可以采用迭代的方法来考虑这个问题。参考C++ 的 STL 库中自带了 next_permutation 来实现C语言的next_permutation:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

static int times = 0;

int next_permutation(int n, char **s)

{

    /**

    * Complete this method

    * Return 0 when there is no next permutation and 1 otherwise

    * Modify array s to its next permutation

    */

    int head_item =0;

    int item =0;

    int size = n;

    char *tmp = NULL;

    // find the sub completed list

    for (item = size - 1; item > 0; item--) {

        if (strcmp(s[item-1], s[item])<0)

        {

            break;

        }

    }

    if (item == 0) {

        // finished

        return 0;

    } else {

        head_item = item - 1;

    }

    // find the next item:

    // The first great than head_item

    for (item = size - 1; item > head_item; item--) {

        if (strcmp(s[head_item], s[item]) <0) {

            break;

        }

    }

    tmp = s[head_item];

    s[head_item] = s[item];

    s[item] = tmp;

    

    // reverse the sub list

    for (item = head_item + 1; item < size; item++, size--) {

        tmp = s[item];

        s[item] = s[size-1];

        s[size-1]= tmp;        

    }

    return 1;

}

int main()

{

    char **s;

    int n;

    scanf("%d", &n);

    s = calloc(n, sizeof(char*));

    for (int i = 0; i < n; i++)

    {

        s[i] = calloc(11sizeof(char));

        scanf("%s", s[i]);

    }

    do

    {

        for (int i = 0; i < n; i++)

            printf("%s%c", s[i], i == n - 1 ? '\n' : ' ');

    } while (next_permutation(n, s));

    for (int i = 0; i < n; i++)

        free(s[i]);

    free(s);

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值