关于全排列的递归算法和非递归算法及内存优化

来源:互联网 发布:mac提取dsdt 编辑:程序博客网 时间:2024/06/04 08:57
  • 这位博友的发贴
  • leeyon415
string[] m_Data={"我","是","好","人"},

这里的 数组长度不一定4个,可能 10个 100个

我要返回所有 不重复 组合!如:
{"我","是","好","人"},
{"我","好","是","人"},
{"我","人","是","好"},
{"是","好","人","我"},
{"好","人","我","是"},
{"人","我","是","好"},
...
..

 

我的回复是(加上了注释):

 

      #region MyRegion 递归
        List<List<string>> GetAll(List<string> lst) {
            List<List<string>> lstRet = new List<List<string>>();
            if (lst == null || lst.Count < 2) {
                lstRet.Add(lst);
                return lstRet;
            }
          
            //只处理不小于2的情况
            List<string> a = lst.GetRange(0, lst.Count - 1);
            string b = lst[lst.Count - 1];

            lstRet.Add(a);
            if (a.Count == 1)  return GetAtom(lstRet, b);
           

            List<List<string>> temp =   GetAll(a);
            return GetAtom(temp, b);      
        }

 

        //得到基础排列的组合,最基本的是从两个元素开始的。

        //
        List<List<string>> GetAtom(List<List<string>> lst,string b){
            List<List<string>> lstRet = new List<List<string>>();
            if (lst == null) return lst;

            foreach (List<string> sub in lst) {
                for(int i = 0; i < sub.Count + 1;i++){
                    List<string> temp = new List<string>();
                    temp.AddRange(sub);
                    temp.Insert(i,b);
                    lstRet.Add(temp);
                }
            }

            return lstRet;
        }

 

        #endregion

 

 

下边的是调用 的代码,

  private void button1_Click(object sender, EventArgs e) {
  //init ,这是Demo数据,生成了10个数字,你可以调大一点,
  //不要太大哟,太大了堆栈会溢出
  List<string> lst = new List<string>(100);
  for (int i = 0; i < 10; i++) {
  lst.Add(i.ToString());
  }

  //返回值就是所有的组合,每个元素是List<string>,表示一种组合
  //
  List<List<string>> lstRet = this.GetN(lst);


  //这是输出结果的过程,
  if (lstRet == null) return;
  foreach (List<string> sub in lstRet) {
  if (sub == null || sub.Count == 0) continue;

  string sAll = "";
  foreach (string ss in sub) { 
  sAll += "," + ss;
  }

  Debug(sAll);
  }

  }


  //这里输出结果,随便 在窗体上加个 ListBox
  void Debug(string s) { 
           listBox1.Items.Add(s);
  }

 

 

 

        这个程序用递归实现,相当耗费资源(试下100个元素,但是,代码很简洁,不包括调用,稍改一下,20句代码应该可以搞定。

      暂时还没有时间改非递归,非递归也比较简单,就是递推。  用递推对资源的占用应该比较少。

 

以下是今天改过的非递归算法:

  这是非递归编写的代码,也比较简单,原理和递归有相似之处。
  从两个数的组合开始,递推到N个数。   
 
   

 #region MyRegion 递推
        List<List<string>> DoGetAll(List<string> lst) {
            List<List<string>> lstRet = new List<List<string>>();
            if (lst == null || lst.Count < 2) {
                lstRet.Add(lst);
                return lstRet;
            }

            List<List<string>> temp  = new List<List<string>>();
            for (int i = 0; i < lst.Count - 1; i++) {
                List<string> a = lst.GetRange(0, i + 1);
                string b = lst[i + 1];
                if (i == 0) temp.Add(a);

                temp = DoGetAtom(temp, b);
            }

            return temp;
        }

        List<List<string>> DoGetAtom(List<List<string>> lst,string b){
            List<List<string>> lstRet = new List<List<string>>();
            if (lst == null) return lst;

            foreach (List<string> sub in lst) {
                for(int i = 0; i < sub.Count + 1;i++){
                    List<string> temp = new List<string>();
                    temp.AddRange(sub);
                    temp.Insert(i,b);
                    lstRet.Add(temp);
                }
            }

            return lstRet;
        }

 

        #endregion        

 

以上代码其实有个深层次的问题,就是事实上它能计算的数据的范围是极其有限的。

如果解决大量集合的排列问题呢?
有很多方案,无法是以下几类:
(1)把内存装不下的数据移到外存中来处理
(2)分段处理,分而治之。
(3)1,2的结合。

其实,以上程序,只需要把 保存结果 的部分独立出来,单独做成一个数据结构(这个结构中存入的数据不受4G限制,事实上链表就可以),就可以解决本程序 的问题。


从执行效率上来看,这个程序是无法保证效率的。 可以对string, list进行优化,在大数量据时提高性能。


原创粉丝点击