鉴于笔者技术有限,此算法在数据规模大于8个时会花费较多时间~_~。
先贴个代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int fac(int n)//计算阶乘
{
int result=1;
for (int i = n; i > 0; i--)
{
result *= i;
}
return result;
}
void change(int* a, int* b)//交换函数
{
int c;
c = *b;
*b = *a;
*a = c;
}
void bubble_sort(int* arrange,int n)//排序
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (arrange[j] > arrange[j + 1])
change(arrange+j, arrange+j+1);
}
}
}
void tran_arrange(int* arrange, int j, int n)//改变排列
{
if (j == 0)//自然顺序做首项
{
return;
}
if (n == 2)
{
change(arrange, arrange + 1);
}
else if(n == 3)//等于3做奇偶不同的对换
{
if (j % 2 == 0)
{
change(arrange, arrange + 1);
}
else if (j % 2 == 1)
{
change(arrange + 1, arrange + 2);
}
}
else //大于3递归
{
if (j % fac(n - 1) == 0)//在后面数循环结束后,调换首数和后面一个数,产生新的组合
{
int tmp = j;
if (tmp > fac(n))
tmp = tmp % fac(n);//tmp要在fac(n)内,防止(1)越界
bubble_sort(arrange + 1,n-1);//排序方便调换
if (tmp == 0)//自然顺序做首排列,第0次
{
return;
}
if (tmp == fac(n - 1))
change(arrange, arrange + n - 1);//调换算法,第一次换最后一位
else
change(arrange, arrange + n - (tmp / fac(n - 1)) + 1);//(1)之后“/”
}
tran_arrange(arrange+1,j,n-1);
}
}
int main()
{
int n = 0;
printf("请输入排列规模:>");
scanf("%d", &n);
int* arrange = (int*)malloc(sizeof(int) * n);
if (arrange == NULL)
{
printf("%s", strerror(errno));
}
for (int i = 0; i < n; i++)
{
*(arrange+i) = i;
}//赋值
for (int j = 0; j < fac(n); j++)
{
tran_arrange(arrange,j,n);
printf("%d:", j);
for (int i = 0; i < n; i++)
{
printf("%d ",*(arrange + i));
}
printf("\n");
}
free(arrange);
arrange = NULL;
return 0;
}
本文将从辅助函数,主要函数,main函数展开叙述
1.辅助函数
辅助函数过于简单,在此不做过多赘述
int fac(int n)//计算阶乘
{
int result=1;
for (int i = n; i > 0; i--)
{
result *= i;
}
return result;
}
void change(int* a, int* b)//交换函数
{
int c;
c = *b;
*b = *a;
*a = c;
}
void bubble_sort(int* arrange,int n)//排序
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (arrange[j] > arrange[j + 1])
change(arrange+j, arrange+j+1);
}
}
}
2.主要函数——实现全排列
先说一下基本思路:
对于一个排列:0 1 2
我找到一种交换方法,在奇数次交换前两个数,在偶数次交换后两个数,在6次交换后,就能够得到这三个数的全排列,看看代码:
if (j == 0)//自然顺序做首项
{
return;
}
if(n == 3)//等于3做奇偶不同的对换
{
if (j % 2 == 0)
{
change(arrange, arrange + 1);
}
else if (j % 2 == 1)
{
change(arrange + 1, arrange + 2);
}
}
运行结果
那么,对于4个数的规模排列,我们便可以采取递归的方式,使只交换最后3个数实现新的排列。
并且,在后3个数的6种情况交换完成后,把后面3个数中的一个数与第一个数交换,完成新的6种排列。
而大于4个数的n个数排列,便递归成n-1,n-2,一直到4个数,在递归时我们只需要在合适的时机交换而产生新的n-1个数再重新排列就可以了。
这是算法的基本思想。
但是还有两个问题,对于在递归前的交换,一是什么时候进行交换,二是以什么的规律进行交换。
对于一问题,何时交换,当然是在后面所有数的所有情况都出现后,再进行换数,如下
也就是在(n-1)!时进行交换。
对于二问题,如何交换,我发现,在每次一组交换完成时,对最后的排序进行升序排序,再按照如下顺序交换,便可将后面所有数都交换一次。
这样,就完成了整个主要函数~_~,贴个代码
void tran_arrange(int* arrange, int j, int n)//改变排列
{
if (j == 0)//自然顺序做首项
{
return;
}
if (n == 2)
{
change(arrange, arrange + 1);
}
else if(n == 3)//等于3做奇偶不同的对换
{
if (j % 2 == 0)
{
change(arrange, arrange + 1);
}
else if (j % 2 == 1)
{
change(arrange + 1, arrange + 2);
}
}
else //大于3递归
{
if (j % fac(n - 1) == 0)//在后面数循环结束后,调换首数和后面一个数,产生新的组合
{
int tmp = j;
if (tmp > fac(n))
tmp = tmp % fac(n);//tmp要在fac(n)内,防止(1)越界
bubble_sort(arrange + 1,n-1);//排序方便调换
if (tmp == 0)//自然顺序做首排列,第0次
{
return;
}
if (tmp == fac(n - 1))
change(arrange, arrange + n - 1);//调换算法,第一次换最后一位
else
change(arrange, arrange + n - (tmp / fac(n - 1)) + 1);//(1)之后“/”
}
tran_arrange(arrange+1,j,n-1);
}
}
3.main函数
最后就很easy了,加一个scanf读取规模,进行动态分配。
int main()
{
int n = 0;
printf("请输入排列规模:>");
scanf("%d", &n);
int* arrange = (int*)malloc(sizeof(int) * n);
if (arrange == NULL)
{
printf("%s", strerror(errno));
}
for (int i = 0; i < n; i++)
{
*(arrange+i) = i;
}//赋值
for (int j = 0; j < fac(n); j++)
{
tran_arrange(arrange,j,n);
printf("%d:", j);
for (int i = 0; i < n; i++)
{
printf("%d ",*(arrange + i));
}
printf("\n");
}
free(arrange);
arrange = NULL;
return 0;
}
主要就是这样,最后贴个全部代码~_~! =
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int fac(int n)//计算阶乘
{
int result=1;
for (int i = n; i > 0; i--)
{
result *= i;
}
return result;
}
void change(int* a, int* b)//交换函数
{
int c;
c = *b;
*b = *a;
*a = c;
}
void bubble_sort(int* arrange,int n)//排序
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (arrange[j] > arrange[j + 1])
change(arrange+j, arrange+j+1);
}
}
}
void tran_arrange(int* arrange, int j, int n)//改变排列
{
if (j == 0)//自然顺序做首项
{
return;
}
if (n == 2)
{
change(arrange, arrange + 1);
}
else if(n == 3)//等于3做奇偶不同的对换
{
if (j % 2 == 0)
{
change(arrange, arrange + 1);
}
else if (j % 2 == 1)
{
change(arrange + 1, arrange + 2);
}
}
else //大于3递归
{
if (j % fac(n - 1) == 0)//在后面数循环结束后,调换首数和后面一个数,产生新的组合
{
int tmp = j;
if (tmp > fac(n))
tmp = tmp % fac(n);//tmp要在fac(n)内,防止(1)越界
bubble_sort(arrange + 1,n-1);//排序方便调换
if (tmp == 0)//自然顺序做首排列,第0次
{
return;
}
if (tmp == fac(n - 1))
change(arrange, arrange + n - 1);//调换算法,第一次换最后一位
else
change(arrange, arrange + n - (tmp / fac(n - 1)) + 1);//(1)之后“/”
}
tran_arrange(arrange+1,j,n-1);
}
}
int main()
{
int n = 0;
printf("请输入排列规模:>");
scanf("%d", &n);
int* arrange = (int*)malloc(sizeof(int) * n);
if (arrange == NULL)
{
printf("%s", strerror(errno));
}
for (int i = 0; i < n; i++)
{
*(arrange+i) = i;
}//赋值
for (int j = 0; j < fac(n); j++)
{
tran_arrange(arrange,j,n);
printf("%d:", j);
for (int i = 0; i < n; i++)
{
printf("%d ",*(arrange + i));
}
printf("\n");
}
free(arrange);
arrange = NULL;
return 0;
}