【问题标题】:Java Natural Merge Sort implementationJava 自然归并排序实现
【发布时间】:2016-09-11 14:38:48
【问题描述】:

我在 Java 中算是新人。我一直在努力解决我们学校教授给我们的一个问题。我应该做一个自然的合并排序算法,它每次都必须找到两个排序的子数组并将它们合并。(这是自下而上合并排序的一个版本)。但我被困在这里是我的代码

public class NaturalMergeMine {
  private static Comparable[] aux;

  public static void sort(Comparable[] a) {
    aux = new Comparable[a.length];
    sort(a, 0, a.length - 1);
  }

  public static boolean isSorted(Comparable[] a) {
    for (int i = 1; i < a.length; i += 1) {
      if (a[i - 1].compareTo(a[i]) < 0) {
        return false;
      }
    }
    return true;
  }

  private static void sort(Comparable[] a, int lo, int hi) {
    int i = lo;
    int j = 0;
    int mid = 0;
    int az = 0;

    while (true) {
      i = 0;
      System.out.println("outter");
      while (i < a.length) {
        System.out.println("inner 1");
        if (i == a.length - 1) {
          break;
        } else if (a[i].compareTo(a[i + 1]) < 0) {
          break;
        }
        i++;
      }

      j = i + 1;

      while (j < a.length) {
        System.out.println("inner 2");
        if (j == a.length - 1) {
          break;
        } else if (a[j].compareTo(a[j + 1]) < 0) {
          break;
        }
        j++;
      }
      mid = lo + (j - lo) / 2;
      Merge(a, lo, mid, j);
      lo = 0;

      if (isSorted(a)) {
        break;
      }
    }
  }

  public static void Merge(Comparable[] a, int lo, int mid, int hi) {
    int i = lo;
    int j = mid + 1;

    for (int k = lo; k <= hi; k++) {
      aux[k] = a[k];
    }

    for (int k = lo; k <= hi; k++) {
      if (i > mid) {
        a[k] = aux[j++];
      } else if (j > hi) {
        a[k] = aux[i++];
      } else if (aux[i].compareTo(aux[j]) < 0) {
        a[k] = aux[j++];
      } else {
        a[k] = aux[i++];
      }
    }
  }

  public static void show(Comparable[] a) {
    for (int i = 0; i < a.length; i++) {
      System.out.print(a[i] + " ");
    }
  }

  public static void main(String[] args) {
    Integer[] arr = {6, 4, 5, 7, 8, 3, 2, 1};
    sort(arr);
    show(arr);
  }
}

发生的情况是它没有正确合并,它在外循环中进入无限循环,这是因为它没有正确排序。有没有人可以建议我更好的方法或者可以告诉我我在这里犯的错误。提前致谢。

【问题讨论】:

    标签: java sorting object merge


    【解决方案1】:

    Amer Qarabsa 的回答解决了原始代码的问题。下面是一些更优化的替代示例,扫描数组以查找成对的升序序列,而不是每次都从头开始。如果数组反转,则第一遍创建 2 次运行,下一次运行 4 次,...。使用原始版本,每次循环的运行大小只会增加一。下面的示例代码使用开区间(最后一个索引是数组的结尾而不是数组的最后一个元素)。

    public class jsortns {
        private static Comparable[] aux;
    
        public static void sort(Comparable[] a) {
            aux = new Comparable[a.length];
            int i;
            int j;
            int k;
            while (true) {                  // merge pass
                i = 0;
                while(true) {               // find, merge pair of runs
                    j = i;                  // find left run
                    while (++j < a.length) {
                        if (a[j-1].compareTo(a[j]) > 0)
                            break;
                    }
                    if(j == a.length){      // if only one run left
                        if(i == 0)          //   if done return
                            return;
                        else                //   else end of merge pass
                            break;
                    }
                    k = j;                  // find right run
                    while (++k < a.length) {
                        if (a[k-1].compareTo(a[k]) > 0){
                            break;
                        }
                    }
                    Merge(a, i, j, k);      // merge runs
                    i = k;
                    if(i == a.length)       // if end of merge pass, break
                        break;
                }
            }
        }
    
        // merge left and right runs
        // ll = start of left run
        // rr = start of right run == end of left run
        // ee = end of right run
        public static void Merge(Comparable[] a, int ll, int rr, int ee) {
            int i = ll;
            int j = rr;
            int k;
            for (k = ll; k < ee; k++)
                aux[k] = a[k];
            k = ll;
            while(true){
                // if left element <= right element
                if (aux[i].compareTo(aux[j]) <= 0) {
                    a[k++] = aux[i++];      // copy left element
                    if(i == rr){            // if end of left run
                        while(j < ee)       //   copy rest of right run
                            a[k++] = aux[j++];
                    return;                 //   and return
                    }
                } else {
                    a[k++] = aux[j++];      // copy right element
                    if(j == ee){            // if end of right run
                        while(i < rr){      //   copy rest of left run
                            a[k++] = aux[i++];
                        }
                    return;                 //   and return
                    }
                }
            }
        }
    

    没有复制回版本,而是在两个数组之间来回合并,如果排序后的数据最终出现在错误的数组中,则仅在最后复制。

    public class jsortns {
        private static Comparable[] b;      // temp array
        private static Comparable[] o;      // original array reference
        private static Comparable[] t;      // used to swap a, b
    
        public static void sort(Comparable[] a) {
            o = a;                          // save ref to a
            b = new Comparable[a.length];   // allocate temp array
            int i;
            int j;
            int k;
            while (true) {                  // merge pass
                i = 0;
                while(true) {               // find, merge pair of runs
                    j = i;                  // find left run
                    while (++j < a.length) {
                        if (a[j-1].compareTo(a[j]) > 0)
                            break;
                    }
                    if(j == a.length){      // if only one run left
                        if(i != 0){         //   if not done
                            while(i < j){   //     copy run to b
                                b[i] = a[i];
                                i++;
                            }
                            break;          //   break to end merge pass
                        } else {            // else sort done
                            if(a != o){     //   if a not original a, copy
                                for(i = 0; i < a.length; i++)
                                    b[i] = a[i];
                            }
                            return;
                        }
                    }
                    k = j;                  // find right run
                    while (++k < a.length) {
                        if (a[k-1].compareTo(a[k]) > 0){
                            break;
                        }
                    }
                    Merge(a, b, i, j, k);   // merge left, right into b
                    i = k;
                    if(i == a.length)       // break if end pass
                        break;
                }
                t = a;                      // swap a and b (references)
                a = b;
                b = t;
            }
        }
    
        // merge left and right runs from a[] to b[]
        // ll = start of left run
        // rr = start of right run == end of left run
        // ee = end of right run
        public static void Merge(Comparable[] a, Comparable[] b, int ll, int rr, int ee) {
            int i = ll;
            int j = rr;
            int k = ll;
            while(true){
                // if left element <= right element
                if (a[i].compareTo(a[j]) <= 0) {
                    b[k++] = a[i++];        // copy left element
                    if(i == rr){            // if end of left run
                        while(j < ee)       //   copy rest of right run
                            b[k++] = a[j++];
                    return;                 //   and return
                    }
                } else {
                    b[k++] = a[j++];        // copy right element
                    if(j == ee){            // if end of right run
                        while(i < rr){      //   copy rest of left run
                            b[k++] = a[i++];
                        }
                    return;                 //   and return
                    }
                }
            }
        }
    

    【讨论】:

    • 非常感谢。这些应用算法的观点和 Amer Qarabsa 的回答帮助我解决了这个问题。
    【解决方案2】:

    问题在于中间计算,我不太清楚你为什么这样做,但如果中间小于 i 在你的合并方法中,你不会遇到错误情况,所以你会坚持发现它而不解决,对于每个run 你需要选择两个数组进行排序,所以你可以将 i 插入到 merge 方法中,而不是 mid ,这样你就可以从故障中开始合并。

     public class NaturalMergeMine {
    private static Comparable[] aux;
    
     public static void sort(Comparable[] a) {
      aux = new Comparable[a.length];
      sort(a, 0, a.length - 1);
    }
    
     public static boolean isSorted(Comparable[] a) {
       for (int i = 1; i < a.length; i += 1) {
         if (a[i - 1].compareTo(a[i]) > 0) {//changed operator to greater than
          return false;
        }
      }
      return true;
    }
    
    private static void sort(Comparable[] a, int lo, int hi) {
      int i = lo;
      int j = 0;
      int mid = 0;
      int az = 0;
    
      while (true) {
       i = 0;
        System.out.println("outter");
        while (i < a.length) {
         System.out.println("inner 1");
         if (i == a.length - 1) {
           break;
          } else if (a[i].compareTo(a[i + 1]) > 0) {//changed operator to greater than
           break;
          }
          i++;
        }
    
        j = i + 1;
    
        while (j < a.length) {
        System.out.println("inner 2");
        if (j == a.length - 1) {
          break;
        } else if (a[j].compareTo(a[j + 1]) > 0) {//changed operator to greater than
          break;
        }
        j++;
      }
     //      mid = lo + (j - lo) / 2;
      Merge(a, lo, i, j);
      lo = 0;
    
      if (isSorted(a)) {
        break;
      }
     }
    }
    
    public static void Merge(Comparable[] a, int lo, int mid, int hi) {
    int i = lo;
    int j = mid + 1;
    
    for (int k = lo; k <= hi; k++) {
      aux[k] = a[k];
    }
    
    for (int k = lo; k <= hi; k++) {
      if (i > mid) {
        a[k] = aux[j++];
      } else if (j > hi) {
        a[k] = aux[i++];
      } else if (aux[i].compareTo(aux[j]) > 0) {//changed the operator to greater than
        a[k] = aux[j++];
      } else {
        a[k] = aux[i++];
      }
     }
     }
    
      public static void show(Comparable[] a) {
       for (int i = 0; i < a.length; i++) {
        System.out.print(a[i] + " ");
       }
      }
    
     public static void main(String[] args) {
      Integer[] arr = {6, 4, 5, 7, 8, 3, 2, 1};
      sort(arr);
      show(arr);
      }
     }
    

    【讨论】:

    • 谢谢,但这不是自上而下合并排序的正常实现吗?我遇到的问题是找到 2 个已排序的子数组,一旦找到它们,我就应该合并它们。这可能不完全是数组的一半。
    • 这是标准的归并排序算法,不是自然归并排序算法。 OP 明确表示问题出在合并部分。如果您在这部分中发现并纠正了某种错误,如果您详细解释更改将是有益的。
    • 其实我已经在标准的归并排序算法中实现了归并方法,并且运行正常。我在这里使用了相同的合并方法。我在上面编写的代码中唯一更改的部分是 sort(Comparable [] a, int lo.....) 方法。但它并没有达到我最初想要的效果。
    • 对不起,我错过了自然,我会编辑答案
    • 谢谢你,但按照你说的做之后。它按降序对数组进行排序。这与我想做的完全相反。
    猜你喜欢
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多