全排列與全組合的非遞迴C語言實現

來源:互聯網
上載者:User

/***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;
}

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.