软件设计师算法之回溯法--全排列

      全排列大家都知道。这里是通过最普遍的全排列,来理解回溯法的一个实现。最普通的全排列,比如A B C 三个字母,每个字母只能用一次,来进行排列,共有6种结果,比如ABC,ACD等。这个全排列结果和我们现实生活中N个人排队的可能性的结果是一样的。

      我这边的思路就是按照位置来进行,比如N个元素,首先第1个位置(索引为0)可以有N种选择,那么第二个位置有N-1种选择,倒数第二个位置有2种选择,最后一个位置只能有1种选择。

       当我们完成一次排列之后,回溯,首先回溯到倒数第二个位置,倒数第二个位置有2种选择,第一次排列已经用了其中一个选择,回溯之后,我们采用另外一个选择,最后一个位置也有一个选择,这样又完成了一次排列。

       完成第2个排列之后,我们再次回溯到倒数第二个位置,发现2种选择都试过了,那么回溯到倒数第3个位置,倒数第3个位置有3种选择,各个选择我们都用一遍之后,继续回溯到倒数第4个,如此回溯直到到第1个位置(索引为0,有N个选择)。N个选择都用一遍,直到把所有的排列情况都尝试了一遍。

        明显可以看出,整个回溯过程,其实就是图的深度优先搜索DFS。

        OK,下面是实现的代码:

#define STR_SIZE 6

char g_data[STR_SIZE] = {'A','B','C','D','E','F'};
char g_output[STR_SIZE] = {0};

unsigned int g_fullPermutationCount = 0;

void FullPermutationTest()
{
	FullPermutation(0);
	printf("\r\nTotal count of full permutation = %d\r\n",g_fullPermutationCount);
}

void PrintFullPermutation()
{
	printf("One of result:\r\n");
	for(int i=0;i<STR_SIZE;i++)
	{
		printf("%2c",g_output[i]);
	}
	printf("\r\n");
}

//判断index位置选择的元素在前面index-1个位置中是否有选择过
BOOL IsSelect(int index)
{
	for(int i=0;i<index;i++)
	{
		if(g_output[i] == g_output[index])
		{
			return TRUE;
		}
	}

	return FALSE;
}

void FullPermutation(int index)
{
	for(int i=0;i<STR_SIZE;i++)
	{
		g_output[index] = g_data[i];
		if(!IsSelect(index)) //表示前面index-1个位置都没有选择过该元素(g_data[i])
		{
			if(index == STR_SIZE-1) //全部位置都选择了,那么完成了一个排列
			{
				PrintFullPermutation();//输出排列
				g_fullPermutationCount++;
			}
			else
			{
				FullPermutation(index+1);//搜索下一个位置的排列
			}
		}
		//继续执行下一个循环,也就是回溯,尝试其他的可能性
	}
}


      测试结果如下:

      


        当然,实际情况的排列可能会有出现重复的字母(比如2个A,或者3个B),那么排列就不一样了。但是还是可以通过如上的回溯稍加变化来实现。

展开阅读全文

没有更多推荐了,返回首页