现在的位置: 首页 > 综合 > 正文

全排列算法总结

2018年05月18日 ⁄ 综合 ⁄ 共 2097字 ⁄ 字号 评论关闭

要研究一下算法,水平很差,只好各种向大神们学习了。。。然后写个总结,感谢各路大神!

一、全排列的递归算法

先上代码,乃懂的

<span style="font-size:14px;">#include<iostream>

using namespace std;

template <class T>
void Swap(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
	
}

template<class T>
void Perm(T list[], int begin, int end)
{
	
	if(begin == end)
	{
		for(int i = 0; i <= end; ++i)

		{
			cout << list[i] << " ";
		}
		cout << endl;
	}
	else
	{
		for (int i = begin; i <= end; ++i)
		{
			Swap(list[begin], list[i]);
			Perm(list, begin+1, end);
			Swap(list[begin], list[i]);
		}
	}
}
int main()
{
	int list[5] = {1,2,3,4,5};
	Perm(list, 0, 4);
	return 0;
}</span>

结果就不上图了...

分析如下:

1.假如我们只有两个数字:12.要对它进行全排列,第一种方式就是12本身,第二种,将12交换,变为21即可。这提示了我们一种交换的思路。

2.假如我们要对123进行全排列。我们可以采用将1固定,“23”进行全排列,将“2”固定,对“13”进行全排列。将“3”固定,对“12”进行全排列。

这其实就是首部为”1“,然后是“2”,然后是“3”,不就是第二位后边的数依次和第一位进行交换么?这是典型的递归的思路。

3.我们每次交换要将排列恢复成为原始的“123”,因为这个算法求排列的时候,前后并没有依赖性,其参考物只有“123”这个原始的第一个排列。否则,如果我们不恢复的话,就会出现,虽然数量与正确解法相同,但是会有重复的排列的现象。

二、全排列的非递归算法

继续先代码:

#include <iostream>

using namespace std;

template<class T>
void Swap(T &a, T &b)
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}

template<class T>
void Print(T *Array, int length)
{
    for (int i = 0; i < length; i++)
    {
        cout<<Array[i];
    }
    cout << endl;
}

template<class T>
bool NextSequence(T *Array, int length)
{
    int flag = 0;//标志位
	int i, j;
    int current;
    for (i = length-1; i > 0 ; i--)//从后往前找,直到找到某一个值,比其后相邻的值小。
    {
        if (Array[i-1] < Array[i])
        {
            flag = 1;//存在
            current = i-1;//记录位置
            break;
        }
    }
    if (flag == 1)
    {
        int temp = current+1;
        for (int i = current+1; i < length; i++)//在当前位置值的后面找恰好比这个值大的值
        {
            if (Array[i] < Array[temp] && Array[i] > Array[current])
            {
                temp = i;
            }
        }
        Swap(Array[temp], Array[current]);//然后交换
        
        //反向操作
        for (i = current+1, j = length-1; i < j; i++, j--)
        {
            Swap(Array[i], Array[j]);
        }
        return true;
    }
    return false;
}
int main()
{
    int Array[5] = {1,2,3,4,5};

    Print(Array, 5);
    while (NextSequence(Array, 5) == true)
    {
        Print(Array, 5);
    }
	return 0;
}

算法大体思路:

比如说有1234四个数字,要将这四个数字实现全排列。“1234”当然是第额一个排列,第二个排列,选取刚好比它大的,我们用大脑当然想的到是“1243”,然后思路如下:

1.从后往前寻找,即沿着4->3->2->1的方向寻找,直到找到某一个数,它比后面的那个数字小。在“1234”中,我们找到了3,因为3比4小,然后将3和4交换就得到比刚好比"1234"大的一个新全排列为"1243".

2.但是这样有bug。。。比如:在某一个时间,我们产生了一个新的排列:“2143”。依据刚才的思路,我们很容易找了1比4小,然后我们将1和4交换了,得到“2413”.这真的是刚好比“2143”大的全排列么?不是,而是“2314”。所以不是让1和紧挨着他的4交换,而是让1和其后最小的比1大的数交换,“4”和“3”,刚好比“1”大的数字应该是3,所以,我们让“1”和“3”交换,得到“2341”。

3.接着,发现还是有bug,应该是“2314”啊。。因为交换后,“3”这个位置以后的数,当然都是从大到小排列的。。只要做一次反向操作就好了。。即将“41”反向,变为“14”。。好了,就得到“2314”了。。

这解释,给力啊!

抱歉!评论已关闭.