用分治法求最大子项

2018-08-16  本文已影响8人  eagleif
/**
 * 分治法求最大子数组
 *
 * @author -lw
 * @date -2018/8/15
 * @note -
 * ---------------------------------------------------------------------------------------------------------------------
 * @modified -
 * @date -
 * @note -
 */
public class Main {
    /**
     * 入口
     *
     * @param args 参数
     */
    public static void main(String[] args) {
        double[] array = {-0, -20, 9, -10, -7, -6, 7, 5, 10, -8};
        MaxItem maxItem = findMaxiMumSubArray(array, 0, array.length - 1);
        System.out.println(maxItem.toString());
    }

    /**
     * 获取没有交叉的数组的数据的最大数组项
     *
     * @param array 数组
     * @param low   左边位置
     * @param high  右边位置
     * @return 结果
     */
    private static MaxItem findMaxiMumSubArray(double[] array, int low, int high) {
        MaxItem result = new MaxItem();
        if (low == high) {
            result.start = low;
            result.end = high;
            result.sum = array[low];
        } else {
            int middle = (low + high) / 2;
            //数组中间位置的左边的最大子项
            MaxItem resultLeft = findMaxiMumSubArray(array, low, middle);
            //数组中间位置的右边的最大子项
            MaxItem resultRight = findMaxiMumSubArray(array, middle + 1, high);
            //中间位置在数组里面的数组的最大子项
            MaxItem resultMiddle = findMaxCrossingSubarray(array, low, middle, high);
            if (resultLeft.sum >= resultRight.sum && resultLeft.sum >= resultMiddle.sum) {
                return resultLeft;
            } else if (resultRight.sum >= resultLeft.sum && resultRight.sum >= resultMiddle.sum) {
                return resultRight;
            } else {
                return resultMiddle;
            }
        }
        return result;
    }

    /**
     * 获取交叉的数组的数据的最大数组项
     *
     * @param array  数组
     * @param low    左边位置
     * @param middle 中间位置
     * @param high   右边位置
     * @return 结果
     */
    private static MaxItem findMaxCrossingSubarray(double[] array, int low, int middle, int high) {
        double leftSum = 0;
        double sum = 0;
        int maxLeft = Integer.MAX_VALUE;
        //注意这里是从middle位置向左做加法(因为最后要将中点左右两边的最大子项加起来)
        for (int i = middle; i >= low; i--) {
            sum = sum + array[i];
            if (sum > leftSum) {
                leftSum = sum;
                maxLeft = i;
            }
        }
        double rightSum = 0;
        sum = 0;
        int maxRight = Integer.MAX_VALUE;
        //注意这里是从middle位置向右做加法(因为最后要将中点左右两边的最大子项加起来)
        for (int j = middle + 1; j <= high; j++) {
            sum = sum + array[j];
            if (sum > rightSum) {
                rightSum = sum;
                maxRight = j;
            }
        }
        MaxItem maxItem = new MaxItem();
        maxItem.start = maxLeft;
        maxItem.end = maxRight;
        maxItem.sum = leftSum + rightSum;
        return maxItem;
    }

    /**
     * 用于存储最大项的数据
     */
    private static class MaxItem {
        /** 开始的位置 */
        public int start;
        /** 结束的位置 */
        public int end;
        /** 最大项的数据的和 */
        public double sum;

        @Override
        public String toString() {
            return "MaxItem{" + "start=" + start + ", end=" + end + ", sum=" + sum + '}';
        }
    }


}

算法导论中的伪代码转换而来的Java语言实现的求最大子项的实现

上一篇下一篇

猜你喜欢

热点阅读