网站首页 > 资源文章 正文
以下是用C语言实现数组全排列的回溯算法代码:
全排列生成算法实现
#include <stdio.h>
#include <stdlib.h>
// 交换两个整数的值
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 深拷贝当前排列到结果集
void savePermutation(int* nums, int numsSize, int** result, int* returnSize) {
result[*returnSize] = (int*)malloc(numsSize * sizeof(int));
for (int i = 0; i < numsSize; i++) {
result[*returnSize][i] = nums[i];
}
(*returnSize)++;
}
// 回溯核心函数
void backtrack(int* nums, int numsSize, int start, int** result, int* returnSize) {
if (start == numsSize) { // 终止条件:生成完整排列
savePermutation(nums, numsSize, result, returnSize);
return;
}
for (int i = start; i < numsSize; i++) {
swap(&nums[start], &nums[i]); // 做选择:交换元素
backtrack(nums, numsSize, start + 1, result, returnSize); // 递归下一层
swap(&nums[start], &nums[i]); // 撤销选择:恢复状态
}
}
// 主接口函数
int** permute(int* nums, int numsSize, int* returnSize) {
// 计算排列总数 n!
*returnSize = 1;
for (int i = 1; i <= numsSize; i++) {
*returnSize *= i;
}
// 分配结果内存
int** result = (int**)malloc((*returnSize) * sizeof(int*));
// 执行回溯算法
*returnSize = 0; // 重置为实际计数
backtrack(nums, numsSize, 0, result, returnSize);
return result;
}
// 打印结果
void printResult(int** result, int size, int numsSize) {
for (int i = 0; i < size; i++) {
printf("[");
for (int j = 0; j < numsSize; j++) {
printf("%d%s", result[i][j], (j < numsSize-1) ? ", " : "");
}
printf("]\n");
}
}
// 示例使用
int main() {
int nums[] = {1, 2, 3};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int returnSize;
int** permutations = permute(nums, numsSize, &returnSize);
printf("输入数组: [1, 2, 3]\n");
printf("全排列结果(%d种):\n", returnSize);
printResult(permutations, returnSize, numsSize);
// 释放内存
for (int i = 0; i < returnSize; i++) {
free(permutations[i]);
}
free(permutations);
return 0;
}
代码详细解析
1. 核心数据结构
int** result; // 二维数组存储所有排列
- result 是指针数组,每个元素指向一个排列(一维数组)
- 内存布局示例(输入[1,2,3]):
result[0] → [1,2,3]
result[1] → [1,3,2]
result[2] → [2,1,3]
...
2. 关键函数解析
swap() 函数
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
- 作用:交换两个整数的值
- 必要性:通过交换元素位置生成不同排列
savePermutation() 函数
void savePermutation(int* nums, int numsSize, int** result, int* returnSize) {
result[*returnSize] = (int*)malloc(numsSize * sizeof(int));
for (int i = 0; i < numsSize; i++) {
result[*returnSize][i] = nums[i];
}
(*returnSize)++;
}
- 深拷贝:将当前排列状态复制到结果集
- 内存管理:为每个排列单独分配内存
- 索引控制:通过returnSize参数跟踪存储位置
backtrack() 函数
void backtrack(int* nums, int numsSize, int start, int** result, int* returnSize) {
if (start == numsSize) { // 终止条件
savePermutation(nums, numsSize, result, returnSize);
return;
}
for (int i = start; i < numsSize; i++) {
swap(&nums[start], &nums[i]); // 做选择
backtrack(nums, numsSize, start + 1, result, returnSize); // 递归
swap(&nums[start], &nums[i]); // 撤销选择
}
}
- 递归过程:
- 终止条件:当start == numsSize时,说明已处理完所有元素
- 循环遍历:从当前位置start开始,依次与后续元素交换
- 状态修改:通过交换生成新的排列
- 递归深入:处理下一个位置(start+1)
- 状态恢复:撤销交换以尝试其他可能性
permute() 函数
int** permute(int* nums, int numsSize, int* returnSize) {
// 计算排列总数 n!
*returnSize = 1;
for (int i = 1; i <= numsSize; i++) {
*returnSize *= i;
}
// 分配结果内存
int** result = (int**)malloc((*returnSize) * sizeof(int*));
// 执行回溯算法
*returnSize = 0; // 重置为实际计数
backtrack(nums, numsSize, 0, result, returnSize);
return result;
}
- 内存预分配:根据n!预先分配结果数组空间
- 双重角色:returnSize既用于返回结果数量,也用于控制存储位置
3. 算法执行流程
以输入数组[1,2,3]为例:
1. 初始调用 backtrack(0)
2. 第一层循环(start=0)
- i=0: 交换位置0与0(无变化)
→ 递归进入 backtrack(1)
→ 第二层循环(start=1)
- i=1: 交换位置1与1
→ 递归进入 backtrack(2)
→ 第三层循环(start=2)
- i=2: 交换位置2与2
→ 触发终止条件,保存[1,2,3]
- i=2: 交换位置1与2 → [1,3,2]
→ 递归处理生成排列
- i=1: 交换位置0与1 → [2,1,3]
→ 递归处理生成排列
- i=2: 交换位置0与2 → [3,2,1]
→ 递归处理生成排列
4. 复杂度分析
- 时间复杂度:O(n*n!)
- 生成n!种排列
- 每次保存排列需要O(n)时间
- 空间复杂度:O(n!)
- 存储所有排列需要n!×n的空间
- 递归栈深度为O(n)
5. 关键优化点
- 原地交换:直接修改原数组,避免额外空间
- 即时保存:只在完整排列时进行深拷贝
- 预分配内存:提前计算所需空间,避免动态扩容
6. 内存管理示意图
permutations → [ ptr1, ptr2, ptr3, ... ]
↗ ↗ ↗
[1,2,3] [1,3,2] [2,1,3] ...
扩展改进方向
- 处理重复元素:添加跳过重复值的判断
if (i > start && nums[i] == nums[start]) continue;
- 迭代实现:用栈模拟递归,避免栈溢出
- 分块存储:对于大规模数据,使用分批生成和存储
通过这个实现,可以清晰看到回溯算法在排列生成中的应用,以及C语言中动态内存管理的具体实践。
猜你喜欢
- 2025-05-09 China-EU 50 years: Advancing stability and prosperity through partnership
- 2025-05-09 资深黑客教小白如何攻破一个网站!超级详细的教学教程!太牛逼了
- 2025-05-09 Guest Q&A|AL-FAGEEH: Driving Collaboration for SDGs
- 2025-05-09 Penumbear 荧光小熊第7关backtrack攻略 黑箱乃至好垫脚
- 2025-05-09 渗透测试系统Kali推出Docker镜像(kali linux渗透测试的艺术)
- 2025-05-09 China opposes forced displacement of people in Gaza: spokesperson
- 2025-05-09 Opportune moment to set the stage for negotiations to end Ukraine crisis
- 2025-05-09 Welcome signs neighbors looking to build trust
- 2025-05-09 ikon专辑《WELCOME BACK》歌单公开
- 2025-05-09 顶配16999!三星折叠屏新品全球发布,多款穿戴设备新品同时亮相
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 电脑显示器花屏 (79)
- 403 forbidden (65)
- linux怎么查看系统版本 (54)
- 补码运算 (63)
- 缓存服务器 (61)
- 定时重启 (59)
- plsql developer (73)
- 对话框打开时命令无法执行 (61)
- excel数据透视表 (72)
- oracle认证 (56)
- 网页不能复制 (84)
- photoshop外挂滤镜 (58)
- 网页无法复制粘贴 (55)
- vmware workstation 7 1 3 (78)
- jdk 64位下载 (65)
- phpstudy 2013 (66)
- 卡通形象生成 (55)
- psd模板免费下载 (67)
- shift (58)
- localhost打不开 (58)
- 检测代理服务器设置 (55)
- frequency (66)
- indesign教程 (55)
- 运行命令大全 (61)
- ping exe (64)
本文暂时没有评论,来添加一个吧(●'◡'●)