我自己想的一道难题,题目的描述很简单,请高手抽1分钟看看

xsh525 2007-04-12 05:19:49
写一个函数,能打出从1到n的所有排列(是排列,不是组合)

比如
fun(3);

就打出
123
132
213
231
312
321

我自己也想了很久,没有答案,不知道有没有高手能给出代码。
...全文
1206 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
双杯献酒 2007-04-15
  • 打赏
  • 举报
回复
STL有算法.
如果自己做,对数据结构的掌握是个考验.
yuyunliuhen 2007-04-14
  • 打赏
  • 举报
回复
mark~
sss_free 2007-04-14
  • 打赏
  • 举报
回复
deng2000贴的程序我还是要反复拜读的,呵呵
dwlitt 2007-04-14
  • 打赏
  • 举报
回复
////////////////////////////////////
//c++ 的递归实现
class CPermute{
private :
int m_num,m_total,*m_arr;

void init(int n){if( n<= 0 ) return; m_num=n;m_total=0;
m_arr = new int[n];
for(int i=0;i<m_num;i++) m_arr[i] = i+1;
}
void destroy(){delete []m_arr;m_arr = NULL;m_num = m_total = 0; }
void PrintPermute(){
printf("NUM %d = ",m_total);
for(int i=0;i<m_num;i++) printf("%d ",m_arr[i]);
printf("\n");
}
void Permute(int k){
#define EXCHANGE(x,y) do{int temp = x;x = y;y = temp;}while(0);
if( k>= m_num-1 ){m_total++;PrintPermute();return;}
Permute(k+1);
for(int i=k+1;i<m_num;i++){
EXCHANGE(m_arr[k],m_arr[i]);
Permute(k+1);
}
}
public:
CPermute():m_num(0),m_total(0),m_arr(NULL){}
~CPermute(){destroy();}

void Calc(int n){init(n);Permute(0); destroy();}
};

void main()
{
CPermute Permute;
Permute.Calc(5); //5的全排列
}
//////////////////////////////////////////////////////
//结果:
NUM 1 = 1 2 3 4 5
NUM 2 = 1 2 3 5 4
.......................
NUM 118 = 5 3 1 4 2
NUM 119 = 5 3 2 4 1
NUM 120 = 5 3 2 1 4
Press any key to continue
dwlitt 2007-04-14
  • 打赏
  • 举报
回复
////////////////////////////////////
//c++ 的递归实现
class CPermute{
private :
int m_num,m_total,*m_arr;

void init(int n){if( n<= 0 ) return; m_num=n;m_total=0; m_arr = new int[n];
for(int i=0;i<m_num;i++) m_arr[i] = i+1;
}
void destroy(){delete []m_arr;m_arr = m_num = m_total = 0;}

void PrintPermute(){
printf("NUM %d = ",m_total);
for(int i=0;i<m_num;i++) printf("%d ",m_arr[i]);
printf("\n");
}
void Permute(int k){
#define EXCHANGE(x,y) do{int temp = x;x = y;y = temp;}while(0);

if( k>= m_num-1 ){m_total++;PrintPermute();return;}
Permute(k+1);
for(int i=k+1;i<m_num;i++){
EXCHANGE(m_arr[k],m_arr[i]);
Permute(k+1);
}
}
public:
CPermute():m_num(0),m_total(0),m_arr(NULL){}
~CPermute(){destroy();}

void Calc(int n){
init(n);
Permute(0);
destroy();
}
};

void main()
{
CPermute Permute;
Permute.Calc(5); //5的全排列
}
//////////////////////////////////////////////////////
//结果:
NUM 1 = 1 2 3 4 5
NUM 2 = 1 2 3 5 4
.......................
NUM 118 = 5 3 1 4 2
NUM 119 = 5 3 2 4 1
NUM 120 = 5 3 2 1 4
Press any key to continue
dwlitt 2007-04-14
  • 打赏
  • 举报
回复
////////////////////////////////////
//c++ 的递归实现
class CPermute{
private :
int m_num,m_total,*m_arr;

void init(int n){
int i;
if( n<= 0 ) return;
m_num=n;m_total=0;
m_arr = new int[n];
for(i=0;i<m_num;i++) m_arr[i] = i+1;
}
void destroy(){
delete []m_arr;
m_arr = NULL;
m_num = m_total = 0;
}
void PrintPermute(){
printf("NUM %d = ",m_total);
for(int i=0;i<m_num;i++) printf("%d ",m_arr[i]);
printf("\n");
}
void Permute(int k){
#define EXCHANGE(x,y) do{int temp = x;x = y;y = temp;}while(0);

if( k>= m_num-1 ){m_total++;PrintPermute();return;}
Permute(k+1);
for(int i=k+1;i<m_num;i++){
EXCHANGE(m_arr[k],m_arr[i]);
Permute(k+1);
}
}
public:
CPermute():m_num(0),m_total(0),m_arr(NULL){}
~CPermute(){destroy();}

void Calc(int n){
init(n);
Permute(0);
destroy();
}
};

void main()
{
CPermute Permute;
Permute.Calc(5); //5的全排列
}
//////////////////////////////////////////////////////
//结果:
NUM 1 = 1 2 3 4 5
NUM 2 = 1 2 3 5 4
.......................
NUM 118 = 5 3 1 4 2
NUM 119 = 5 3 2 4 1
NUM 120 = 5 3 2 1 4
Press any key to continue
Generics 2007-04-13
  • 打赏
  • 举报
回复
这是利用字符串增减字符的递归算法。

#include <string>
#include <iostream>

using namespace std;


void string_permutation( std::string& orig, std::string& perm )
{
if( orig.empty() )
{
std::cout<<perm<<std::endl;
return;
}

for(int i=0;i<orig.size();++i)
{
std::string orig2 = orig;

orig2.erase(i,1);

std::string perm2 = perm;

perm2 += orig.at(i);

string_permutation(orig2,perm2);

}
}

int main()
{

std::string orig="1234";
std::string perm;

string_permutation(orig,perm);

cout<<"Complete!"<<endl;

system("pause");

return 0;
}
Generics 2007-04-13
  • 打赏
  • 举报
回复
这是用了stl里面标准算法的程序。

//Examples of using next_permutation

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>

using namespace std;


//using pointers
void display(char* c_str)
{
cout<<c_str<<endl;
}

int main()
{
char ca[]="1234";

display(ca);
for(int i=0;i<24-1;++i)
{
next_permutation(ca,ca+4);
display(ca);
}


return 0;
}
Generics 2007-04-13
  • 打赏
  • 举报
回复
这是用了递归的算法。

//This program uses vector permutation function
#include<iostream>
#include<vector>
#include<string>

using namespace std;

//using iterators
void display(vector<char> perm)
{
for(vector<char>::iterator it= perm.begin();it!=perm.end();++it)
cout<<*it;
cout<<endl;
}

//recursive template permutation function
//Note : func parameters must always be vector<T> !
template <typename T, typename Func>
void vector_permutation(std::vector<T>& now,
std::vector<T> next, Func func)
{
int size=now.size();
if(size>0)
{
for(int cnt=0; cnt<size;++cnt)
{
std::vector<T> vt;

std::vector<T>::const_iterator it=now.begin();
for(int cnt1=0;cnt1<size;++cnt1)
{
if(cnt1==cnt)
{
++it;
continue;
}
else
vt.push_back(*it);
++it;
}

std::vector<T>::const_iterator it1=now.begin();
for(int cnt2=1;cnt2<=cnt;++cnt2)
{
++it1;
}

next.push_back(*it1);
vector_permutation(vt,next,func);
next.pop_back();
}

}
else
{
func(next);
}
}

int main()
{
vector<char> ca;
ca.push_back('1');
ca.push_back('2');
ca.push_back('3');
ca.push_back('4');


vector<char> cnext;
vector_permutation(ca,cnext,display);

return 0;
}
deng2000 2007-04-13
  • 打赏
  • 举报
回复
生成1,2,...n的所有排列,这算是组合数学的一个经典问题了. 比较直观的方法是使用递归,如楼上几位给出的解法. 在编程时递归法是把双刃剑,威力强大但也有先天缺陷(如栈溢出). 因此如有可能用循环代替递归时,最好避免使用它. 前面taodm提到的使用STL中的next_permutation就可以达到这个目标.美中不足是,next_permutation的运行开销颇为昂贵(N!量级).

其实早在1973年S.Even就给出过一个简单的循环算法生成1..n的所有排列.可用C++程序表示如下:

#include <stdio.h>

#define LEFT -1
#define RIGHT 1

void Permute(int n);

int main()
{

Permute(5);
return 0;
}

int FindLargestMobile(int *array, char *arrow, int len)
{
int nPos = -1;
int nValue = -1;
for(int i=0; i<len ;i++)
{
int k = i + arrow[i];
if(k<0 || k>=len)
continue;
if(array[i] < array[k])
continue;
if (array[i] <= nValue)
continue;
nValue = array[i];
nPos = i;
}

return nPos;
}

bool Next(int *array, char *arrow, int len)
{
int nPos = FindLargestMobile(array, arrow, len);
if(nPos < 0)
return false;

int nValue = array[nPos];
// switch
int nAnother = nPos + arrow[nPos];
int nTmp = array[nPos];
array[nPos] = array[nAnother];
array[nAnother] = nTmp;
char cTmp = arrow[nPos];
arrow[nPos] = arrow[nAnother];
arrow[nAnother] = cTmp;

// change direction
for (int i=0; i<len; i++)
{
if(array[i] > nValue)
{
if(arrow[i] == LEFT)
arrow[i] = RIGHT;
else
arrow[i] = LEFT;
}
}
return true;
}


void PrintList(int *array, int len)
{
for(int i=0; i<len; i++)
printf("%d ", array[i]);
printf("\n");
}


void Permute(int n)
{
int* array = new int[n];
char *arrow = new char[n];
for(int i=0; i<n; i++)
{
array[i] = i+1;
arrow[i] = LEFT;
}

int nCount = 0;

while(true)
{
PrintList(array, n);
nCount ++;
if(!Next(array, arrow, n))
break;
}
printf("-------------------------\ntotal: %d permutes\n", nCount);
}
XphteR 2007-04-13
  • 打赏
  • 举报
回复
使用递归即可解决。从数据源中取数据每次的操作都是相同的。
xiaolh 2007-04-13
  • 打赏
  • 举报
回复
排列好组合完全是两回事
# include "stdio.h"
# include "stdlib.h"
#define N 3
int sum[]={1,2,3};
int flag[]={1,1,1};
int res[N]={0},r=0;

int p(int num)
{
if( num == 1 )
{
int i=0;
for(i=0;i<N;i++)
{
if(flag[i]==0)
{
continue;
}
res[r]=sum[i];
break;
}
for(i=0;i<N;i++)
{
printf("%d",res[i]);
}
printf("\n");

}
else
{
int i=0;
for(i=0;i<N;i++)
{
if(flag[i]==0)
{
continue;
}
res[r++]=sum[i];
flag[i]=0;
p(num-1);
flag[i]=1;
r--;
}
}
}
int main(void)
{
p(3);

system("pause");
}
amei_zhang83 2007-04-13
  • 打赏
  • 举报
回复
学习,还没有怎么看懂呢!!嗬嗬!!
Jim_King_2000 2007-04-13
  • 打赏
  • 举报
回复
想自己实现的话可以用递归.

void func(arr[], int size, int layer)
{
if (layer >= 8)
{
已生成好了全排列;
}
else
{
for (int i = 0; i < size; i++)
{
// 已经生成了layer个数,存放在arr[0] ~ arr[layer-1]中
// 生成第layer+1个数
if (layer > 0 && i与前面生成的数字重复)
continue;

arr[layer] = i;
func(arr, size, ++layer);
}
}
}
rainv 2007-04-13
  • 打赏
  • 举报
回复
mark一下
wwiilla 2007-04-13
  • 打赏
  • 举报
回复
算法与分析上的原题
void Perm( int list[],int k,int m ){
//产生list[k:m]的所有排列
if( k > m ){
for( int i = 0; i <= m ; i ++ )
cout << list[i] ;
cout << endl;
}
else
for( int i = k; i <= m; i ++ ){
Swap( list[k],list[i] );
Perm( list, k + 1, m );
Swap( list[k],list[i]);
}
}
void Swap( int &a,int &b ){
int temp = a;
a = b;
b = temp;
}
deng2000 2007-04-13
  • 打赏
  • 举报
回复
From sss_free()
我觉得deng2000() 应该跟我讲的本质上是一样的,你的两个数组相当于两个堆栈。如果没猜错你的LEFT RIGHT好比是图灵机上面读头的移动方向吧?正好验证了我的算法,因为带两个堆栈的下推自动机与一个图灵机等价。
-----------------------------------------------------------------

可能是一样的. 至于LEFT和RIGHT我只是照搬S.Even的想法:每个数带一个方向(左或右)来记住中间状态. 谢谢你的提醒, 这太象一个标准的图灵机了, 呵呵.
btw, 刚才发现我的程序中有个内存泄漏bug. 在Permute()函数最后应加上这两句:
delete [] array;
delete [] arrow;
fscd 2007-04-13
  • 打赏
  • 举报
回复
呵呵楼主的排列问题,用元素推移交换就可以了.
123
132
213
231
312
321

看清楚从123起,每次其实只需要交换或者推移一个数字而已.
C_walk 2007-04-13
  • 打赏
  • 举报
回复
确实挺难的,难在怎么建立一个庞大的数组,要不然还是很好解决的
sss_free 2007-04-13
  • 打赏
  • 举报
回复
我觉得deng2000() 应该跟我讲的本质上是一样的,你的两个数组相当于两个堆栈。如果没猜错你的LEFT RIGHT好比是图灵机上面读头的移动方向吧?正好验证了我的算法,因为带两个堆栈的下推自动机与一个图灵机等价。
加载更多回复(13)

65,213

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧