全排列

全排列

1.类似于C++STL库中的全排列

abc 的全排列: abc, acb, bac, bca, cab, cba
123 的全排列: 123, 132, 213, 231, 312, 321
思想参考自:http://blog.csdn.net/morewindows/article/details/7370155?reload
剑指offer P155,此外全排列还可以用以解决8皇后问题,对于按照一定要求摆放若干数字,都可以考虑用全排列解决。
全排列就是从第一个数字起每个数分别与它后面的数字交换。
1:从后向前找第一对相邻的递增数对,前一个数replaced为被替换数
2:再由后向前找第一个比被替换数大的数,然后与被替换数交换。
3:最后反转被替换数之后的所有数据。此时完成一次排列

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp(void const *a, void const *b)
{
	char *c = (char *)a;
	char *d = (char *)b;

	return (*c > *d) ? 1: -1;
}

void swap(char *a, char *b)
{
	char tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

/*反转字符串*/
void reverse(char *left, char *right)
{
	while (left < right)
	{
		swap(left++, right--);
	}
}

int next_permutation(char *start, char *end)
{
	char *replaced, *p, *find;

	/*因为是排好序的,两个元素时直接结束*/
	if (start == --end)
	{
		return 0;
	}

	replaced = end;

	while (replaced != start)
	{
		p = replaced--;

		if (*replaced < *p) /*从后向前找第一对相邻的递增数对,前一个数replaced为被替换数*/
		{
			find = end;

			while (*find <= *replaced) /*从后向前找第一个比被替换数大的替换数*/
			{
				--find;
			}

			swap(replaced, find);
			reverse(p, end); /*被替换数之后的数全部反转*/
			return 1;
		}
	}

	reverse(start, end); /*这一句是为了和STL中的next_permutation一致,还原到最小的排列状态*/
	return 0;
}

int main(void)
{
	char str[10];

	while (scanf("%s", str) != EOF)
	{
		int len = strlen(str);

		qsort(str, len, sizeof(char), cmp); /*递增排序*/

		printf("全排列如下:\n");

		do
		{
			puts(str);
		}while (1 == next_permutation(str, str+len)); /*接着使用交换后的序列计算*/
	}

	return 0;
}


1.类似于C++STL库中的全排列去重的全排列:就是从第一个数字起每个数分别与它后面非重复出现的数字交换,王道程序员求值宝典P239。但是这个不满足字典顺序
*/去重的全排列:就是从第一个数字起每个数分别与它后面非重复出现的数字交换,王道程序员求值宝典P239。但是这个不满足字典顺序
*//*
*去重的全排列:就是从第一个数字起每个数分别与它后面非重复出现的数字交换,王道程序员求值宝典P239。但是这个不满足字典顺序
*//*
*去重的全排列:就是从第一个数字起每个数分别与它后面非重复出现的数字交换,王道程序员求值宝典P239。但是这个不满足字典顺序
*/1.去重的全排列:就是从第一个数字起每个数分别与它后面非重复出现的数字交换,王道程序员求值宝典P239。但是这个不满足字典顺序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp(const void *a, const void *b)
{
	char *c = (char *)a;
	char *d = (char *)b;

	return (*c > *d) ? 1: -1;
}

void swap(char *a, char *b)
{
	char tmp = *a;
	*a = *b;
	*b = tmp;
}

/*在str数组中,[begin,end)中是否有数字与下标为end的数字相等*/
int euqal(char *str, int begin, int end)
{
	int i;
	for (i=begin; i<end; i++)
	{
		if (str[i] == str[end])
		{
			return 1;
		}
	}

	return 0;
}

/*k表示当前选取到第几个数,m表示共有多少数*/
void perm(char *str, int k, int m)
{
	int i;

	if (k == m)
	{
		printf("%s\n", str);
	}
	else
	{
		for (i=k; i<=m; i++) /*第i个数分别与它后面的数字交换就能得到新的排列*/
		{
			if ( 0 == euqal(str, k, i) )
			{
				swap(&str[k], &str[i]);
				perm(str, k+1, m);
				swap(&str[k], &str[i]);
			}
		}
	}
}

int main(void)
{
	char str[10];

	while(scanf("%s", str) != EOF)
	{
		int len = strlen(str);
		qsort(str, len, sizeof(char), cmp); /*递增排序*/

		printf("全排列如下:\n");
		perm(str, 0, len-1);
	}

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值