上得厅堂,下得厨房,写得代码,翻得围墙。欢迎来到睿不可挡的每日一小练!

题目:按字典顺序列出全部排列

内容:请写一个程序,用字典顺序列出n个元素的全部排列

这个问题有点小复杂,不是太好想。反正我是想了好久

看到这个题目我先是想到的就是递归由于这个题目就是用指针对高位选择,然后将指针传给临近的低位再选择。

只是细致研究原来没这么简单

以n=4举例当处理以1开头的排列时1234到1432,可是在排列2开头的时候不太好建立统一的递归关系。

(没办法太统一的递归方法中将后面的数字选出来),所以将第一位分类数字经行单独处理,事实上第一位数字的选择也是又规律可循的。

1234  1432  

2134  2431

3124  3421

4123  4321

12345  15432

21345  25431

....

能够看出1和2换时2都在最后一位,2和3换时,3在倒数第二位。。

就是你换第i个数时,就在倒数第i-1位。

然后我们再来处理除第一位的排列即从i,1,2,3,4,..i-1,i+i,..n(如果第一位是i)到i,n,...i+1,i-1,...3,2,1。

的排列

事实上这里也是有规律的。就是先从后向前查找第一个顺序相邻的位置然后交换,然后对交换后面的排列逆序。

(事实上这就是分解了我们人类排序的步骤,仅仅是人的智能比較快。我们感受不到)。

比方 21354 从后向前第一个顺序相邻是35交换53为21534然后对后面逆序21435就是21354的后面一个数了。

当数列中没有顺序相邻了。我们的排列就结束了

如 4321,54321。

所以我们就能够依照这个规律来编敲代码了。


#include <iostream>
using namespace std;

int set[1000];
bool signal = false;
int n;

int _tmain(int argc, _TCHAR* argv[])
{
void changeFirst();
cout << "请输入排列的集合的最大整数n:" << endl;
cin >> n;
for (int i = 0; i < n; i++)
{
set[i] = i + 1;
}
cout << "该集合的全部排列为:" << endl;
changeFirst();
getchar();
getchar();
return 0;
}

void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}

void reverse(int index_Start, int index_End)
{
int length = index_End - index_Start;
for (int i = 0; i <= length / 2; i++)
swap(set[i + index_Start], set[length - i + index_Start]);

}

void permutationSet()
{
for (int x = 0; x < n; x++)
cout << set[x] << " ";
cout << endl;
signal = false;
int i, j, k;
for (i = n - 2; i>0; i--)
if (set[i]<set[i + 1])
{
j = i + 1;
signal = true;
break;
}
if (signal == false)
return;
for (k = n - 1; k>0; k--)
if (set[k]>set[i])
break;
swap(set[i], set[k]);
reverse(j, n - 1);
permutationSet();
}

void changeFirst()
{
int i = n - 1;
while (i >= 0)
{
permutationSet();
swap(set[0], set[i]);
reverse(1, n - 1);
i--;
}
}


实验结果

每日一小练——按字典顺序列出全部排列_递归方法


欢迎大家增加每日一小练。嘿嘿!

每天练一练,日久见功夫,加油。



            -End-