字典全排序问题

1.非递归方法(字典序法)求全排列

对给定的字符集中的字符规定了一个先后关系,在此基础上规定两个全排列的先后是从左到右逐个比较对应的字符的先后。

[例]字符集{1,2,3},较小的数字较先,这样按字典序生成的全排列是:

         123,132,213,231,312,321

※ 一个全排列可看做一个字符串,字符串可有前缀后缀

  生成给定全排列的下一个排列.所谓一个的下一个就是这一个与下一个之间没有其他的。这就要求这一个与下一个有尽可能共同前,也即变化限制在尽可能后缀上。

 一般而言,设P是[1,n]的一个全排列。
      P=P1P2…Pn=P1P2…Pj-1PjPj+1…Pk-1PkPk+1…Pn
    find:  j=min{i|Pi<Pi+1}
         k=max{i|Pi>Pj}
      1,  对换Pj,Pk,
      2,  将Pj+1…Pk-1PjPk+1…Pn翻转
          P’= P1P2…Pj-1PkPn…Pk+1PjPk-1…Pj+1即P的下一个

如何得到346987521的下一个
    1,从尾部往前找第一个P(i-1) < P(i)的位置
            3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1
        最终找到6是第一个变小的数字,记录下6的位置i-1
    2,从i位置往后找到最后一个大于6的数
            3 4 6 -> 9 -> 8 -> 7 5 2 1
        最终找到7的位置,记录位置为m
    3,交换位置i-1和m的值
            3 4 7 9 8 6 5 2 1
    4,倒序i位置后的所有数据
            3 4 7 1 2 5 6 8 9
    则347125689为346987521的下一个排列
private static void PermutationList()
        {
            int fromIndex, endIndex, changeIndex;
            Sort(0, length - 1);
            do
            {
                // 输出一种全排列
                Output();
                fromIndex = endIndex = length - 1;
                // 向前查找第一个变小的元素
                while (fromIndex > 0 && words[fromIndex] < words[fromIndex - 1]) --fromIndex;
                changeIndex = fromIndex-1;
                if (fromIndex == 0) break;
                // 向后查找最后一个大于words[fromIndex-1]的元素
                while (changeIndex+1< length && words[changeIndex+1] > words[fromIndex - 1]) ++changeIndex;
                Swap(fromIndex - 1, changeIndex);   // 交换两个值
                InvertArray(fromIndex, endIndex);   // 对后面的所有值进行反向处理
            } while (true);
        }

2.递归方法求全排列

分别将每个位置交换到最前面位,之后全排列剩下的位。

递归全排列 1 2 3 4 5
    1,for循环将每个位置的数据交换到第一位
            swap(1,1~5)
    2,按相同的方式全排列剩余的位。
    3, 一次全排列完后需要再次交换回去,准备下一次全排列。

  /// 递归方式生成全排列的方法
        /// </summary>
        /// <param name="fromIndex">全排列的起始位置</param>
        /// <param name="endIndex">全排列的终止位置</param>
        private static void PermutationList(int fromIndex, int endIndex)
        {
            if (fromIndex == endIndex)
                Output();
            else
            {
                for (int index = fromIndex; index <= endIndex; ++index)
                {
                    // 此处排序主要是为了生成字典序全排列,否则递归会打乱字典序
                    Sort(fromIndex, endIndex);
                    Swap(fromIndex, index);
                    PermutationList(fromIndex + 1, endIndex);
                    Swap(fromIndex, index);   // 需要交换回去进行下一次全排列
                }
            }
        }

所有详细代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Algorithms
{
    class Permutation
    {
        private static int MAXLENGTH = 20;

        private static int length;
        private static char[] words = new char[MAXLENGTH];

        private static void Swap(int indexX, int indexY)
        {
            if (indexX != indexY)
            {
                char ch = words[indexX];
                words[indexX] = words[indexY];
                words[indexY] = ch;
            }
        }

        private static void InvertArray(int fromIndex, int endIndex)
        {
            for (; fromIndex < endIndex; ++fromIndex, --endIndex)
                Swap(fromIndex, endIndex);
        }

        private static void Sort(int fromIndex, int endIndex)
        {
            Array.Sort(words, fromIndex, endIndex - fromIndex + 1);
        }

        private static void Output()
        {
            for (int index = 0; index < length; ++index)
                Console.Write(words[index] + " ");
            Console.WriteLine();
        }

        private static void PermutationList()
        {
            int fromIndex, endIndex, changeIndex;
            Sort(0, length - 1);
            do
            {
                // 输出一种全排列
                Output();
                fromIndex = endIndex = length - 1;
                // 向前查找第一个变小的元素
                while (fromIndex > 0 && words[fromIndex] < words[fromIndex - 1]) --fromIndex;
                changeIndex = fromIndex;
                if (fromIndex == 0) break;
                // 向后查找最后一个大于words[fromIndex-1]的元素
                while (changeIndex + 1 < length && words[changeIndex + 1] > words[fromIndex - 1]) ++changeIndex;
                Swap(fromIndex - 1, changeIndex);   // 交换两个值
                InvertArray(fromIndex, endIndex);   // 对后面的所有值进行反向处理
            } while (true);
        }

        /// <summary>
        /// 递归方式生成全排列的方法
        /// </summary>
        /// <param name="fromIndex">全排列的起始位置</param>
        /// <param name="endIndex">全排列的终止位置</param>
        private static void PermutationList(int fromIndex, int endIndex)
        {
            if (fromIndex == endIndex)
                Output();
            else
            {
                for (int index = fromIndex; index <= endIndex; ++index)
                {
                    // 此处排序主要是为了生成字典序全排列,否则递归会打乱字典序
                    Sort(fromIndex, endIndex);
                    Swap(fromIndex, index);
                    PermutationList(fromIndex + 1, endIndex);
                    Swap(fromIndex, index);
                }
            }
        }

        public static void PermutationTest()
        {
            Console.Write("please input the permutation words:");
            words = Console.ReadLine().ToCharArray();
            length = words.Count();
            PermutationList();
            Console.ReadLine();
        }
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值