码迷,mamicode.com
首页 > 编程语言 > 详细

使用Java实现一则算法

时间:2017-04-16 22:40:12      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:技术分享   分享   需要   使用   pos   补充   toc   循环   技术   

【Java】 使用Java实现一则算法

前情提要

在学习Java的过程中,我的一个基友扔给了我一道算法题,为了检验自己对Java的学习情况我决定使用Java解决这道算法题。


具体问题

现有一株K叉树,我们知道其前序遍历与后序遍历,也知道K的值,求该K叉树有多少种可能形态。如一13叉树,前序遍历为abejkcfghid,后序遍历为jkebfghicda,则其可能形态有207352860种。


问题分析

根据遍历的定义我们可以知道:

  1. 前序遍历的第一个字母和后序遍历的最后一个字母是他的根。

  2. 前序遍历的根的后一个字母是它最左边的子树。

  3. 后续遍历的根的前一个字母是它最右边的子树。

以题目为例:(这里我们从后序遍历入手)

  1. a为该树的根,d为a的最右子树,其余字母都是a的后裔;

  2. 以d为根,在前序遍历中d右边的为d的后裔(无);d左边的为d的兄弟及其后裔(即bejkcfghi),其中c为除了d外a的最右子树。

  3. 以c为根,在前序遍历中c右边的为c的后裔(即fghi), c左边的为c左边的兄弟及其后裔(即bejk),c的后裔的前序遍历为fghi,后序遍历为fghi,i为c的最右子树;c的左边的兄弟及其后裔的前序遍历为bejk,后序遍历为jkeb。b为除了d,c外a的最右子树;

  4. 先处理c左边的兄弟及其后裔,可知b为a的子树,c、d的兄弟;e为b的子树;j、k为e的子树;

  5. 处理c的后裔,根据上述处理方法易得f、g、h、i都是c的子树;

技术分享

  • 如图所示,可见a有3个子树,b有1个子树,c有4个子树,e有2个子树。因为是13叉树,当一个根节点有n个子树,则该结点与子树的排列可能性为C(n,13),故该13叉树总的可能形态有C(3,13)* C(1,13)* C(4,13)* C(2,13) = 207352860。

  • 总结以上过程,我们需要的东西是一个能将K叉树不断拆分,能求出每一个根节点子树数量的方法。


程序实现

首先,我们要明白我们需要什么:

  1. 一个main类,里面能初始化我们所需要的数据,包括题目给出的K,前序遍历和后序遍历,最好还能最后处理结果并输出。

  2. 在分析过程中我们需要用到大量的C(n,k),如果每个C(n,k)都单独运算的话非常麻烦,我们可以用一个数组计算并存储它们。

  3. 下面自然是重头戏了,通过方法实现算法。这个方法:

1.需要能根据给定的前序遍历和后序遍历判定出根节点;

2.通过根节点拆分前序遍历和后序遍历,同时计算每个根节点子树的数量;

3.能够调用自己,因为拆分自己是要不断循环的,此外我们还需要一个数组用于记录有多少个根,每个跟有多少个子树,这个数组显然是应该独立在方法外的。


实际程序

public class qianhou {                         //主类
  public static void main(String[] args){
    String qian = "abejkcfghid";               //初始化输入
    String hou = "jkebfghicda";
    byte k = 13;    
    long poss = 1;                             //结果
    char [] dlr = qian.toCharArray();          //Java中对String类型利用复杂,转化成char数组方便操作
    char [] lrd = hou.toCharArray();           //dlr前序遍历,lrd后序遍历
    Jisuan a1 = new Jisuan();                 
    int[] zuh=a1.setarray(k);                  //将方法计算的组合数结果
    a1.find(dlr,lrd);                       
    for (int i=1; i<a1.ccount+1; i++){         //计算结果
        poss = poss * zuh[a1.acco[i]];
    }
    System.out.println(poss);
  }
}

 class Jisuan{

    int[] acco = new int[10000];               

    //新建数组记录根节点子树个数(也可以用ArrayList,虽然给ArrayList数组内的值++比较麻烦,但可以控制数组大小。注意不能写在方法中

    int ccount = 0;                            //acco数组指针


    public int[] setarray(byte k){             //记录C(n,k)值的数组
        int[] zuhe = new int[k+1];
        zuhe[0] = 1;
        for (int i=1; i<=k; i++){
              zuhe[i] = 1;
              zuhe[i] =zuhe[i-1]*(k+1-i)/i;
        }   
        return zuhe;
    }   


    public void find(char[] dlr , char[] lrd){ //调用对象应为前序遍历与后序遍历,因为有完整的信息

        int i1 = 0, i2=0, i3 = 0;              //初始化指针

        int l = dlr.length;                    //初始化遍历长度   

        while (dlr[i1] != lrd[l-1]){           //寻找前序遍历中的最右子树位置
          i1++; 
        }

        //此处由于时间关系,未使用try校验初始条件是否合理,应该补充

        if (l != 1){                           //如长度为1则无子树,不需要继续分割
            if (i1!=0){                        //如果最右子树在前序遍历中位置不为0,说明无左侧兄弟及其后裔,左侧无需分割
                char[] ldlr = new char[i1];    //将左侧兄弟及其后裔的前序遍历与后序遍历分割分割
                char[] llrd = new char[i1];
                for (i2=0; i2<i1;i2++){
                    ldlr[i2] = dlr[i2];
                    llrd[i2] = lrd[i2];
                }
                acco[ccount] = acco[ccount]+1; //根下子树数量+1
                find(ldlr,llrd);               //先分割左侧兄弟及其后裔,先遍历根的所有兄弟,无需大量调控记录数组的指针
            }
            if (i1!=l-1){                      //如果最右子树在前序遍历中位置不为末尾,说明无后裔,右侧无需分割
                char[] rdlr = new char[l-i1-1];//将其后裔的前序遍历与后序遍历分割分割
                char[] rlrd = new char[l-i1-1];
                for (i3=0; i3<l-i1-1;i3++){
                    rdlr[i3] = dlr[i3+1+i1];
                    rlrd[i3] = lrd[i3+i1];
                }
                ccount++;                      //数组指针指向下一个根
                acco[ccount] = 1;              //根下子树数量+1
                find(rdlr,rlrd);
            }
        }
    }
 }

总结

Java虽然并不适合用来写算法,但是就是因为这重重障碍和限制条件,写起算法来能遇到更多的问题,在解决这些问题的过程中,反而能更加深入的理解Java的内在逻辑和自身的缺陷。

  • 这大概就是所谓的时间是检验真理的唯一标准了吧...

使用Java实现一则算法

标签:技术分享   分享   需要   使用   pos   补充   toc   循环   技术   

原文地址:http://www.cnblogs.com/squallmoon/p/6720165.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!