LinuxSir.Org  
| 网站首页 | 论坛帮助 |

欢迎来到LinuxSir.Org!
您还未登录,请登录后查看论坛,或者点击论坛上方的注册链接注册新账号。


发表新主题 回复
 
主题工具
旧 06-09-04, 10:21 第 1 帖
soloforce 帅哥
 
soloforce 的头像
 
 
注册会员  
  注册日期: Dec 2004
  帖子: 2,280
  精华: 14
 

标题: [算法]全排列算法C++递归实现


当做练习C++的小玩艺,高手们就不必浪费时间了:)
----------------------------------------------------------------
思路:把各个元素逐个插入到已有排列中所有可能的位置,当得到的目标排列长度等于题给要求排列长度时,把该排列保存起来,即为一个成功的排列。

实现:C++, vector, 递归

效率:设每插入一次为一个基本运算,则时间复杂度为 O(n!) ; 加上vector在插入时又有开销,时间效率不高。 若不把结果输出到屏幕,则AMD XP 1600+ / 1G mem 的运行时间如下:
引用:
8个元素的全排列:
~/coding/cpp $ time ./a.out
real 0m0.154s
user 0m0.134s
sys 0m0.005s

------------------------
9个元素的全排列:
~/coding/cpp $ time ./a.out

real 0m1.409s
user 0m1.208s
sys 0m0.060s

------------------------
10个元素的全排列:
~/coding/cpp $ time ./a.out

real 0m13.858s
user 0m11.227s
sys 0m0.669s

PHP 代码:
#include <iostream>
#include <vector>
#define arr_size(A) (sizeof(A)/sizeof(A[0]))
using namespace std;

template<typename Type>
vector<Type>& permutation(vector<Typedesvector<Typesrc)
{
    static 
vector<Typeresult;
    if( 
src.empty() ){
        
//append a permutation to result-vector
        
result.insert(result.end(), des.begin(), des.end());
        return 
result;
    }
    
Type curr=src.back();
    
src.pop_back();
    for(
typename vector<Type>::iterator it=des.begin();it<des.end()+1it++){
        
//try to insert an item to any possible position
        
it=des.insert(it,curr);
        
permutation(des,src);
        
//remove it for next insertion
        
des.erase(it);
    }
    return 
result;
}

int main()
{
    
int arr[]={1,2,3,4,5,6,7,8,9,10};
    
vector<int>vi(arr,arr+arr_size(arr));
    
vector<int>result=permutation(vector<int>(),vi);

    
// print results to stdout 
    
for(vector<int>::iterator it=result.begin(); it<result.end();){
        for(
int i=0i<arr_size(arr); i++){
            
cout<<*it<<" ";
            
it++;
        }
        
cout<<endl;
    }
    
cout<<"permutations count: "<<result.size()/arr_size(arr)<<endl;








__________________
Athlon Phenom II X4 940 OC 3.6G / Kingston DDR2 4G / DFI 790X-M2RS / Sapphire HD4870 /Audigy2 ZS / 22' LCD / Acbel iPower660

此帖于 06-09-04 10:29 被 soloforce 编辑.
  soloforce 当前离线   回复时引用此帖
旧 06-09-04, 16:36 第 2 帖
yuhch123
 
 
 
注册会员  
  注册日期: Feb 2004
  帖子: 77
  精华: 0
 

iostream不是一般的慢,改成stdio.h,用scanf和printf会快很多吧







__________________
vim + gcc + gdb
  yuhch123 当前离线   回复时引用此帖
旧 06-09-04, 16:42 第 3 帖
Iambitious 帅哥
 
 
 
注册会员  
  注册日期: Jul 2006
  我的住址: ICT
  帖子: 339
  精华: 1
 

代码:
public boolean nextPermutation(int[] a) { int i, j; for (i = a.length - 1; i > 0; i--) { if (a[i] > a[i - 1]) { break; } } i--; if (i == -1) return false; for (j = a.length - 1; j >= 0; j--) { if (a[j] > a[i]) break; } int t = a[j]; a[j] = a[i]; a[i] = t; for (i = i + 1, j = a.length - 1; i < j; i++, j--) { t = a[i]; a[i] = a[j]; a[j] = t; } return true; }
字典序数法:c++ stl中的next_permutation的实现方法,应该是综合情况下最快的产生全排列的算法(尤其在有重复数据的情况下)。

此帖于 06-09-04 16:50 被 Iambitious 编辑.
  Iambitious 当前离线   回复时引用此帖
旧 06-09-04, 16:49 第 4 帖
Iambitious 帅哥
 
 
 
注册会员  
  注册日期: Jul 2006
  我的住址: ICT
  帖子: 339
  精华: 1
 

字典序数法是按照“字典”顺序给出的全排列,有一个排列p1,p2,...pn生成下一个排列的算法如下:
1。求满足关系式p(j-1) < p(j)的j的最大值,设为i
2。求满足关系式p(i-1) < p(k)的k的最大值,设为j
3。p(i-1)与p(j)互相交换,得到新的数列
4。在把新得到的数列从第i个位置到最后一个位置,全部逆转,所得到的数列就是下一个字典序数的排列。
初始状态为p1<=p2<=p3<=...pn
终止状态为pn>=p(n-1)>=...>=p2>=p1
  Iambitious 当前离线   回复时引用此帖
旧 06-09-04, 17:28 第 5 帖
soloforce 帅哥
 
soloforce 的头像
 
 
注册会员  
  注册日期: Dec 2004
  帖子: 2,280
  精华: 14
 

又掌握了一种方法,谢谢Iambitious了。
不过我看字典法每求一个排列要比较、交换的次数好像很多,对于无重复数据的排列应该也不是效率最高的算法吧; 如果重复数据比较多,那的确很快,而且不会产生重复输出。
  soloforce 当前离线   回复时引用此帖
旧 06-09-04, 19:24 第 6 帖
Iambitious 帅哥
 
 
 
注册会员  
  注册日期: Jul 2006
  我的住址: ICT
  帖子: 339
  精华: 1
 

在非插入全排列算法里面应该是最快的,其他的方法需要比较的次数更多,插入全排列的生成算法,如果用链表来实现的话,应该是最快的。
  Iambitious 当前离线   回复时引用此帖
旧 10-08-25, 23:21 第 7 帖
demonarea
 
 
 
注册会员  
  注册日期: Apr 2010
  帖子: 5
  精华: 0
 

以前写过一个非递归的,拿出来献丑一下,因为本人是英语专业,写的不好大家多包涵,主要思想还是和lz一样的,只是把递归改成非递归而已,从算法思想上来讲自然是Iambitious的好。

代码:
#include<stdio.h> #include<string.h> #define N 12 #define pop(str) strcpy(str, stack[--top]) #define push(str) strcpy(stack[top++], str) #define permute(str, i) \ ({int t; t = str[i]; str[i] = str[i-1]; str[i-1] = t; str;}) static char str[N+1], stack[N*(N-1)/2+1][N+1]; static int len, top; int main () { push("1"); /* push the root */ while( top > 0 ) { /* exit when all leaves visited */ pop(str); if( (len = strlen(str)) >= N-1 ) printf( "%s\n", str ); /* reach the leaf */ else { for( int i = len+1; i >= 1; i-- ) str[i] = str[i-1]; str[0] = len + '1'; push(str); for( int i = 1; i <= len; i++ ) /* push brothers */ push( permute( str, i ) ); } } return 0; }
  demonarea 当前离线   回复时引用此帖
发表新主题 回复


主题工具

发帖规则
您 [不可以] 发表新主题
您 [不可以] 回复主题
您 [不可以] 上传附件
您 [不可以] 编辑您的帖子

已 [启用] BB 代码
已 [启用] 表情符号
已 [启用] IMG 代码
已 [禁用] HTML 代码
[论坛跳转…]


所有时间均为[北京时间]。现在的时间是 02:37


Powered by vBulletin 版本 3.6.8
版权所有 ©2000 - 2012, Jelsoft Enterprises Ltd.
官方中文技术支持: vBulletin 中文
版权所有 ©2002 - 2011, LinuxSir.Org