基于c语言简单实现全排列

鉴于笔者技术有限,此算法在数据规模大于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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值