1. 程式人生 > >排列組合遞迴和非遞迴演算法總結篇

排列組合遞迴和非遞迴演算法總結篇

#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;
}





相關推薦

排列組合演算法總結

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

排列實現(permutation)(C++)

全排列問題 以下是C++程式碼實現: //Permutation1 和 permutation2 分別是基於遞迴和非遞迴的實現,都可以實現去除重複的排列 //讀者也可以自己提交之後到leet

一列數字的規則如下;1,1,2,3,5,8,13,21,34........ 求第30位數字是多少,用兩種方法演算法實現

斐波納契數列(Fibonacci Sequence),又稱黃金分割數列。在數學上,斐波納契數列以如下被以遞迴的方法定義:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)在現代物理、準晶體結構、化學等領域,斐波納契數列都有直接的應用,現在我從演算法的角度,利用遞迴和非

二叉樹的前序,中序,後序的遍歷的程式碼-C語言

#include <stdio.h> #include<stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input l

二叉樹的前中後序遍歷(版本)

各位讀者週末愉快呀,今天我想來說說一道很常見的面試題目 —— 關於二叉樹前中後序遍歷的實現。本文將以遞迴和非遞迴方式實現這 3 種遍歷方式,程式碼都比較短,可以放心食用。 先簡單說明一下這 3 種遍歷方式有什麼不同 —— 對於每種遍歷,樹中每個結點都需要經過 3 次(對於葉結點,其左右子樹視為空子樹),但前

演算法】二叉樹的遍歷(轉)

原文地址 【寫在前面】   二叉樹是一種非常重要的資料結構,很多其它資料結構都是基於二叉樹的基礎演變而來的。對於二叉樹,有前序、中序以及後序三種遍歷方法。因為樹的定義本身就 是遞迴定義,因此採用遞迴的方法去實現樹的三種遍歷不僅容易理解而且程式碼很簡潔。而對於樹的遍歷若採用非遞迴的方法,就要採

leetcode 783. 二叉搜尋樹結點最小距離(實現java)

題目描述: 給定一個二叉搜尋樹的根結點 root, 返回樹中任意兩節點的差的最小值。 示例: 輸入: root = [4,2,6,1,3,null,null] 輸出: 1 解釋: 注意,root是樹結點物件(TreeNode object),而不是陣列。 給定的樹 [4,

No.19程式碼練習:斐波那契數列,某數k次冪,模擬實現strlen(),階乘 ,逆置字串(

學習不易,需要堅持。 遞迴 程式呼叫自身的程式設計技巧稱為遞迴( recursion)。遞迴做為一種演算法在程式設計語言中廣泛應用。 一個過程或函式在其定義或說明中有直接或間接呼叫自身的一種方法,它通常把一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解,遞迴策略只需

楊氏矩陣查詢數字(

楊氏矩陣  有一個二維陣列. 陣列的每行從左到右是遞增的,每列從上到下是遞增的. 在這樣的陣列中查詢一個數字是否存在。 要求:時間複雜度小於O(N);  例:  1 2 3          4 5 6  

求第n個斐波那契數(分別用兩種方法求解)

斐波那契數列指的是這樣一個數列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55……這個數列從第3項開始,每一項都等於前兩項之和。 這裡分別用遞迴和非遞迴的方法實現: 遞迴 #define _CRT_SECURE_NO_WARNINGS 1 #include&l

c++二叉樹的的前序中序後序遍歷以及層序遍歷

二叉樹的遞迴版的前序,中序和後序遍歷很簡單也很容易理解,這裡就放一個前序遍歷的例子 //前序遍歷遞迴演算法,遞迴演算法都大同小異,這裡就不一一列舉了 void binaryTree::pro_order(NodeStack::Node *t) { NodeStack::Node *h = t;

猴子吃桃問題,用方法

猴子吃桃問題:猴子第一天摘下若干個桃子,當即吃了一半,還不過癮,又多吃了一個 第二天早上又將剩下的桃子吃掉一半,又多吃了一個。以後每天早上都吃了前一天剩下的一半零一個。到第10天早上想再吃時,見只剩下一個桃子了。求第一天共摘了多少。   public class Test{ &nb

全面分析再動手的習慣:連結串列的反轉問題(方式)

https://www.cnblogs.com/kubixuesheng/p/4394509.html dashuai的部落格 要麼牛B!要麼滾!   首頁   聯絡 訂閱 管理 隨筆-88  文章-0 

二叉樹的後序遍歷-演算法

同樣的,建立的演算法在先序中有,略去。 後序遞迴遍歷演算法 void PostOrder(BiTree bt){ if(bt){ PostOrder(bt->lchild); PostOrder(bt->rchild); cout<<bt-

二叉樹的中序遍歷-演算法

建立二叉樹就不說了,這裡直接: 中序遞迴遍歷演算法 void InOrder(BiTree T){ if(T){ InOrder(T->lchild); cout<<T->data<<" "; InOrder(T->rch

二叉樹的先序遍歷-演算法

需要實踐先序遍歷,我們先建立二叉樹。這裡採用先序序列建立二叉樹,不為別的,因為簡單。 typedef int ElemType; typedef struct BiTNode{ ElemType data; struct BiTNode *lchild, *rchild; }*BiTre

先序遍歷-(java版)

用輔助棧就行儲存。   import java.util.Stack; class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; publi

中序遍歷--(java版)

根據中序遍歷的順序,對於任一結點,優先訪問其左孩子,而左孩子結點又可以看做一根結點,然後繼續訪問其左孩子結點,直到遇到左孩子結點為空的結點才進行訪問,然後按相同的規則訪問其右子樹。因此其處理過程如下:   對於任一結點root,引入一個輔助節點p,其作用是:標記已經訪問過的節點, &nb

分別實現求第n個斐波那契數。

//非遞迴 int main() { int a = 0; int b = 1; int c = 0; int i = 0; int n = 0; printf("請輸入數字n(n>2)求第n個斐波那契數:"); scanf("%d",&n); for(i =

Leetcode---中序遍歷二叉樹--

中序遍歷二叉樹 題目連結:中序遍歷二叉樹 解法一: 遞迴遍歷比較簡單 public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayLi