目录

  • 前言
  • 一、算法思想分析
  • 二、算法效率分析
  • 三、算法代码
    • C语言代码
  • 后记

前言

排列与组合问题,无论是在我们生活中还是项目实际运用中,都说非常之常见的。那么,如何去运用算法思想生成全排列(一组元素的所有排列)呢?
首先,我们来算一笔账。组合是无序的,只需要从一组数据中找到一个子组即可,而组合数如下:

那么排列呢?只会比组合更为复杂,排列在组合的基础上,加了顺序,我们需要获取的是带有顺序的一组数据,n个数据中取m个数进行排列,总排列数如下:

而全排列,是在n个中取n个进行排列,则全排列个数为n!,n!级别的计算量,在算法运算中,本就已经是很大的量了,再加上我们还要通过一些算法来获取到全排列,那么,这个算法的复杂度级别注定会非常高。
插入法获取全排列,这是一个非常容易想到的方法,利用全面已经获取到的排列,直接插入来获取排列,但是这个算法不仅实施起来有难度,而且其复杂度也是在n!之上,显然不可取,这就是为什么我们要理解Johnson Trotter全排列算法了。

一、算法思想分析

Johnson Trotter全排列算法,是一种非常高效的生成全排列的算法。其原理在于,我们为需要排列的每个元素进行标记,先赋予一个初始排列,在初始排列的基础上,获取所有的排列。

  • 赋予从小到大的初始排列,将每个元素赋予一个方向,所有元素的初始方向,全部指向较小的方向(可以理解为左方),如果箭头指向一个相邻的较小元素(就是我指定的方向的相邻的元素比我小),我们说它在这个箭头标记的排列中是可移动的元素。而可移动元素显然不可能只有一个,但是对于n个需要排列的数据,我们在一次遍历之后,查找到的最大的可移动元素才是我们想要的元素。
  • 怎么处理这个最大的可移动元素?在一轮遍历找到最大的可移动元素后,我们将最大的可移动元素与其指向的相邻元素(就是我指的那个较小的元素)交换位置,由此便产生了一次排列。
  • 在交换了顺序之后,再重复上述操作?不,这里需要再加一步操作:我们需要将所有比我们刚才找到的最大的可移动元素大的元素(这里需要理清一下最大可移动的概念,比最大可移动元素还要大的元素不一定是可以移动元素哦),将这些元素的指向进行反转(例如:如果原先指向左边,则重新指向到右边),完成这一步之后,再重复上述操作,继续查找最大可移动元素。
  • 最后,直至我们找不到可移动元素,那么我们认定,全排列已经生成。

Johnson Trotter全排列算法的思想较容易理解,用代码实现起来较为轻松,但这个算法也因此存在缺点,存在什么缺点?大家可以思考一下。

二、算法效率分析

emmmm我能不分析么。。。
总的来说,因为全排列的个数本身就已经有n!个了,那么算法复杂度再怎么优化也是大于n!的,但相对于其他算法,本算法对于全排列个数本身,可以说是线性级别的。
具体级别,大家有兴趣可以分析一下,如果分析出来了,可以留言给我一份嘿嘿,非常感谢。

三、算法代码

C语言代码

C语言的代码如下,如果代码中有任何问题,大家都可以提出来,欢迎指正,感激不尽。今天就先不贴JavaScript代码了,晚上还要肝英语作业emmmmm。

/*johnson-Trotter 全排列算法 输入:一个随机数n  输出:展示n的全排列 因排列有限 最大先限制为7 */
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
struct element {/*值*/int value;/*状态*/int state;
};
#define MAXN 100
/*全局数组*/
element arr[MAXN];
int counter=0;/*交换ele函数 显然 我们交换的是地址*/
void swap(int i,int j){element t=arr[i];arr[i]=arr[j];arr[j]=t;
} /*参数1:数组长度  参数2:上一次查找后所得到的最大可移动元素的位置*/
void JST(int n,int maxIndex) {/*上一次查找后 输出一次排列*/printf("第%d个:",++counter);for(int i=1; i<=n; i++) {printf("%d",arr[i]);}printf("\n");/*因为上一次其实已经查找过最大可移动元素 当前只有将最大可移动元素与它该交换的位置交换即可 这里我们需要明确 交换之后的排列 是在下一次输出的(前提是下一次存在交换的)*//*交换*/int maxIndexValue=arr[maxIndex].value;swap(maxIndex,maxIndex+arr[maxIndex].state);/*变换所有比上一次查找出来的元素大的方向*/for(int i=1;i<=n;i++){if(arr[i].value>maxIndexValue){arr[i].state=(arr[i].state==1)?-1:1;}}/*找到下一次最大可移动元素 我们先假设存在*/int isCanMove=false; // 必须假设一个是否可移动 因为我假设了第一个可移动 所以必须有一个标准来衡量是否可以的 来达到出口条件的要求int flagMax; // 标记最大可移动元素的位置 假设第一个int valueMax=-1; // 标记最大可移动元素的值 假设第一个for(int i=1; i<=n; i++) {/*如果为1 向 右 比较*/if(arr[i].state==1) {if(arr[i].value>arr[i+1].value&&arr[i].value>=valueMax) {flagMax=i;valueMax=arr[i].value;isCanMove=true;}}/*如果为-1 向 左 比较*/if(arr[i].state==-1) {if(arr[i].value>arr[i-1].value&&arr[i].value>=valueMax) {flagMax=i;valueMax=arr[i].value;isCanMove=true;}}}/*如果还可以移动 则进入下一次的排列 */if(isCanMove) JST(n,flagMax);else {printf("第%d个:",++counter);for(int i=1; i<=n; i++) {printf("%d",arr[i]);}}return ;
}
int main() {/*改变随机种子数 保证每次的随机数不一样*/srand(time(NULL));/*2~7以内的随机全排列*/int n = rand() % 5+2;/* 数组赋值 初值是位置值 状态全部向左 即-1 向右则为1 */arr[0].value=9999; // 0位置元素极大 保证第一个元素不会与之交换  反正正常数组里面最大的为7 arr[n+1].value=9999; // 同理 for(int i=1; i<=n; i++) {arr[i].value=i;arr[i].state=-1;}/*调用全排列算法 显然 第一次默认最后一个元素为最大可以的元素 所以第二个参数传递位置:n*/JST(n,n);printf("\n %d个数全排列共有%d个 ",n,counter);
}

后记

非常感谢看到这里。
在众多的排列算法之中,Johnson Trotter算法思想是较为好理解的,无论是对于手写全排列,还是对于计算机编程全排列,其思想都是易于实现的。并且其复杂度也是相对较低的(还是那句话,本身全排列个数就已经n!了,算法效率也没法低了)。而前面我们提到,Johnson Trotter算法本身存在一个缺陷,是什么呢?Johnson-Trotter算法生成的是最小变化的序,对于需要字典序列的全排列(例如:123,132,213,231,312,312),是无法满足的,这也是它的一个小缺陷了,不过它已经很强大了。
JavaScript代码后续会更新,记得用node运行更佳哦。

算法设计与分析——Johnson Trotter算法相关推荐

  1. 哈工大威海算法设计与分析_计算机算法设计与分析第一章 算法概述

    晓强Deep Learning的读书分享会,先从这里开始,从大学开始.大家好,我是晓强,计算机科学与技术专业研究生在读.我会不定时的更新我的文章,内容可能包括深度学习入门知识,具体包括CV,NLP方向 ...

  2. 算法设计与分析:贪心算法 - 排课问题(DP与贪心的区别与应用)

    文章目录 前言 贪心算法概念 排课问题 问题描述与分析 动态规划求解 简化问题应用贪心算法 总结 本文参考UCAS卜东波老师算法设计与分析课程撰写 前言 前面两大章节的内容分治思想与动态规划暂时告一段 ...

  3. 计算机算法设计与分析教学大纲,《算法设计与分析》教学大纲

    <<算法设计与分析>教学大纲>由会员分享,可在线阅读,更多相关<<算法设计与分析>教学大纲(3页珍藏版)>请在人人文库网上搜索. 1.课程编号:&quo ...

  4. 算法设计与分析:最短路径算法

    某个函数(u,v) : 表示这个函数用到u.v这两个点 d[v] : 当前顶点v的值 w[u,...,v] : u到v一种路径的权值 一.松弛relax(u,v) 解释:这是一种计算起始点走到某个顶点 ...

  5. 计算机算法设计与分析期末试题,算法设计与分析期末考试试卷(D卷)(含答案).doc...

    算法设计与分析期末考试试卷(D卷) 一.选择题(0分,每题分) .D A.n2/2 + 2n的渐进表达式上界函数是O(2n) B.n2/2 + 2n的渐进表达式下界函数是Ω(2n) C.logn3的渐 ...

  6. 【算法设计与分析】排序算法性能分析

    github:项目地址 一.实验目的 掌握选择排序.冒泡排序.合并排序.快速排序.插入排序算法原理 掌握不同排序算法时间效率的经验分析方法,验证理论分析与经验分析的一致性. 二.实验概述 排序问题要求 ...

  7. 《算法设计与分析》部分算法总结

    1.蛮力法 蛮力法的概述和定义: 蛮力法--简单说是一种简单直接的算法设计策略,也叫作暴力法,枚举法或者穷举法,蛮力法解决问题常常简单粗暴,常常基于问题的描述和所涉及的概念,定义直接求解,逐一列举并且 ...

  8. 算法设计与分析 实验五 算法综合实验

    实验5.<算法综合实验> 一.实验目的 理解和复习所学各种算法的概念 掌握和复习所学各种算法的基本要素 掌握各种算法的优点和区别 通过应用范例掌握选择最佳算法的设计技巧与策略 二.实验内 ...

  9. 【算法设计与分析】贪心算法:单源最短路径和prim算法的最小生成树

    1.单源最短路径问题的问题提出是,计算带权有向图G =(V, E)中一个点(源点)到其余各顶点的最短路径长度,如下图所示.设源点为顶点1,采用Dijkstra算法求下图中源V0为到其余各顶点的最短路径 ...

最新文章

  1. 威胁报告:mDNS 反射式 DDoS 攻击
  2. BZOJ1036: [ZJOI2008]树的统计Count
  3. 开放大学计算机应用基础形考答案,国家开放大学计算机应用基础形考作业二答案~.doc...
  4. redis之 zadd、zremrangebyscore、zremrangebyrank、zscore、zcard、zcount、zrangebyscore、zinczrevrankzrevrange
  5. mysql必_MySQL必知必会(一)
  6. win8.1已阻止java_win8系统下打开java程序时出现应用程序已被安全设置阻止的解决方法...
  7. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 TaskMasger 启动
  8. skylark 叫响中国云计算时代(类GAE云计算平台)
  9. Javascript项目
  10. FTP文件传输工具(三)
  11. oracle数据库单张表备份,oracle数据库如何备份一张表
  12. 2021年程序员个人年终工作总结10篇
  13. 完全认识计算机网络之TCP/IP
  14. java.lang.IllegalArgumentException: Illegal URL:
  15. android导入support-v4包(导包通用教程)
  16. 腾讯智慧交通的「KPI底座」
  17. 德勤报告丨走向智能边缘
  18. AndroidStudio音乐播放服务service实现
  19. mysql安装的密码设置_MySql之安装以及设置密码等
  20. 自定义View之绘图篇(二):路径(Path)

热门文章

  1. 数据库(oracle)服务器的cpu大于80%
  2. 利用新浪API实现数据的抓取\微博数据爬取\微博爬虫
  3. 表的自然连接(数据结构链表链接)
  4. 继电器控制模块的一些知识
  5. soot中基本的对象
  6. UVA 12325 宝箱 Zombie‘s Treasure Chest
  7. pandas duplicated() 重复行标记与drop_duplicates()删除
  8. DoTween的使用与详解
  9. PWM、SPWM、SVPWM的个人理解
  10. 【粗翻】CALIPSO数据用户指南-激光雷达等级1B 4.x数据质量声明