0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

解决不重复序列的全排列问题的两个方法:递归和字典序法

算法与数据结构 来源:未知 作者:易水寒 2018-03-29 11:19 次阅读

简介

给定 {1, 2, 3, , , n},其全排列为 n! 个,这是最基础的高中组合数学知识。我们以 n=4 为例,其全部排列如下图(以字典序树形式来呈现):

程序

我们很容易想到用递归来求出它的所有全排列。

仔细观察上图,

以 1 开头,下面跟着 {2, 3, 4} 的全排列;

以 2 开头,下面跟着 {1, 3, 4} 的全排列;

以 3 开头,下面跟着 {1, 2, 4} 的全排列;

以 4 开头,下面跟着 {1, 2, 3} 的全排列。

代码如下:

/**

*

* author : 刘毅(Limer)

* date : 2017-05-31

* mode : C++

*/

#include

#include

usingnamespacestd;

voidFullPermutation(intarray[],intleft,intright)

{

if(left==right)

{

for(inti=0;i< 4;i++)

cout<< array[i] << " ";

cout<< endl;

}

else

{

for(inti=left;i<= right;i++)

{

swap(array[i],array[left]);

FullPermutation(array,left+1,right);

swap(array[i],array[left]);

}

}

}

intmain()

{

intarray[4]={1,2,3,4};

FullPermutation(array,0,3);

return0;

}

运行如下:

咦~ 递归写出的全排列有点不完美,它并不严格遵循字典序。但是熟悉 C++ 的朋友肯定知道另一种更简单,更完美的全排列方法。

定义于文件 内的两个算法函数:

1、next_permutation,对于当前的排列,如果在字典序中还存在下一个排列,返回真,并且把当前排列调整为下一个排列;如果不存在,就把当前排列调整为字典序中的第一个排列(即递增排列),返回假。

2、prev_permutation,对于当前的排列,如果在字典序中还存在上一个排列,返回真,并且把当前排列调整为上一个排列;如果不存在,就把当前排列调整为字典序中的最后一个排列(即递减排列),返回假。

/**

*

* author : 刘毅(Limer)

* date : 2017-05-31

* mode : C++

*/

#include

#include

usingnamespacestd;

voidFullPermutation(intarray[])

{

do

{

for(inti=0;i< 4;i++)

cout<< array[i] << " ";

cout<< endl;

}while(next_permutation(array,array+4));

}

intmain()

{

intarray[4]={1,2,3,4};

FullPermutation(array);

return0;

}

运行截图省略。输出结果正好符合字典序。

那这个 “轮子” 是怎么做的呢?(摘自侯捷的《STL 源码剖析》)

1、next_permutation,首先,从最尾端开始往前寻找两个相邻元素,令第一元素为*i,第二元素为*ii,且满足*i < *ii,找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个大于*i的元素,令为*j,将 i,j 元素对调,再将 ii 之后的所有元素颠倒排列,此即所求之 “下一个” 排列组合。

2、prev_permutation,首先,从最尾端开始往前寻找两个相邻元素,令第一元素为*i,第二元素为*ii,且满足*i > *ii,找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个小于*i的元素,令为*j,将 i,j 元素对调,再将 ii 之后的所有元素颠倒排列,此即所求之 “上一个” 排列组合。

代码如下:

boolnext_permutation(int*first,int*last)

{

if(first==last)returnfalse;// 空区间

int*i=first;

++i;

if(i==last)returnfalse;// 只有一个元素

i=last;

--i;

for(;;)

{

int*ii=i;

--i;

if(*i< *ii)

{

int*j=last;

while(!(*i< *--j))  // 由尾端往前找,直到遇上比 *i 大的元素

;

swap(*i,*j);

reverse(ii,last);

returntrue;

}

}

if(i==first)// 当前排列为字典序的最后一个排列

{

reverse(first,last);// 全部逆向排列,即为升序

returnfalse;

}

}

boolprev_premutation(int*first,int*last)

{

if(first==last)returnfalse;// 空区间

int*i=first;

++i;

if(i==last)returnfalse;// 只有一个元素

i=last;

--i;

for(;;)

{

int*ii=i;

--i;

if(*i> *ii)

{

int*j=last;

while(!(*i> *--j))// 由尾端往前找,直到遇上比 *i 大的元素

;

swap(*i,*j);

reverse(ii,last);

returntrue;

}

}

if(i==first)// 当前排列为字典序的第一个排列

{

reverse(first,last);// 全部逆向排列,即为降序

returnfalse;

}

}

结后语

这篇文章主要介绍了解决不重复序列的全排列问题的两个方法:递归和字典序法。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 程序
    +关注

    关注

    117

    文章

    3781

    浏览量

    80982
  • C++
    C++
    +关注

    关注

    22

    文章

    2107

    浏览量

    73594

原文标题:详解全排列算法

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    决不重复序列排列问题的两个方法

    简介给定 {1, 2, 3, , , n},其排列为 n! ,这是最基础的高中组合数学知识。
    的头像 发表于 04-27 09:21 1.1w次阅读
    解<b class='flag-5'>决不重复</b><b class='flag-5'>序列</b><b class='flag-5'>全</b><b class='flag-5'>排列</b>问题的<b class='flag-5'>两个</b><b class='flag-5'>方法</b>

    求产生一0~9的随机数组,要求不重复

    要求产生一0~9的随机数组,数组不重复,产生10数容易,怎么实现数字不重复?求高手!
    发表于 06-07 13:20

    【我是电子发烧友】正电流和负电流和零电流

    保护误动作,常采用两个第一段组成的四段式保护。灵敏一段是按躲过被保护线路末端单相或相接地短路时出现的最大零电流整定的。其动作电流小,保护范围大,但在单相故障切除后的非相运行状态下
    发表于 06-21 16:18

    一阶通滤波器正负检测的原理和仿真

      常用的正负检测有很多种方法,例如带阻滤波器(BS)、低通滤波器(LPF)、陷波器(NF)、延迟信号撤销
    发表于 01-11 16:25

    python合并字典的 7 种方法

    | 操作符了,只不过它通常用于对集合(set)取并集。利用这一点,也可以将它用于字典的合并,只不过得绕弯子,有点不好理解。你得先利用 items 方法将 dict 转成 dict_items,再对这
    发表于 04-08 15:11

    DNA片段拼接中的预归并重复序列屏蔽方法

    针对DNA 片段拼接中的重复序列识别及屏蔽问题,提出一种预归并重复序列屏蔽方法。在片段拼接前通过扫描子串标识出可能存在重叠关系的shotgu
    发表于 03-21 15:47 25次下载

    基于斜率故障模型的模拟电路软故障字典

    提出了一种新的模拟电路故障字典。与传统方法不同,该方法利用两个节点电压之间的关系函数作为故障特征。对于线性模拟电路,节点电压关系函数为一次
    发表于 05-25 14:46 29次下载

    基于电路功能的分区诊断故障字典

    本文提出了一种基于电路功能分区诊断并建立直流故障字典,分步实施故障定位的电路故障诊断方法。该方法是在构成整个直流故障字典时,通过对电路的分析并结合对故障
    发表于 08-31 14:35 10次下载

    输电线路相排列方法

    同塔多回输电线路之问存在着复杂的电磁耦合关系,当其合环后,各段线路本身的不平衡相互叠加,加剧了环型电网的三相不平衡性。为了减小环型电网的三相不平衡性,结合线路相排列方式进行研究。通过分析环型电网中
    发表于 03-29 17:32 2次下载
    输电线路相<b class='flag-5'>序</b><b class='flag-5'>排列</b><b class='flag-5'>方法</b>

    python实现合并字典方法

    字典对象内置了一 update 方法,用于把另一个字典更新到自己身上。
    的头像 发表于 04-08 15:11 1019次阅读

    永磁同步电动机分数槽集中绕组排列方法分析

    排列 分析 互相验证 ; 提 出 了 应用 电 势星 形图 与 循环数对永磁 同
    发表于 06-20 10:27 0次下载

    两个LED和两个按钮的使用

    电子发烧友网站提供《两个LED和两个按钮的使用.zip》资料免费下载
    发表于 01-30 16:04 1次下载
    <b class='flag-5'>两个</b>LED和<b class='flag-5'>两个</b>按钮的使用

    Python序列字典类型介绍

    字典 介绍 字典是“键值对”的无序可变序列字典中的每个元素都是一“键值对”,包含:“键对象”和“值对象”。 可以通过“键对象”实现快速获
    的头像 发表于 03-08 17:35 1310次阅读
    Python<b class='flag-5'>序列</b>的<b class='flag-5'>字典</b>类型介绍

    如何判定两个信号序列的相似程度?

    在统计学中,相关是描述两个随机变量序列或二元数据之间的统计关系,无论是否具有因果关系。
    的头像 发表于 04-15 09:14 8040次阅读
    如何判定<b class='flag-5'>两个</b>信号<b class='flag-5'>序列</b>的相似程度?

    Python比较两个时间序列在图形上是否相似

    比较两个时间序列在图形上是否相似,可以通过以下方法: 可视化比较:将两个时间序列绘制在同一张图上,并使用相同的比例和轴标签进行比较。可以观察
    的头像 发表于 10-16 11:33 658次阅读