算法设计与分析——Johnson Trotter算法

博客详细介绍了Johnson Trotter全排列算法的思想、效率分析及C语言实现。该算法通过标记和交换元素来生成全排列,具有较低的时间复杂度。尽管存在无法生成字典序全排列的缺陷,但在理解和实现上相对简单。
摘要由CSDN通过智能技术生成

前言

排列与组合问题,无论是在我们生活中还是项目实际运用中,都说非常之常见的。那么,如何去运用算法思想生成全排列(一组元素的所有排列)呢?
首先,我们来算一笔账。组合是无序的,只需要从一组数据中找到一个子组即可,而组合数如下:
组合的个数(图来自百度)
那么排列呢?只会比组合更为复杂,排列在组合的基础上,加了顺序,我们需要获取的是带有顺序的一组数据,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
  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值