/***Perm.h*****/
#ifndef _ALGORITHM_PERM_H
#define _ALGORITHM_PERM_H
#include <windows.h>
//回呼函數, 每個排列或組合的結果均做為參數傳遞給該函數
typedef void (*PERM_CALLBACK_PROC)(int nIndexArr[], int nArrLen, LPVOID lpUserData);
/**************************************************************************************
函數名稱: PermNoRecurse
函數功能: 使用非遞迴演算法對一個數組中的元素進行全排列,並訪問每一種排列下的數組元素
參數列表:
nArrSize 數組元素個數
lpUserData 指向使用者數組的首地址
call_back 執行每個排列結果的回呼函數
傳回值: 無
註解: 每個排列結果傳遞給回呼函數call_back執行
***************************************************************************************/
void PermNoRecurse(int nArrSize, LPVOID lpUserData, PERM_CALLBACK_PROC call_back);
/// 求從數組a[1..n]中任選m個元素的所有組合。
/// a[1..n]表示候選集,m表示一個組合的元素個數。
/// 返回所有組合的總數。
/**************************************************************************************
函數名稱: CombineNoRecurse
函數功能: 使用非遞迴回溯法從含有n個元素的數組中任選m個
參數列表:
nArrSize 數組元素總個數
nCombine 組合的元素個數
lpUserData 指向使用者數組的首地址
call_back 執行每個組合結果的回呼函數
傳回值: 無
註解: 每個組合結果傳遞給回呼函數call_back執行
***************************************************************************************/
void CombineNoRecurse(int nArrSize, int nCombine, LPVOID lpUserData, PERM_CALLBACK_PROC call_back);
#endif
/*****Perm.cpp*****/
#include "Perm.h"
//交換數組a中下標為i和j的兩個元素的值
void swap(int* a,int i,int j)
{
a[i] ^= a[j];
a[j] ^= a[i];
a[i] ^= a[j];
}
//將數組a中的下標i到下標j之間的所有元素逆序倒置
void reverse(int a[],int i,int j)
{
for(; i<j; ++i,--j)
{
swap(a,i,j);
}
}
void PermNoRecurse(int nArrSize, LPVOID lpUserData, PERM_CALLBACK_PROC call_back)
{
if( nArrSize<2 )
{
return;
}
int i = 0;
int j = 0;
int * pIndexArr = new int[nArrSize];
for( i=nArrSize-1; i>=0; i--)
{
pIndexArr[i] = i;
}
do
{
call_back(pIndexArr, nArrSize, lpUserData);
//找到不符合趨勢的元素的下標i
for( i=nArrSize-2; i>=0; --i)
{
if( pIndexArr[i]<pIndexArr[i+1])
{
break;
}
else
{
if( i == 0)
{
return;
}
}
}
for( j=nArrSize-1; j>i; --j)
{
if( pIndexArr[j]>pIndexArr[i] )
{
break;
}
}
swap(pIndexArr,i,j);
reverse(pIndexArr,i+1,nArrSize-1);
}while(true);
delete []pIndexArr;
}
void CombineNoRecurse(int nArrSize, int nCombine, LPVOID lpUserData, PERM_CALLBACK_PROC call_back)
{
nCombine = nCombine > nArrSize ? nArrSize : nCombine;
int * pIndexArr = new int[nCombine + 1];
for(int i=0; i<=nCombine; i++)
{
pIndexArr[i] = i-1; // 注意這裡order[0]=-1用來作為迴圈判斷標識
}
int k = nCombine;
bool flag = true; // 標誌找到一個有效組合
while(pIndexArr[0] == -1)
{
if(flag) // 輸出符合要求的組合
{
/*for(i=1; i<=m; i++)
cout << a[order[i]] << " ";*/
call_back(&pIndexArr[1], nCombine, lpUserData);
flag = false;
}
pIndexArr[k]++; // 在當前位置選擇新的數字
if(pIndexArr[k] == nArrSize) // 當前位置已無數字可選,回溯
{
pIndexArr[k--] = 0;
continue;
}
if(k < nCombine) // 更新當前位置的下一位置的數字
{
pIndexArr[++k] = pIndexArr[k-1];
continue;
}
if(k == nCombine)
flag = true;
}
delete[] pIndexArr;
}
/*
int combine(int a[], int n, int m)
{
m = m > n ? n : m;
int* order = new int[m+1];
for(int i=0; i<=m; i++)
order[i] = i-1; // 注意這裡order[0]=-1用來作為迴圈判斷標識
int count = 0;
int k = m;
bool flag = true; // 標誌找到一個有效組合
while(order[0] == -1)
{
if(flag) // 輸出符合要求的組合
{
for(i=1; i<=m; i++)
cout << a[order[i]] << " ";
cout << endl;
count++;
flag = false;
}
order[k]++; // 在當前位置選擇新的數字
if(order[k] == n) // 當前位置已無數字可選,回溯
{
order[k--] = 0;
continue;
}
if(k < m) // 更新當前位置的下一位置的數字
{
order[++k] = order[k-1];
continue;
}
if(k == m)
flag = true;
}
delete[] order;
return count;
}
*/
/********TestPerm.cpp********/
// TestPerm.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <time.h>
#include "Perm.h"
long g_nCount = 0;
void ProcessOneComb(int nIndexArr[], int nArrLen, LPVOID lpUserData)
{
char * pPass = (char * )lpUserData;
printf("(");
for(int i=0; i<nArrLen-1; i++)
{
printf("%c,", pPass[nIndexArr[i]]);
}
printf("%c),", pPass[nIndexArr[i]]);
printf("\n");
}
void ProcessOnePerm(int nIndexArr[], int nArrLen, LPVOID lpUserData)
{
char * pPass = (char * )lpUserData;
for(int i=0; i<nArrLen; i++)
{
printf("%c", pPass[nIndexArr[i]]);
}
if(strnicmp("robin", pPass, 5) == 0)
{
getchar();
}
printf("\n");
}
void ProcessOneItem(int nIndexArr[], int nArrLen, LPVOID lpUserData)
{
g_nCount ++;
//PermNoRecurse(nArrLen, lpUserData, ProcessOnePerm);
}
void ProcessOneItemNULL(int nIndexArr[], int nArrLen, LPVOID lpUserData)
{
g_nCount ++;
}
int main(int argc, char* argv[])
{
char szPass[32];
strcpy(szPass, "abcdefghijklmnopqrstuvwxyz");
int n = 0;
n = 5;
time_t t_start = time(NULL);
CombineNoRecurse(strlen(szPass), n, szPass, ProcessOneItem);
time_t t_end = time(NULL);
printf("Comb(%d, %d) time consumed : %d secs, count = %d \n", strlen(szPass), n, t_end-t_start, g_nCount);
//CombineNoRecurse(strlen(szPass), n, szPass, ProcessOneComb);
/*
time_t t_start = time(NULL);
for(int i=1; i<=26; i++)
{
CombineNoRecurse(strlen(szPass), i, szPass, ProcessOneItem);//);ProcessOneItemNULL
//printf("\n");
}
time_t t_end = time(NULL);
printf("Time consumed : %d secs, count = %d \n", t_end-t_start, g_nCount);
*/
/*
int nCnt = g_nCount;
t_start = time(NULL);
for(int i=1; i<nCnt; i++)
{
PermNoRecurse(n, NULL, ProcessOneItem);
if(i%2000 == 0)
{
printf("%d full permutation processed.\n", i);
}
}
t_end = time(NULL);
printf("Perm(%d) time consumed : %d secs, count = %d \n", n, t_end-t_start, g_nCount);
*/
return 0;
}