关于全排列

前几天遇到一个组合的问题,在《编程之美2.3》上找到了解决方法。

昨天在看July的博客,看到了全排列的问题,结果状态不佳,写了好久没写出来。

今天看到了STL库中next_permutation的解法,理解完实现了一下。

递归版本:

优点 : 元素不必预先排序,并且允许出现相同项

缺点: 递归开销大

非递归版本(字典序排序):

优点:没有递归疯狂的函数调用(入栈,出栈),效率高

缺点:因为是字典序排序,不允许出现相同项,调用前必须先排序

/*
* ********************* 全排列的递归写法 ****************************************************
*/
#include <iostream>
using namespace std;

void AllPermutation(char *a,int i,int n)
{
	/*
	*  输出 a[0] ~ a[n-1] 的全排列
	*  i 为当前被固定的元素的序号
	*/

	// 1. 如果 i 为最后一个被固定的数,此时为一种排序,输出
	if(i == n -1 )
	{
		for(int i = 0;i < n;++i)
			cout << a[i] << " ";
		cout << endl;
		return;
	}

	// 2.如果 i 不是最后一个数,依次交换 i 与之后的项,进行一次全排列
	for(int j = i;j < n;++j)
	{
		swap(a[j],a[i]);
		AllPermutation(a,i + 1,n);
		swap(a[j],a[i]);
	}
}
int main()
{
	char a[] = {'a','b','c'};
	int n = sizeof(a)/sizeof(char);
	AllPermutation(a,0,n);
}


/*
* *********************************全排列的非递归写法**************************************
*/
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

template <class Iterator>
bool next_permutations(Iterator begin,Iterator end)
{
	/*
	*  找出序列的下一个序列
	*  如 1234 -> 1243 -> 1324 ->1342 ->1423 > 1432
	*/
	Iterator first = begin;
	Iterator last  = end;
	Iterator i;
	Iterator ii;
	Iterator j;

	// 1.1 从后往前找出两个相邻的项,使得 i < ii
	for(--last;last != begin;--last)
	{
		if(*(last - 1) < *last)
		{
			i  = last - 1;
			ii = last;
			break;
		}
	}
	// 1.2 如果找不到这样的项,结束
	if(last == begin)
		return false;

	// 2.1 继续从后往前找到第一个大于i的项,标记为 j
	for(last = end - 1;last != i; --last)
	{
		if(*last > *i)
		{
			j = last;
			break;
		}
	}
	// 2.2 如果找不到这样的项,结束
	if(last == i)
		return false;
	// 3.1 交换 i 和 j 两个项
	iter_swap(i,j);
	// 3.2 从 ii 开始(包括 ii )逆转所有项
	reverse(ii,end);
	return true;
}

int main()
{
	// 1. 构建一个序列
	vector<char> vec;
	vec.push_back('1');
	vec.push_back('2');
	vec.push_back('3');
	vec.push_back('4');
	// 2. 对序列进行排序
	sort(vec.begin(),vec.end());
	// 3. 输出初始序列
	for(auto i = vec.begin();i != vec.end();++ i)
		cout << *i << " ";
	cout << endl;
	// 4. 输出余下序列
	while(next_permutations(vec.begin(),vec.end()))
	{
		for(auto i = vec.begin();i != vec.end();++ i)
			cout << *i << " ";
		cout << endl;
	}
}


参考:

《STL源码剖析》

http://www.cnblogs.com/devymex/archive/2010/08/17/1801122.html

http://leonard1853.iteye.com/blog/1450085

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值