【问题标题】:sorting using recursion使用递归排序
【发布时间】:2011-02-12 16:03:31
【问题描述】:

我有以下函数可以将无序数组排序为前面有偶数,后面有奇数。有没有办法在不使用任何循环的情况下完成它?

//front is 0, back =array.length-1;
arrangeArray (front, back);

public static void arrangeArray (int front, int back)
{
    if (front != back || front<back)
    {
        while (numbers [front]%2 == 0)
            front++;


        while (numbers[back]%2!=0)
            back--;


        if (front < back)
        {
            int oddnum = numbers [front];
            numbers[front]= numbers[back];
            numbers[back]=oddnum;

            arrangeArray (front+1, back-1);
        }
    }
}

【问题讨论】:

    标签: algorithm recursion sorting


    【解决方案1】:

    Mergesort 对于没有循环的代码来说相当简单:

    void mergesort(int lo, int hi)
    {
        if (lo<hi)
        {
            int m=(lo+hi)/2;
            mergesort(lo, m);
            mergesort(m+1, hi);
            merge(lo, m, hi);
        }
    }
    

    我将把它排序为偶数/奇数作为练习给读者:)

    (听起来像家庭作业)

    【讨论】:

    • 我认为归并排序的结构不是解决这个问题的正确结构。这向中间递归,不涉及分而治之,只是纯粹的迭代递归。
    • Charles:如何在中间拆分数组,在两半上使用递归,然后合并它们,而不是分而治之的算法?
    • 我是说这个问题不需要分而治之(合并排序是),分而治之问题通常在 O(nlogn) 中解决,而这个问题可以在 O 中完成(n)
    • 哦,我假设它不需要对数字进行排序,只需要前面的偶数一半(不一定排序)和后面的奇数。
    • @Charles Ma:是的,你得到了我的 +1。
    【解决方案2】:

    当你进行递归时,你有一个基本步骤和一个递归步骤。

    在这种情况下,基本条件是 front == back,因为您从边缘开始并在中间结束。当你到达中间时,你就知道它已经完成了。

    在执行递归步骤之前,您必须进行一些排序。您一次只进行一步排序,所以现在只处理 array[front] 和 array[back] 处的元素。将它们安排到正确的位置后,进行递归调用。

    你会得到这样的结果:

    public static void arrangeArray (int front, int back)
    {
       if(front >= back) return;
       int f = numbers[front];
       int b = numbers[back];
       if(f%2 == 0) {
          front++;
       } else {
          numbers[back] = f;
          back--;
       }
       if (b%2 == 0) {
          numbers[front] = b;
          front++;
       } else {
          back--;
       }  
       arrangeArray(front, back);                                         
    }
    

    它未经测试,可能不适用于边缘条件,但这是一个好的开始:)

    【讨论】:

      【解决方案3】:

      不就是这样吗:

      //front is 0, back =array.length-1; 
      arrangeArray (front, back); 
      
      public static void arrangeArray (int front, int back) 
      { 
          if (front != back || front<back)
          { 
              if (numbers [front]%2 == 0) 
                  arrangeArray (front+1, back); 
              else
              if (numbers[back]%2!=0) 
                  arrangeArray (front, back-1); 
              else
              if (front < back) 
              { 
                  int oddnum = numbers [front]; 
                  numbers[front]= numbers[back]; 
                  numbers[back]=oddnum; 
      
                  arrangeArray (front+1, back-1); 
              } 
          } 
      } 
      

      ?

      【讨论】:

        【解决方案4】:

        我可以推荐这个 Python sn-p 来激发高级思考吗?

        compare = lambda x,y: x - y if x%2 == y%2 else y%2 - x%2
        >>> sorted([3,4,2,1,5,6,7,90,23,44], cmp=compare)
        [1, 3, 5, 7, 23, 2, 4, 6, 44, 90]
        

        我认为需要构建一个返回负数、0 和正数的比较器函数并使用它。

        【讨论】:

          【解决方案5】:

          你想做的是

          arrangeArray(front, back, bool recursed=false) {
              if (recursed) {
                  arrangeArray(front, back/2, true);
                  return arrangeArray(back/2, back, true);
              }
              // Do stuff here.
          }
          

          【讨论】:

          • 嗯...如果你用record=false调用它,它什么也不做。如果你用 recursed=true 调用它,它会永远递归。
          【解决方案6】:

          以下内容应该具有指导意义。这是一个递归的O(N) 解决方案,它重新排列前面的偶数和后面的奇数,但除此之外不进行任何排序。

          static boolean isEven(int n) {
              return (n & 1) == 0;
          }
          static boolean isOdd(int n) {
              return !isEven(n);
          }
          static int[] swapped(int[] nums, int i, int j) {
              int t = nums[i];
              nums[i] = nums[j];
              nums[j] = t;
              return nums;
          }
          static int[] arrange(int[] nums, int lo, int hi) {
              return
                  (lo >= hi) ? nums :
                  (isEven(nums[lo])) ? arrange(nums, lo + 1, hi) :
                  (isOdd(nums[hi])) ? arrange(nums, lo, hi - 1) :
                  arrange(swapped(nums, lo, hi), lo + 1, hi - 1);
          }   
          static void evenOddSort(int... nums) {
              System.out.println(java.util.Arrays.toString(
                  arrange(nums, 0, nums.length - 1)
              ));
          }   
          public static void main(String[] args) {
              evenOddSort(1,3,5,7,2,4,6);
          } // prints "[6, 4, 2, 7, 5, 3, 1]"
          

          我认为三元运算符使递归流程更自然,但如果您对它的工作方式不太满意,您可以使用传统的if-else

          static int[] arrange(int[] nums, int lo, int hi) {
              if (lo >= hi) {
                  return nums;
              } else if (isEven(nums[lo])) {
                  return arrange(nums, lo + 1, hi);
              } else if (isOdd(nums[hi])) {
                  return arrange(nums, lo, hi - 1);
              } else {
                  return arrange(swapped(nums, lo, hi), lo + 1, hi - 1);
              }
          }
          

          【讨论】:

          • 滥用嵌套三元运算符。 :P
          • @Stephen:我不同意。三元运算符之所以具有右关联性是有原因的,它允许这种表达式级别的 if-else 类似构造。
          • 我同意斯蒂芬的观点。仅仅因为你可以不用括号写出来并不意味着你应该这样做。表达式 x ^ a + b ^ c + d 定义得很好,但是那些不熟记优先规则的人会感到非常困惑。
          猜你喜欢
          • 1970-01-01
          • 2021-07-17
          • 2017-12-22
          • 2022-01-16
          • 2014-08-12
          • 2017-01-14
          • 2020-07-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多