递归和非递归算法实现的全排列类库

/* ----------------------------------------------------------
 * 文件名称:FullPermutation.cs
 * 
 * 作者:秦建辉
 * 
 * QQ:36748897
 * 
 * 版本历史:
 *      V1.0	2011年06月22日
 *              递归和非递归算法实现的全排列类库
 *              
 * 参考资料:
 *      http://plutoblog.iteye.com/blog/976216
 *      http://tieba.baidu.com/f?kz=12248706
 * ------------------------------------------------------------ */
using System;
using System.Collections.Generic;

namespace Splash
{
    /// <summary>
    /// 递归和非递归实现按顺序输出的全排列类库
    /// </summary>
    public static class FullPermutation
    {
        /// <summary>
        /// 递归实现的按顺序输出的全排列数组列表
        /// </summary>
        /// <param name="index">起始索引号</param>
        /// <param name="length">元素个数</param>
        /// <returns>全排列数组列表</returns>
        public static List<Int32[]> Seed(Int32 index, Int32 length)
        {
            if (length <= 0) return null;

            Int32[] used = new Int32[length];
            Int32[] result = new Int32[length];
            List<Int32[]> list = new List<Int32[]>();

            Array.Clear(used, 0, length);   // 初始化
            Proc(0, index, length, list, used, result);

            return list;
        }

        // 递归实现
        private static void Proc(Int32 step, Int32 index, Int32 length, List<Int32[]> list, Int32[] used, Int32[] result)
        {
            if (step == length)
            {
                list.Add((Int32[])result.Clone());  // 注意:克隆数组
            }
            else
            {
                for (Int32 i = 0; i < length; i++)
                {
                    if (used[i] == 0)   // 未处理
                    {
                        used[i] = 1;
                        result[step] = index + i;
                        Proc(step + 1, index, length, list, used, result);
                        used[i] = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 非递归实现的按顺序输出的全排列迭代器
        /// </summary>
        /// <param name="index">起始索引号</param>
        /// <param name="length">元素个数</param>
        /// <returns>全排列迭代器</returns>
        /// <remarks>
        /// 基本思想:
        ///     1. 找到所有排列中最小的一个排列P
        ///     2. 找到刚刚好比P大比其它都小的排列Q
        ///     3. 循环执行第二步,直到找到一个最大的排列,算法结束
        /// </remarks>
        public static System.Collections.IEnumerable Cell(Int32 index, Int32 length)
        {
            if (length <= 0)
            {   // 迭代结束
                yield break;
            }
            else if (length == 1)
            {   // 只有一个元素
                yield return new Int32[] { index };
            }
            else
            {   // 生成一个最小排列
                Int32[] A = new Int32[length];
                for (Int32 i = 0; i < length; i++)
                    A[i] = index + i;

                while (true)
                {
                    yield return A;

                    Int32 i, j;

                    // 从后向前找出不符合从大到小的元素A[i]
                    for (i = length - 2; i >= 0; i--)
                    {
                        if (A[i] < A[i + 1])
                            break;
                        else if (i == 0)
                            yield break;    // 所有元素都满足从大到小,迭代结束
                    }

                    // 从后向前找出比其大的元素A[j]
                    for (j = length - 1; j > i; j--)
                    {
                        if (A[j] > A[i]) break;
                    }

                    // 交换A[i]和A[j]
                    A[i] ^= A[j];
                    A[j] ^= A[i];
                    A[i] ^= A[j];

                    // 反转后面的元素,使A[i]后面的元素变成最小排列
                    Array.Reverse(A, i + 1, length - i - 1);
                }
            }
        }
    }
}

调用示例:

using System;
using System.Collections.Generic;

namespace Splash
{
    class Program
    {
        static void Main(string[] args)
        {
            String s = "abcde";

            // 测试全排列列表
            Console.WriteLine("测试全排列列表");
            List<Int32[]> list = FullPermutation.Seed(0, 3);
            if (list != null)
            {
                foreach (Int32[] item in list)
                {
                    for (Int32 i = 0; i < item.Length; i++)
                    {
                        if (i != 0) Console.Write(" ");
                        Console.Write(s[item[i]]);
                    }
                    Console.WriteLine();
                }
            }

            // 测试迭代器
            Console.WriteLine();
            Console.WriteLine("测试迭代器");
            foreach (Int32[] item in FullPermutation.Cell(0, 3))
            {
                for (Int32 i = 0; i < item.Length; i++)
                {
                    if (i != 0) Console.Write(" ");
                    Console.Write(s[item[i]]);
                }
                Console.WriteLine();
            }
        }
    }
}

Comments are closed.