【问题标题】:Does my merge sort implementation has divide and conquer?我的合并排序实现有分而治之吗?
【发布时间】:2017-03-19 17:08:02
【问题描述】:

我在一次采访中被告知要根据分而治之的概念编写一个实现归并排序的程序。

我写了下面的程序,

var myGlobalArray = undefined;

myGlobalArray = [8,4,17,2,1,32];
example01(myGlobalArray);

myGlobalArray = [48,14,17,2,11,132];
example01(myGlobalArray);

myGlobalArray = [45,14,5,2,1,12];
example01(myGlobalArray);

myGlobalArray = [45,-14,-5,2,1,-12];
example01(myGlobalArray);

myGlobalArray = [38,27,43,3,9,82,10];
example01(myGlobalArray);


function example01(myArray){
   var mainArray = [];

   createSubArray(myArray,0);

   mainArray = mergeArrays(mainArray);
   console.log(mainArray[0]);

   // creates an array which contains n arrays for n numbers present in myarray
   // i.e. if array = [ 34, 1, 27, 3 ] that the below method will return
   // [ [34], [1], [27], [3] ]
   function createSubArray(subArray,index){
        var localArray = [];

        if(subArray[index] !== undefined){
            localArray.push(subArray[index]);
            mainArray.push(localArray);
            createSubArray(subArray,++index);// performs division recursively   
        }       
   }//createSubArray


   // merge the arrays present i.e. 
   // if gblArray = [ [2,5], [1,7] ] 
   // then the below method will return
   // an merged array [ [1, 2, 5, 7] ]
   function mergeArrays(gblArray){
        var mergedArrays = [],
            main_array = gblArray,
            arr = [], 
            counter = 0, 
            nextCounter = 0;

        do{

            while(counter < main_array.length){
                nextCounter = counter + 1;

                if(main_array[nextCounter] !== undefined){
                    arr = mergeAndSort(main_array[counter],main_array[nextCounter]);    
                    mergedArrays.push(arr);
                }else{
                    mergedArrays.push(main_array[counter]);
                }
                counter = nextCounter + 1;
            }

            main_array = mergedArrays;
            mergedArrays = [];  
            counter = 0;
            nextCounter = 0;

        }while(main_array.length > 1);

        return main_array;
   }//mergeArrays


   // merges two array and sorts i.e.
   // if array1 = [23,1] and array2 = [4,12] than
   // the below method returns [1,4,12,23]
   function mergeAndSort(array1,array2){
        var array2Counter = 0, 
            array1Counter = 0, 
            mergedArray = [];

        while(array2Counter < array2.length && array1Counter < array1.length){

            if(array2[array2Counter] < array1[array1Counter]){
                mergedArray.push(array2[array2Counter]);
                array2Counter++;
            }else{
                mergedArray.push(array1[array1Counter]);
                array1Counter++;
            }
        }

        while(array1Counter < array1.length){
            mergedArray.push(array1[array1Counter]);
            array1Counter++;
        }

        while(array2Counter < array2.length){
            mergedArray.push(array2[array2Counter]);
            array2Counter++;
        }

        return mergedArray;
   } //mergeAndSort



}//example01

如果我运行上面的代码, 输出是

[ 1, 2, 4, 8, 17, 32 ]
[ 2, 11, 14, 17, 48, 132 ]
[ 1, 2, 5, 12, 14, 45 ]
[ -14, -12, -5, 1, 2, 45 ]
[ 3, 9, 10, 27, 38, 43, 82 ]

但是通过查看我上面实现的合并排序程序,面试官说如果不遵循分而治之的概念。

我试图说服他使用“mergeArrays”和“mergeAndSort”方法 分而治之。但他不同意。

我哪里错了?

【问题讨论】:

  • 这可能更适合 codereview.stackexchange。一般来说,归并排序就像sort = merge(sort(first-half),sort(second-half)) 一样简单,首先您的解决方案看起来过于冗长。
  • mergeAndSort 应仅称为 merge

标签: javascript arrays sorting logic mergesort


【解决方案1】:

Wikipedia上分而治之的定义是:

一种基于多分支递归的算法设计范式。分治算法通过递归地将问题分解为两个或多个相同或相关类型的子问题来工作,直到这些子问题变得简单到可以直接解决。然后将子问题的解决方案组合起来,得到原始问题的解决方案。

您的解决方案确实进行了划分,并且确实组合了解决方案以给出最终解决方案,但它不会递归地执行划分,从而使子问题逐渐变小。

编辑:您确实使用了递归,但不是以此处预期的方式。您的递归是tail-recursion,切掉最小的单元(它们不会逐渐变小),并通过一系列递归调用重复该切碎,这可以很容易地在循环中执行。

您的解决方案是bottom-up approach,而分而治之通常被理解为top-down method。虽然这两种方法都是归并排序的有效实现,但严格来说,其中只有一种使用了分治范式。

但在更广泛的解释中,分而治之也可以是自下而上的,放宽了上面引用的定义中的一些要求。所以这最终可能是一个见仁见智的问题。

【讨论】:

  • 关于分而治之的wiki文章链接到它的归并排序文章为例,归并排序文章包括自底向上归并排序。 breaking down a problem into two or more sub-problems 应该包括将一个问题分解为一个大小为 n 的数组的 n 个子问题。问题是零递归是否可以被视为递归的情况,类似于对数组大小为 1 个元素进行自上而下的合并排序。
  • 是的,在我看来这是一个见仁见智的问题。如果零递归可以看作是递归的一种情况,那么定义中就没有必要提及它了,所有算法都符合一个包含递归的定义。
  • 您可以考虑自上而下的合并排序,在每个递归级别将一个数组划分为 k >= 2 个子数组,然后在返回时合并 k 个子数组。使用这个类比,自下而上类似于 k == n 的自上而下。
  • 是的,使用常量 k >= 2 确实符合自上而下的定义,但使用 k==n 您可以消除 -- 通过设计——递归。这是一个边界情况,这是否仍然符合定义是一个见仁见智的问题。
猜你喜欢
  • 1970-01-01
  • 2018-02-09
  • 2013-02-05
  • 2012-09-08
  • 1970-01-01
  • 2013-07-02
  • 2020-07-23
  • 1970-01-01
  • 2017-05-12
相关资源
最近更新 更多