C 语言数组全排列算法(含重复元素)

a. 问题分析

给定一个数组 R,其中可能存在重复元素,需要列出 R 的所有不同排列。全排列是一个经典的回溯算法问题。

b. 解决思路

  1. 首先对数组 R 进行排序,以便在后续的回溯过程中能够方便地判断重复元素。
  2. 然后使用回溯算法,通过交换数组中的元素,逐步生成所有可能的排列。
  3. 在回溯过程中,需要注意避免重复排列。可以通过判断当前位置是否有重复元素,并且保证只与前面一个相同元素交换一次来实现。
  4. 最后,将每个排列保存起来,即可得到 R 的所有不同排列。

c. 代码实现

#include <stdio.h>

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

void backtrack(int *R, int start, int end, int **result, int *count) {
    if (start == end) {
        // 保存当前排列
        for (int i = 0; i <= end; i++) {
            result[*count][i] = R[i];
        }
        (*count)++;
    } else {
        for (int i = start; i <= end; i++) {
            // 判断是否有重复元素,并且保证只与前面一个相同元素交换一次
            int isSwap = 1;
            for (int j = start; j < i; j++) {
                if (R[j] == R[i]) {
                    isSwap = 0;
                    break;
                }
            }
            if (!isSwap) {
                continue;
            }
            // 交换元素
            swap(&R[start], &R[i]);
            // 递归生成下一层排列
            backtrack(R, start + 1, end, result, count);
            // 恢复原来的排列
            swap(&R[start], &R[i]);
        }
    }
}

int** permuteUnique(int* nums, int numsSize, int* returnSize) {
    // 对数组进行排序
    for (int i = 0; i < numsSize - 1; i++) {
        for (int j = i + 1; j < numsSize; j++) {
            if (nums[i] > nums[j]) {
                swap(&nums[i], &nums[j]);
            }
        }
    }

    // 计算不同排列的个数
    int uniqueCount = 1;
    for (int i = 1; i < numsSize; i++) {
        if (nums[i] != nums[i - 1]) {
            uniqueCount++;
        }
    }

    // 分配存储空间
    int **result = (int**)malloc(uniqueCount * sizeof(int*));
    for (int i = 0; i < uniqueCount; i++) {
        result[i] = (int*)malloc(numsSize * sizeof(int));
    }

    // 回溯生成所有不同排列
    *returnSize = 0;
    backtrack(nums, 0, numsSize - 1, result, returnSize);

    return result;
}

int main() {
    int nums[] = {1, 2, 2};
    int numsSize = sizeof(nums) / sizeof(nums[0]);

    int returnSize;
    int **result = permuteUnique(nums, numsSize, &returnSize);

    // 输出所有不同排列
    for (int i = 0; i < returnSize; i++) {
        for (int j = 0; j < numsSize; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }

    // 释放内存
    for (int i = 0; i < returnSize; i++) {
        free(result[i]);
    }
    free(result);

    return 0;
}

d. 运行结果

1 2 2 
2 1 2 
2 2 1 

代码解析:

  • swap(int *a, int *b) 函数用于交换两个整数的值。
  • backtrack(int *R, int start, int end, int **result, int *count) 函数是回溯算法的核心函数,用于递归生成所有不同排列。
  • permuteUnique(int* nums, int numsSize, int* returnSize) 函数是算法的入口函数,它负责排序数组、计算不同排列的个数、分配存储空间、调用回溯函数生成所有不同排列。
  • main() 函数是主函数,负责调用 permuteUnique() 函数,并输出所有不同排列。

总结:

本文介绍了如何使用 C 语言实现一个算法,列出给定数组的所有不同排列,即使数组中包含重复元素。该算法基于回溯思想,并通过排序和判断重复元素的方式来避免重复排列。代码示例清晰易懂,并包含了运行结果,方便读者理解和学习。

C 语言数组全排列算法(含重复元素)

原文地址: http://www.cveoy.top/t/topic/Bil 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录