详解全排列算法


简介


给定 {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 <iostream>

#include <algorithm>

 

using namespace std;

 

void FullPermutation(int array[], int left, int right)

{

    if (left == right)

    {

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

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

        cout << endl;

    }

    else

    {

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

        {

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

            FullPermutation(array, left + 1, right);

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

        }

    }

}

 

int main()

{

 

    int array[4] = { 1,2,3,4 };

 

    FullPermutation(array, 0, 3);

 

    return 0;

}


运行如下:



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


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


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


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


/**

*

* author : 刘毅(Limer)

* date   : 2017-05-31

* mode   : C++

*/

 

#include <iostream>  

#include <algorithm>  

 

using namespace std;

 

void FullPermutation(int array[])

{

    do

    {

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

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

        cout << endl;

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

}

 

int main()

{

 

    int array[4] = { 1,2,3,4 };

 

    FullPermutation(array);

 

    return 0;

}


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


那这个 “轮子” 是怎么做的呢?(摘自侯捷的《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 之后的所有元素颠倒排列,此即所求之 “上一个” 排列组合。


代码如下:


bool next_permutation(int * first, int * last)

{

    if (first == last) return false;  // 空区间

    int * i = first;

    ++i;

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

    i = last;

    --i;

 

    for (;;)

    {

        int * ii = i;

        --i;

        if (*i < *ii)

        {

            int * j = last;

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

                ;

            swap(*i, *j);

            reverse(ii, last);

            return true;

        }

    }

 

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

    {

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

        return false;

    }

}

 

bool prev_premutation(int * first, int * last)

{

    if (first == last) return false;  // 空区间

    int * i = first;

    ++i;

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

    i = last;

    --i;

 

    for (;;)

    {

        int * ii = i;

        --i;

        if (*i > *ii)

        {

            int * j = last;

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

                ;

            swap(*i, *j);

            reverse(ii, last);

            return true;

        }

    }

 

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

    {

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

        return false;

    }

}


结后语


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


转自:刘毅

https://61mon.com/index.php/archives/197/


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/304124.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS2019 调试技巧之附加进程

C# 创建服务并附加到进程进行调试步骤一&#xff1a;在任务栏右键-》》点击任务管理器-》》选择服务&#xff0c;找到启动的进程PID或者WINR 进入cmd命令 输入 netstat -ano | find "进程端口" 找端口步骤二&#xff1a;VS中找到“调试”菜单&#xff0c;选择“…

sql同时向两个表插入数据_SQL入门-数据库和客户端的安装,表的创建和数据插入...

1、如何验证MySQL数据库安装成功按照上图操作打开SQL命令行客户端输入安装MySQL时设置的密码并按enter键&#xff0c;得到下图&#xff1a;如果有显示出来红框里的内容&#xff0c;就表示安装成功。红框里的内容表示的是MySQL数据库版本号。2、如何用客户端&#xff08;Navicat…

我是怎么进入Oracle这样的大企业的?

导语&#xff1a;人工智能是泡沫么&#xff1f;AI产业的未来将何去何从&#xff1f;机器学习又该怎么学习&#xff1f;AI行业从业者又是怎么看待这个行业的呢&#xff1f;踏入一个行业之前最好对这个行业有个全方位的了解。本文作者饶毅&#xff0c;现就职于甲骨文公司。AI行业…

websocket文档_WebSocket推送 原理扫盲到上手实践

关于服务端推送技术&#xff0c;大家比较熟悉的可能就是轮询&#xff0c;但是轮询只能是由客户端先发起http请求。在HTTP1.1中的keep-alive方式建立的http连接&#xff0c;但是一个Request只能对应一个Response&#xff0c;而且这个Response是被动的&#xff0c;不能主动发起。…

DISCUZ7.2在通达OA2009桌面显示技巧

最近在测试DISCUZ 和通达...猛然间看到,,,可以DISCUZ可以和通达完美结合,禁不住进行了测试.....效果还挺好的...最初效果图如下:感觉挺别扭的,于是将DISCUZ调用代码更改了代码如下:[show1] <table width"100%" > <tr> <td alignleft> <di…

如何在 ASP.Net Core 中使用 Lamar

ASP.Net Core 自带了一个极简的 开箱即用 的依赖注入容器&#xff0c;实际上&#xff0c;你还可以使用第三方的 依赖注入容器 来替代它&#xff0c;依赖注入是一种设计模式&#xff0c;它能够有效的实现对象之间的解耦并有利于提高单元测试和维护性&#xff0c;你可以使用 依赖…

扎克伯格做了26张PPT,员工效率提10倍,已被疯狂传阅!

1、时间常有&#xff0c;时间在于优先。2、时间总会有的&#xff1a;每天只计划 4&#xff5e;5 小时真正的工作。3、当你在状态时&#xff0c;就多干点&#xff1b;不然就好好休息&#xff1a;有时候会连着几天不是工作状态&#xff0c;有时在工作状态时却又能天天忙活 12 小时…

2010南非世界杯32强手绘海报

2010南非世界杯32强手绘海报 2010年南非世界杯已经进入最后的倒计时&#xff0c;近日&#xff0c;ESPN推出了一组以世界杯32强为主题的手绘海报。在这组颇有漫画性质的海报中&#xff0c;32强每支球队的特点都是展现得淋淋尽致&#xff0c;卡卡、梅西、C罗、托雷斯等球星也自然…

鹅厂二面,Nginx回忆录

上周二面鹅厂&#xff0c;面试官问出了“nginx你了解吗&#xff1f;”这样宽泛直白的句式&#xff0c;我一时抓不到重点&#xff0c;一时语噻。下班想了一下&#xff0c;平时潜移默化用到不少nginx的能力&#xff0c;但在面试的时候没有吹成对应的概念。面谈nginx核心能力nginx…

干货|吴恩达Coursera课程教你学习神经网络二!

上一周的课程中讲了神经网络的结构以及正向传播(feed forward)过程&#xff0c;了解了神经网络是如何进行预测的&#xff0c;但是预测的结果怎么和真是结果进行比较以及发现了错误如何修改还没有提及。这一周的课程中&#xff0c;介绍了cost function作为结果比较的标准以及bac…

vue预加载动态生成runtime.js_预渲染 prerender-spa-plugin 避坑指南

预渲染原理在webpack打包结束并生成文件后&#xff08;after-emit hook&#xff09;&#xff0c;会启动一个server模拟网站的运行&#xff0c;用puppeteer&#xff08;google官方的headless 无头浏览器浏览器&#xff09;访问指定的页面route&#xff0c;得到相应的html结构&am…

使用 .NET CLI 构建项目脚手架

前言在微服务场景中&#xff0c;开发人员分配到不同的小组&#xff0c;系统会拆分为很多个微服务&#xff0c;有一点是&#xff0c;每个项目都需要单元测试&#xff0c;接口文档&#xff0c;WebAPI接口等&#xff0c;创建新项目这些都是重复的工作&#xff0c;而且还要保证各个…

.net 垃圾回收机制

尽管在.NET framework下我们并不需要担心内存管理和垃圾回收(Garbage Collection)&#xff0c;但是我们还是应该了解它们&#xff0c;以优化我们的应用程序。同时&#xff0c;还需要具备一些基础的内存管理工作机制的知识&#xff0c;这样能够有助于解释我们日常程序编写中的变…

《自然》杂志:中国人越来越沉迷于对着一个叫“区块链”的东西胡言乱语

起初&#xff0c;《自然》杂志以为在2018年春节前后中国发生了一场瘟疫&#xff0c;但很快就改变了这一看法。除了精神亢奋无法入睡&#xff0c;那里的人们身体还算健康。不过&#xff0c;他们越来越沉迷于对着一个叫“区块链”的东西胡言乱语&#xff0c;根本停不下来。因为教…

python if 跳出_Python保留字简单释义

作者&#xff1a;小小程序员链接&#xff1a;https://zhuanlan.zhihu.com/p/87393696来源&#xff1a;知乎著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。Guido van Rossum在1991年正式对外发布Python版本&#xff0c;现在已成为最流行的语言…

敏捷个人:提供更多文档下载,并转载一篇敏捷个人读书笔记

这两周一直忙着OpenExpressApp的自动化测试支持了&#xff0c;对于敏捷个人最近在思考作为新手如何学习的问题&#xff0c;后期我会写篇blog与大家分享一下。在敏捷个人项目中我发布了敏捷个人&#xff0d;认识自我&#xff0c;管理自我.pdf&#xff0c;有很多朋友之前看过&…

大数据揭秘:低学历者发财的概率有多大?结果很吃惊

先看两幅图&#xff1a;Table 1: Mean Earnings by Highest Degree Earned, $: 2009 (SAUS, table 232)Table 2: Unemployment Rates by Educational Attainment图一是美国社会收入和最高学历的关系&#xff0c;图二是美国社会失业率和受教育程度的关系&#xff0c;数据来自SAU…

Win10 Terminal + WSL 2 安装配置指南

自从 Windows Terminal 正式发布后就再没有用过 Windows 系统自带的终端了。主要是 Terminal 简洁且灵活&#xff0c;更重要的是支持特殊字体&#xff0c;通过一些简单的配置可以使得终端看起来更舒适养眼。自从 Win 10 有了 Linux 子系统&#xff08;WSL&#xff09;&#xff…

如何快速解剖数据背后隐藏的信息

1946年2月16日&#xff0c;是一个值得纪念的日子。在这一天&#xff0c;人类历史上真正意义上的第一台电子计算机诞生了&#xff0c;此后计算机便随着科技的发展以强大的生命力飞速发展着。而作为用来定义计算机程序的形式语言——编程语言也紧跟计算机其后蓬勃发展&#xff0c…