问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

C语言实现1-n全排列的四种算法详解

创作时间:
作者:
@小白创作中心

C语言实现1-n全排列的四种算法详解

引用
1
来源
1.
https://docs.pingcode.com/baike/1206705

C语言实现1-n全排列是算法学习中的一个重要课题,本文将详细介绍递归算法、字典序算法、交换法和动态规划四种实现方法。每种方法都有其独特的思路和应用场景,通过本文的学习,你将能够掌握全排列问题的多种解法。

一、递归算法简介

递归算法是通过函数自身调用自身,以逐步解决问题的方法。在全排列问题中,递归算法的核心思想是将问题分解成更小的子问题,逐步求解。具体步骤如下:

  1. 固定第一个数字,递归求解剩余数字的全排列。
  2. 交换第一个数字与剩余数字,继续递归求解。
  3. 回溯,恢复原始数组,继续下一轮交换。

二、递归算法实现细节

递归算法的实现需要处理以下几个方面:

  1. 递归结束条件:当剩余数字只有一个时,直接输出当前排列。
  2. 递归调用:固定一个数字,对剩余数字继续递归求解。
  3. 数组交换:交换当前数字与剩余数字,继续递归求解。

代码示例

#include <stdio.h>

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

void permute(int *arr, int start, int end) {
    if (start == end) {
        for (int i = 0; i <= end; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    } else {
        for (int i = start; i <= end; i++) {
            swap(&arr[start], &arr[i]);
            permute(arr, start + 1, end);
            swap(&arr[start], &arr[i]); // 回溯
        }
    }
}

int main() {
    int n;
    printf("Enter the value of n: ");
    scanf("%d", &n);
    int arr[n];
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }
    permute(arr, 0, n - 1);
    return 0;
}

三、字典序算法

字典序算法是一种基于字典顺序生成全排列的方法。其基本思想是从当前排列生成字典序的下一个排列,直到所有排列生成完毕。具体步骤如下:

  1. 从右向左找到第一个顺序对,即arr[i] < arr[i+1]。
  2. 从右向左找到第一个大于arr[i]的数字arr[j]。
  3. 交换arr[i]和arr[j]。
  4. 反转arr[i+1]到arr[n-1]的部分。

代码示例

#include <stdio.h>
#include <stdbool.h>

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

void reverse(int *arr, int start, int end) {
    while (start < end) {
        swap(&arr[start], &arr[end]);
        start++;
        end--;
    }
}

bool next_permutation(int *arr, int n) {
    int i = n - 2;
    while (i >= 0 && arr[i] >= arr[i + 1]) {
        i--;
    }
    if (i < 0) {
        return false;
    }
    int j = n - 1;
    while (arr[j] <= arr[i]) {
        j--;
    }
    swap(&arr[i], &arr[j]);
    reverse(arr, i + 1, n - 1);
    return true;
}

int main() {
    int n;
    printf("Enter the value of n: ");
    scanf("%d", &n);
    int arr[n];
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }
    do {
        for (int i = 0; i < n; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    } while (next_permutation(arr, n));
    return 0;
}

四、交换法

交换法是通过交换数组中的元素来生成全排列的方法。其基本思想是通过交换当前元素与其他元素,生成新的排列。具体步骤如下:

  1. 固定第一个元素,递归求解剩余元素的全排列。
  2. 交换当前元素与其他元素,继续递归求解。
  3. 回溯,恢复原始数组,继续下一轮交换。

代码示例

#include <stdio.h>

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

void permute(int *arr, int start, int end) {
    if (start == end) {
        for (int i = 0; i <= end; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    } else {
        for (int i = start; i <= end; i++) {
            swap(&arr[start], &arr[i]);
            permute(arr, start + 1, end);
            swap(&arr[start], &arr[i]); // 回溯
        }
    }
}

int main() {
    int n;
    printf("Enter the value of n: ");
    scanf("%d", &n);
    int arr[n];
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }
    permute(arr, 0, n - 1);
    return 0;
}

五、动态规划

动态规划是一种通过将问题分解成子问题,逐步求解的方法。在全排列问题中,动态规划可以通过记录之前的排列,逐步生成新的排列。具体步骤如下:

  1. 初始化一个数组,保存初始排列。
  2. 逐步生成新的排列,保存到数组中。
  3. 输出所有排列。

代码示例

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

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

void permute(int *arr, int start, int end, int **result, int *count) {
    if (start == end) {
        for (int i = 0; i <= end; i++) {
            result[*count][i] = arr[i];
        }
        (*count)++;
    } else {
        for (int i = start; i <= end; i++) {
            swap(&arr[start], &arr[i]);
            permute(arr, start + 1, end, result, count);
            swap(&arr[start], &arr[i]); // 回溯
        }
    }
}

int main() {
    int n;
    printf("Enter the value of n: ");
    scanf("%d", &n);
    int arr[n];
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }
    int factorial = 1;
    for (int i = 2; i <= n; i++) {
        factorial *= i;
    }
    int **result = (int **)malloc(factorial * sizeof(int *));
    for (int i = 0; i < factorial; i++) {
        result[i] = (int *)malloc(n * sizeof(int));
    }
    int count = 0;
    permute(arr, 0, n - 1, result, &count);
    for (int i = 0; i < factorial; i++) {
        for (int j = 0; j < n; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }
    for (int i = 0; i < factorial; i++) {
        free(result[i]);
    }
    free(result);
    return 0;
}

六、总结

递归算法、字典序算法、交换法和动态规划都是实现1-n全排列的有效方法。递归算法通过逐步固定每个元素,递归求解剩余元素的排列,简单易懂。字典序算法通过逐步生成字典序的下一个排列,效率较高。交换法通过交换当前元素与其他元素,生成新的排列。动态规划通过记录之前的排列,逐步生成新的排列。每种方法都有其优缺点,选择合适的方法可以提高问题的解决效率。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号