当前位置: 首页 > news >正文

C语言实现全排列(非递归法)(以猪八戒买包子的故事为例解释)

文章目录

  • 前言
  • 1、用数学原理手动实现求全排列的第K个状态
  • 2、C++调包验证上述手动算的对不对
  • 3、用C语言实现上述求全排列第k步过程(以猪八戒买包子为例解释)
  • 4、C语言实现一个数的全排列
  • 5、与递归法实现全排列对比(deepseek分析)
  • 6、结语

前言

实现一个数的全排列在编程和数学中是很常见的事儿,如果是实际项目,往往调用C++中算法包更方便快捷(#include导入algorithm包、next_permutation、prev_permutation等)。但是作为学习者,最好还是可以不调包实现自己的全排列。常见的方法是使用递归法,但是对于递归掌握的不是很好的情况下,递归法还是不太好理解。本位介绍一种非递归法,使用数学原理的方法实现一个数字的全排列。

1、用数学原理手动实现求全排列的第K个状态

在这里插入图片描述
在这里插入图片描述
计算序列第100个状态:
在这里插入图片描述
计算序列第94个状态:
在这里插入图片描述
计算序列第100万个状态:
在这里插入图片描述

2、C++调包验证上述手动算的对不对

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、用C语言实现上述求全排列第k步过程(以猪八戒买包子为例解释)

在这里插入图片描述
下面的程序实现跟草稿纸上手动去计算的思路不完全一样,主要是从第0位开始,每次确定这一位上应该放几。就是看这个数在这个位置上能拿下几个这个位置上对应的阶乘数,能拿下几步当前这个位置上就放几步后位置上的数(前提是走到几步的位置上是有效的,这里程序实现没有去跟草稿纸上把剩下的数在后面升序排列,但是利用了基排序的思想,看在有效位置走到了哪里(这就是八戒走到位之后把那一位的店铺炸掉的原因))
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>#define N 10 // 有几个位置 八戒有几条命以及有几个包子店int fac[N];   // fac[i] = (N-1-i)!,即 fac[0]=9!, fac[1]=8!, ..., fac[9]=0! 表示每一世包子的价格
int valid[N]; // valid[i] = 1 表示数字 i 可用 表示包子店是否有效void init() {fac[N - 1] = 1;  // 0! = 1valid[N - 1] = 1;  // 数字 9 可用for (int i = N - 2; i >= 0; i--) {fac[i] = fac[i + 1] * (N - 1 - i);  // 递推 (N-1-i)! 代表每一世包子的价格valid[i] = 1; // 数字 i 可用 表示包子店初始的时候都是有效的}
}// 获取从左往右第 i 位上的数字(i 从 0 开始) 八戒每一世可以走到底几个店铺
int get(int i, int *k) { // 猪八戒这一世手里拿着k元钱 能走到第几个店铺 每一世包子价格不一样int step = *k / fac[i];  // 猪八戒这一世可以买几个包子 这一世包子的价格就是这个位置上阶乘数int j = 0; // 每世都从第一个包子店往后走 但是只有有效的包子店铺才会消耗八戒手里的包子while (step >= 0) { // 包子的数量可以是0的 八戒手里没有包子的话 还可以往前走 遇到有效店铺还让他消耗包子的话八戒会拿炸弹和店铺同归于尽step -= valid[j];   // 但是只有有效的包子店才能让八戒消耗包子 每走到一个有效店铺用掉一个包子 没有包子还让八戒消耗包子就准备同归于尽if (step < 0) break; // 让八戒包子是负数了就是触发八戒拿炸弹同归于尽的信号 手里没有包子了 你还让八戒消耗一个j++; // 往下一个店铺走 但是下一个店铺是否有效 不一定}valid[j] = 0;  // 八戒用炸弹和店铺同归于尽了 店铺就失效了*k %= fac[i]; // 八戒下一条命手里有多少钱return j;      // 返回八戒炸掉的那个店铺位置
}int main() {init();int k = 100;k -= 1; // 求第k个状态 那就是已经走了(k - 1)步 初始状态是0123456789 在这个基础上走了几步for (int i = 0; i < N; i++) { // 从第0世开始到第9世 八戒手里的钱可以走到第几个店铺printf("%d", get(i, &k));}printf("\n");system("pause");return 0;
}

以上就利用数学原理和C语言,可以求全排列的某一个状态,以此为基础,把求第k步状态的功能封装成一个函数,然后求出一个数的全排列。

4、C语言实现一个数的全排列

写一个循环,把第1到N的阶乘的状态都找出来就实现了一个数的全排列
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>#define N 4 // 有几个位置 八戒有几条命以及有几个包子店int fac[N];   // fac[i] = (N-1-i)!,即 fac[0]=9!, fac[1]=8!, ..., fac[9]=0! 表示每一世包子的价格
int valid[N]; // valid[i] = 1 表示数字 i 可用 表示包子店是否有效void init() {fac[N - 1] = 1;  // 0! = 1valid[N - 1] = 1;  // 数字 9 可用for (int i = N - 2; i >= 0; i--) {fac[i] = fac[i + 1] * (N - 1 - i);  // 递推 (N-1-i)! 代表每一世包子的价格valid[i] = 1; // 数字 i 可用 表示包子店初始的时候都是有效的}
}// 获取从左往右第 i 位上的数字(i 从 0 开始) 八戒每一世可以走到底几个店铺
int get(int i, int* k) { // 猪八戒这一世手里拿着k元钱 能走到第几个店铺 每一世包子价格不一样int step = *k / fac[i];  // 猪八戒这一世可以买几个包子 这一世包子的价格就是这个位置上阶乘数int j = 0; // 每世都从第一个包子店往后走 但是只有有效的包子店铺才会消耗八戒手里的包子while (step >= 0) { // 包子的数量可以是0的 八戒手里没有包子的话 还可以往前走 遇到有效店铺还让他消耗包子的话八戒会拿炸弹和店铺同归于尽 step -= valid[j];   // 但是只有有效的包子店才能让八戒消耗包子 每走到一个有效店铺用掉一个包子 没有包子还让八戒消耗包子就准备同归于尽if (step < 0) break; // 让八戒包子是负数了就是触发八戒拿炸弹同归于尽的信号 手里没有包子了 你还让八戒消耗一个j++; // 往下一个店铺走 但是下一个店铺是否有效 不一定}valid[j] = 0;  // 八戒用炸弹和店铺同归于尽了 店铺就失效了*k %= fac[i]; // 八戒下一条命手里有多少钱// --------------------------这里本来是返回j 这里改成j+1否则打印的是0-N-1的全排列 而不是1-N的全排列---------------------------/return j + 1;      
}// 输入一个k,返回第k个排列的状态
void permutation(int k) {init();k -= 1; // 求第k个状态 那就是已经走了(k - 1)步 初始状态是0123456789 在这个基础上走了几步for (int i = 0; i < N; i++) { // 从第0世开始到第9世 八戒手里的钱可以走到第几个店铺printf("%d", get(i, &k));}printf("\n");
}int main() {init();for (int j = 1; j <= fac[0] * N; j++) { // fac[0]存的是N-1的阶乘 离N的阶乘还差一个因数Nprintf("j = %d\t", j);permutation(j);}system("pause");return 0;
}

5、与递归法实现全排列对比(deepseek分析)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6、结语

让算法学习变得简单有趣(如果您发现我写的有错误,欢迎在评论区批评指正。)

http://www.lryc.cn/news/627025.html

相关文章:

  • SpringBoot 整合 Langchain4j RAG 技术深度使用解析
  • imx6ull-驱动开发篇30——Linux 非阻塞IO实验
  • redis---常用数据类型及内部编码
  • 设计具有功能安全和网络安全能力的新型半导体芯片
  • 攻克PostgreSQL专家认证
  • Unicode 字符串转 UTF-8 编码算法剖析
  • JVM面试精选 20 题(终)
  • SQL count(*)与 sum 区别
  • 第三阶段数据-4:SqlHelper类,数据库删除,DataTable创建
  • STM32F4 内存管理介绍及应用
  • 建模工具Sparx EA的多视图协作教程
  • PyTorch - Developer Notes
  • 吴恩达 Machine Learning(Class 3)
  • 国产化PDF处理控件Spire.PDF教程:如何使用 Python 添加水印到 PDF
  • Linux命令大全-ps命令
  • Linux系统之部署nullboard任务管理工具
  • 基于springboot中学信息技术课程教学网站
  • 栈上创建和堆上创建区别
  • Nginx 的完整配置文件结构、配置语法以及模块详解
  • 设计模式1-单例模式
  • 继续记事本项目
  • 盲盒商城h5源码搭建可二开幸运盲盒回收转增定制开发教程
  • Hyperledger Fabric官方中文教程-改进笔记(十三)-使用测试网络创建通道
  • Google Chrome 扩展不受信任 - 不受支持的清单版本 解决方案
  • 整体设计 之定稿 “凝聚式中心点”原型 --整除:智能合约和DBMS的在表层挂接 能/所 依据的深层套接
  • AR 虚实叠加技术在工业设备运维中的实现流程方案
  • 云原生环境下的ITSM新趋势:从传统运维到智能化服务管理
  • MySQL 50 道经典练习题及答案
  • YOLOv8n-pose 模型使用
  • 学习中需不需要划线、做笔记