排列组合递归和非递归算法总结篇

#include <iostream>
#include <string>
#include <math.h>
#include <vector>
#include <algorithm>


using namespace std;

//method1
bool flag[5] ;
int arr[5] = {1,2,3,4,5};
int len = sizeof(arr)/sizeof(int);
void Comb(int n,int count);
//

//method2
void Comb2(int n,int count);
vector<int> result;

//method3:

void Comb3(int n,int count);
int GetCombCount(int n,int m);

//3
void  GetCharComb();

//4
int data[3] = {1,2,3};
int data1[3] = {4,2,3};
void permutation(int *a,int len);

void stl_permutaton(int *a,int len);

//求全幂集  可以依次取Comb(4,1) Comb(4,2)  Comb(4,5) + 空集



//5
int num = 0;
void permutation(int array[], int begin, int end);



int main()
{
	
	vector<char> result;

	for(int i = 0;i<5;i++)
		flag[i] = false;
	cout << "---递归组合1(根据标志位打印每一个组合)----" << endl;
	Comb(4,3);
	cout << "---递归组合2(保存每一个组合到容器中)---" << endl;
	Comb2(4,1);
	
	cout << "---非递归组合---" << endl;
	Comb3(5,3);

	cout << "---字符串所有组合(幂集除去空串)----" << endl;
	GetCharComb();

	cout << "---非递归排列---" << endl;
	permutation(data,3);

	cout << "----STL全排列--" << endl;
	stl_permutaton(data1,3);

	cout <<"--递归排列----" <<  endl;
	 int a[3] = { 2, 3, 4};
    permutation(a, 0, sizeof(a) / sizeof(int) - 1);

	return 0;
}


void Comb(int n,int count)
{
	if(count == 0)
	{
		//simiar with select   using vector storage selected data will be  similar with epoll 
		for(int i = 0;i<len;i++)
			if(flag[i] == true)
				cout << arr[i] << " ";
		cout << endl;
		return;//-  exit condition 1--(递归结束条件1)
	}
	if(n<0)//  exit condition 2   --(递归结束条件2)
		return;
	flag[n] = true;
	Comb(n-1,count-1);
	flag[n] = false;
	Comb(n-1,count);
}

void Comb2(int n,int count)
{
	if(count == 0)
	{
		//每次递归结束 求得的一个组合 ,
		vector<int>::iterator it;
		for(it = result.begin();it < result.end();it++)//
			cout << *it << " ";
		cout << endl;
		return;
	}
	if(n<0)
		return;
	result.push_back(arr[n]);
	Comb2(n-1,count-1);
	result.pop_back();
	Comb2(n-1,count);

}



/*
用一个数组,模拟2进制加法器,某一个为1,则取对应的字符,若为0则不取,就能够实现字符组合。也可以不用数组。设有n个字符。
int num 从 1 自增到 2^n -1, 将num右移i位,跟1做按位&操作,即可判断第i个字符取还是不取。
001 010 011 100 101 110 111
c    b    bc  a  ac  ab abc


//还存在的问题的是符数组的长度<32的话这个办法还是很不错的,如果>32就需要原始方法了。


*/
void  GetCharComb()  
{//求幂集
	//string str= "aabc";
	string str = "abc";
	int N = str.size();
	int num  = pow(2.0,N) ;// (2.0   N)
	for(int i=1;i<num;i++)//num = [1-7]
	{
		for(int j=0;j<N;j++)
		{
			if((i>>j)&1)//tips ----:检测为1的bit位
				cout<<str[j];//----str[j]  则先为a
		}
		cout<<endl;
	}

}


/*
字典序变化(1234---->  4321)
1.从最右边开始比较两两相邻的元素,直至找到右边比左边大的一对,左边那个
2.就是将要被替换的,再从最右边开始找比这个元素大的第一个,交换他们两个
3.交换之后,翻转交换元素的后面的所有元素
*/



void permutation(int *a,int len)
{
	int i,j;
	int tmp;
	int num = 6;//1*2*3
	copy(arr,arr+len,ostream_iterator<int,char>(cout," "));
	cout << endl;
	for(i=len-1;i>0;i--)
	{
		if(a[i] > a[i-1])// i-1  【1】
		{
			for(j = len-1;j>=0;j--)
				if(a[j] > a[i-1])//【2】
				{
					tmp = a[i-1];
					a[i-1] = a[j];
					a[j] = tmp;

					//【3】
					int m = i,n = len-1;
					while(m<=n)
					{
						tmp = a[m];
						a[m] = a[n];
						a[n] = tmp;
						m++;
						n--;
					}

					break;
				}
			i = len;//begin again
			copy(a,a+len,ostream_iterator<int,char>(cout," "));
			cout << endl;
		}
	}
}

void stl_permutaton(int *a,int len)
{//字典序的第一个序列必须递增
	sort(a,a+len);
	do
	{
		copy(a,a+len,ostream_iterator<int,char>(cout," "));
		cout << endl;
	}while(next_permutation(a,a+len));
}




/*
思路:
(A、B、C、D)的全排列为
1、A后面跟(B、C、D)的全排列
2、B后面跟(A、C、D)的全排列
3、C后面跟(A、B、D)的全排列
4、D后面跟(A、B、C)的全排列
而对1中的(B、C、D)照样可以按照上面的形式进行分解。



*/
void permutation(int array[], int begin, int end)
{
    int i;

    if(begin == end){//递归退出条件  处理最后一个元素了
		num ++;
		//cout << end << endl;
        for(i = 0; i <= end; ++i){
            cout<<array[i]<<" ";
        }
        cout<<endl;
        return;
    } else {
        //for循环遍历该排列中第一个位置的所有可能情况
        for(i = begin; i <= end; ++i) {
            swap(array[i], array[begin]);
            permutation(array, begin + 1, end);
            swap(array[i], array[begin]);//还原数组  继续下一次遍历
        }
    }
}


//Non-Recursive method to get combination
void Comb3(int n,int count)
{/*
递减最小变化:
从右往左找第一对10交换,表示我想把数变小
但我我希望减小的最少,则交换点后面的数要尽量大,所以把1全部移到交换点后的高位
11100
11010
11001
10110
10101
10011
01110
01101
01011
00111
 */
	//int bit[5] = {1,1,1,0,0};//initial bit array
	int *bit = new int[n];
	for(int k = 0;k<n;k++)
	{
		if(k<count)
			bit[k] = 1;
		else
			bit[k] = 0;
	}

	int i,j,beg,end;
	int len = sizeof(arr)/sizeof(int);
	int N = GetCombCount(n,count);   //C(n,count)  C(5,3)

	for(i = 0;i<len;i++)
		if(bit[i] == 1)
			cout << arr[i];


	cout << endl;
	for(j = 1;j<=N-1;j++)
	{


	for(i = len-1;i>0;i--)
	{
		if(bit[i] == 0 && bit[i-1] == 1)
		{
			swap(bit[i],bit[i-1]);
		
		//from index: [i to len-1] , make all bit 1 in the right
		beg = i;
		end = len - 1;
		while(1)
		{
			while(bit[beg] == 1)
			{
				beg ++;
				if(beg >= len)
					break;
			}
			while(bit[end] == 0)
			{
				end --;
				if(end <i)
					break;
			}

			if(beg < end)
				swap(bit[beg],bit[end]);
			else
				break;

		}//end of "while"
		break;
		}//end of "if"

	//	copy(bit,bit+5,ostream_iterator<int,char>(cout," "));
	//	cout <<endl;

	}

	for(i = 0;i<len;i++)
		if(bit[i] == 1)
			cout << arr[i];
	cout << endl;

	}

}

int GetCombCount(int n,int m)
{
	int i;
	int a,b,c,s;// s = a/(b*c)
	a = b = c =1;
	for(i = 1;i<=n;i++)
		a*=i;
	for(i = 1;i<=m;i++)
		b*=i;
	for(i = 1;i<=n-m;i++)
		c*=i;
	s = a/(b*c);
	return s;
}

《排列组合递归和非递归算法总结篇》

《排列组合递归和非递归算法总结篇》

    原文作者:递归算法
    原文地址: https://blog.csdn.net/hishentan/article/details/39062347
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞