排列与全排列算法

一. 排列与组合的区别

      

      排列是有顺序的, 如(a, b, c)和(b, c, a)是不同的, 虽然同样是三个字母, 但顺序不同.

      组合是没有顺序的,如(a, b, c)和(b, c, a)是相同的, 只要是同样的字母组合, 顺序无所谓.

 

二. 全排列

      

      n个不同元素排成一列. 可将n个不同元素按1 ~ n进行编号, 则n个不同元素的全排列可看成这个自然数的全排列. n个不同元素的全排列共有n!种. 

 

三. 全排列算法

3.1 例子


1234全排列有这些:

1 234, 1 243, 1 324, 1 342, 1 423, 1 432

2 134, 2 143, 2 314, 2 341, 2 413, 2 431

3 124, 3 142, 3 214, 3 241, 3 412, 3 421

4 123, 4 132, 4 213, 4 231, 4 312, 4 321

 

3.2 分解


3.2.1 对1234进行分解

看上面的4组数据, 可分为

以1开头后面跟着(2, 3, 4)的排列

以2开头后面跟着(1, 3, 4)的排列

以3开头后面跟着(1, 2, 4)的排列

以4开头后面跟着(1, 2, 3)的排列

 

3.2.2 再对"以1开头"后面跟着的(2, 3, 4)进行分解"

以2开头后面跟着(3, 4)的排列

以3开头后面跟着(2, 4)的排列

以4开头后面跟着(2, 3)的排列

 

3.2.3 如此类推, 层层分解, 其实就是递归.

 

3.3 递归实现


求字符串"12345"的全排列

#include "stdafx.h"
#include <vector>
#include <string>
#include <algorithm>

std::vector<std::string> g_data;
// 全排列算法
void Permutation(char * pDataSurce, char* pData, int nLen)
{
	// 到达了最后, push进去.
	if(1 == nLen)
	{
		g_data.push_back(std::string(pDataSurce));
		return;
	}
	int i;
	for(i = 0; i < nLen; ++i)
	{
		std::swap(pData[0], pData[i]);
		Permutation(pDataSurce, pData + 1, nLen - 1);
		std::swap(pData[0], pData[i]);
	}	
}

int _tmain(int argc, _TCHAR* argv[])
{
	char chData[256];
	::sprintf_s(chData, "12345");
	Permutation(chData, chData, strlen(chData));
	return 0;
}

 说明:

1. 这里使用递归的思想很容易理解, 但是递归的深度是不能无限的.

2. 这个算法可以优化, 因为有很多重复的操作. 

 

3.4 非递归实现


      STL中有一个函数next_permutation,  它的功能判断传入的序列是否存在"下一个排列", 如果存在, 则产生这个序列并返回true, 否则返回false;

个人理解:

1. 传入的是一个序列. 就是说序列元素间存在比较关系的.

2. 什么叫下一个排列, 例如: 12345这是升序的, 它是第一个排序, 而最后一个排列就是54321了, 54321没有"下一个排列".

 

(_Pr是比较器)

template<class _BidIt, class _Pr> inline

bool next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred);

 

template<class _BidIt> inline

bool next_permutation(_BidIt _First, _BidIt _Last); 

代码

#include "stdafx.h"
#include <vector>
#include <string>
#include <algorithm>

std::vector<std::string> g_data;
void Permutation(char * pData, int nLen)  
{  
    std::sort(pData, pData + nLen);  
    do
    {  
		g_data.push_back(std::string(pData));
    }while(std::next_permutation(pData, pData + nLen));  
}

int _tmain(int argc, _TCHAR* argv[])
{
	char chData[256];
	::sprintf_s(chData, "12345");
	Permutation(chData, strlen(chData)); 
	return 0;
}

 

说明:

1. g_data的内容的存储顺序在递归实现和非递归实现是不同的.

2. 既然STL都帮你实现了, 那肯定用啦.

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值