2017-09-08 44 views
0

我知道快速排序算法,但我只關心合併排序算法。'MergeSort算法' - 在JAVA中有什麼更好的實現?

我在互聯網上發現了兩種類型的合併排序算法實現。 但是,當我將它們與插入算法進行比較時,它們看起來效率較低,並且這對於大量項目來說不是預期的。

Enter the number of elements you want to sort: 
300000 

Time spent to executing BubbleSort: 362123 milliseconds 
Time spent to executing Selection: 108285 milliseconds 
Time spent to executing Insertion: 18046 milliseconds 
Time spent to executing MergeSort: 35968 milliseconds 
Time spent to executing MergeSort2: 35823 milliseconds 

是否有另一種方法來實現合併排序算法,使其比插入算法更有效?

看看我的代碼...

package br.com.test.test1; 

import java.util.Random; 
import java.util.Scanner; 

/** 
* 
* @author Joao 
*/ 
public class Main { 

    // generate an int array with random numbers between 0 and 500 
    public static int[] generateRand(int n){ 
     int[] randArray = new int[n]; 
     Random number = new Random(); 

     // random numbers between 0 and 500 
     for (int i = 0; i < n; i++){ 
      randArray[i] = number.nextInt(501); 
     } 
     return randArray; 
    } 

    public static void main(String[] args) { 
     long startTime; 
     Scanner input = new Scanner(System.in); 
     int n; 

     System.out.println("Enter the number of elements you want to sort:"); 
     n = input.nextInt(); 

     MyArray array = new MyArray(n); 
     int[] aux = new int[n]; 
     aux = generateRand(n); 


     array.copy(aux); 
     startTime = System.currentTimeMillis(); 
     array.bubblesort(); 
     // Time spent to executing BUBBLESORT 
     System.out.println("\nTime spent to executing BubbleSort: "+(System.currentTimeMillis() - startTime)+" milliseconds"); 


     array.copy(aux); 
     startTime = System.currentTimeMillis(); 
     array.selection(); 
     // Time spent to executing SELECTION 
     System.out.println("Time spent to executing Selection: "+(System.currentTimeMillis() - startTime)+" milliseconds"); 


     array.copy(aux); 
     startTime = System.currentTimeMillis(); 
     array.insertion(); 
     // Time spent to executing INSERTION 
     System.out.println("Time spent to executing Insertion: "+(System.currentTimeMillis() - startTime)+" milliseconds"); 


     array.copy(aux); 
     startTime = System.currentTimeMillis(); 
     array.mergeSort(0, n-1); 
     // Time spent to executing MERGESORT 
     System.out.println("Time spent to executing MergeSort: "+(System.currentTimeMillis() - startTime)+" milliseconds"); 


     array.copy(aux); 
     startTime = System.currentTimeMillis(); 
     array.mergeSort2(0, n-1); 
     // Time spent to executing MERGESORT 2 
     System.out.println("Time spent to executing MergeSort2: "+(System.currentTimeMillis() - startTime)+" milliseconds"); 

    } 
} 

---- ------和

package br.com.test.test1; 

/** 
* 
* @author Joao Paulo 
*/ 
class MyArray { 
    private int[] v; 
    private int n; // array index 
    private int len; 

    public MyArray(int length) { 
     len = length; 
     v = new int[len]; 
     n = 0; 
    } 

    public void copy(int[] k){ 
     n = 0; 
     for (int i = 0; i < len; i++) { 
      v[i] = k[i]; 
      n++; 
     } 
    } 

    public void show(){ 
     for (int i = 0; i < n; i++) { 
      System.out.print(" " + v[i]); 
     } 
     System.out.println("\n"); 
    } 


    // ******* START OF ALGORITHMS TO SORT ******* 

    // ---------- Start of BubbleSort and Selection -------------- 
    public void bubblesort(){ 
     for (int i = 0; i < n; i++){ 
      for (int j = 0; j < n-1; j++) { 
       if (v[j] > v[j+1]) { 
        change(j, j+1); 
       } 
      } 
     } 
    } 

    public void selection() { 
     int min; 
     for (int i = 0; i < n-1; i++) { 
      min = i; 
      for (int j = i+1; j < n; j++){ 
       if (v[j] < v[min]){ 
        min = j; 
       } 
      } 
      change(i, min); 
     } 
    } 

    private void change(int one, int two) { 
     int temp = v[one]; 
     v[one] = v[two]; 
     v[two] = temp; 
    } 
    // ---------- End of BubbleSort and Selection ---------------- 


    // ---------- Start of Insertion ----------------------------- 
    public void insertion() { 
     int i, j; 
     int temp; 
     for (i=1; i < n; i++) { 
      temp = v[i]; // marked variable 
      j = i; 
      while ((j > 0) && (v[j-1] > temp)) { 
       v[j] = v[j-1]; 
       j = j - 1; 
      } 
      v[j] = temp; 
     } 
    } 
    // ---------- End of Insertion ------------------------------- 


    // ---------- Start of MergeSort ----------------------------- 
    public void mergeSort (int start, int end){ 
     if(start == end) return; 

     int middle = (start+end)/2; 
     mergeSort(start,middle); 
     mergeSort(middle+1,end); 
     merge(start,middle,end); 
    } 

    public void merge(int start, int middle, int end) { 
     int[] aux = new int[v.length]; 

     for (int x = start; x <= end; x++) { 
      aux[x] = v[x]; 
     } 

     int i = start; 
     int j = middle+1; 
     int k = start; 

     //emptying out array 'v' inserting items neatly in array 'aux' 
     while (i <= middle && j <= end) { 
      if (aux[i] < aux[j]){ 
       v[k++] = aux[i++]; 
      } else { 
       v[k++] = aux[j++]; 
      } 
     } 

     //copying values from 'aux' to 'v' 
     while (i <= middle){ 
      v[k++] = aux[i++]; 
     } 

     while (j <= end){ 
      v[k++] = aux[j++]; 
     } 
    } 
    // ---------- End of MergeSort ------------------------------- 


    // ---------- Start of MergeSort 2 ---------------------------- 
    public void mergeSort2 (int start, int end) { 
     if(start >= end) return; 

     int middle = (start+end)/2; 
     mergeSort2(start,middle); 
     mergeSort2(middle+1,end); 
     merge2(start,middle,end); 
    } 

    public void merge2(int start, int middle, int end) { 
     int[] helper = new int[v.length]; 

     // Copy both parts into the helper array 
     for (int i = start; i <= end; i++) { 
      helper[i] = v[i]; 
     } 

     int i = start; 
     int j = middle + 1; 
     int k = start; 

     // Copy the smallest values from either the left or the right side back to the original array 
     while (i <= middle && j <= end) { 
      if (helper[i] <= helper[j]) { 
       v[k] = helper[i]; 
       i++; 
      } else { 
       v[k] = helper[j]; 
       j++; 
      } 
      k++; 
     } 

     // Copy the rest of the left side of the array into the target array 
     while (i <= middle) { 
      v[k] = helper[i]; 
      k++; 
      i++; 
     } 
     // Since we are sorting in-place any leftover elements from the right side 
     // are already at the right position. 
    } 
    // ---------- End of MergeSort 2 ------------------------------ 

} 
+1

如果代碼正常工作,Code Review Stack Exchange是提問這個問題的地方。 – AJNeufeld

+0

[瞭解合併排序優化:避免副本](https://stackoverflow.com/questions/7577825/understanding-merge-sort-optimization-avoiding-copies)。 [合併MergeSort和插入排序,使其更有效](https://stackoverflow.com/questions/15057287/combining-mergesort-with-insertion-sort-to-make-it-more-efficient)/ [合併排序和插入排序](https://cs.stackexchange.com/questions/68179/combining-merge-sort-and-insertion-sort)。 – Dukeling

+2

你的mergesorts速度很慢,因爲你在每次遞歸調用中都要分配一個新數組。你應該只分配一個臨時數組。 –

回答

0

執行工作/溫度數組的單個分配和避免在合併期間複製數據(除非將一個剩餘運行從一個陣列移動到另一個陣列)。

自下而上排序示例。

package jsortbu; 
import java.util.Random; 

public class jsortbu { 
    static void MergeSort(int[] a)   // entry function 
    { 
     if(a.length < 2)     // if size < 2 return 
      return; 
     int[] b = new int[a.length]; 
     BottomUpMergeSort(a, b); 
    } 

    static void BottomUpMergeSort(int[] a, int[] b) 
    { 
    int n = a.length; 
    int s = 1;        // run size 
     if(1 == (GetPassCount(n)&1)){  // if odd number of passes 
      for(s = 1; s < n; s += 2)  // swap in place for 1st pass 
       if(a[s] < a[s-1]){ 
        int t = a[s]; 
        a[s] = a[s-1]; 
        a[s-1] = t; 
       } 
      s = 2; 
     } 
     while(s < n){      // while not done 
      int ee = 0;      // reset end index 
      while(ee < n){     // merge pairs of runs 
       int ll = ee;    // ll = start of left run 
       int rr = ll+s;    // rr = start of right run 
       if(rr >= n){    // if only left run 
        do{      // copy it 
         b[ll] = a[ll]; 
         ll++; 
        }while(ll < n); 
        break;     // end of pass 
       } 
       ee = rr+s;     // ee = end of right run 
       if(ee > n) 
        ee = n; 
       Merge(a, b, ll, rr, ee); 
      } 
      {        // swap references 
       int[] t = a; 
       a = b; 
       b = t; 
      } 
      s <<= 1;      // double the run size 
     } 
    } 

    static void Merge(int[] a, int[] b, int ll, int rr, int ee) { 
     int o = ll;       // b[]  index 
     int l = ll;       // a[] left index 
     int r = rr;       // a[] right index 
     while(true){      // merge data 
      if(a[l] <= a[r]){    // if a[l] <= a[r] 
       b[o++] = a[l++];   // copy a[l] 
       if(l < rr)     // if not end of left run 
        continue;    //  continue (back to while) 
       while(r < ee){    // else copy rest of right run 
        b[o++] = a[r++]; 
       } 
       break;      //  and return 
      } else {      // else a[l] > a[r] 
       b[o++] = a[r++];   // copy a[r] 
       if(r < ee)     // if not end of right run 
        continue;    //  continue (back to while) 
       while(l < rr){    // else copy rest of left run 
        b[o++] = a[l++]; 
       } 
       break;      //  and return 
      } 
     } 
    } 

    static int GetPassCount(int n)   // return # passes 
    { 
     int i = 0; 
     for(int s = 1; s < n; s <<= 1) 
      i += 1; 
     return(i); 
    } 

    public static void main(String[] args) { 
     int[] a = new int[10000000]; 
     Random r = new Random(); 
     for(int i = 0; i < a.length; i++) 
      a[i] = r.nextInt(); 
     long bgn, end; 
     bgn = System.currentTimeMillis(); 
     MergeSort(a); 
     end = System.currentTimeMillis(); 
     for(int i = 1; i < a.length; i++){ 
      if(a[i-1] > a[i]){ 
       System.out.println("failed"); 
       break; 
      } 
     } 
     System.out.println("milliseconds " + (end-bgn)); 
    } 
} 

自上而下合併排序示例。一對相互遞歸的函數用於避免複製操作。合併的方向基於遞歸的級別。合併()對於自下而上和自上而下都是相同的。

package jsorttd; 
import java.util.Random; 

public class jsorttd { 
    static void MergeSort(int[] a)   // entry function 
    { 
     if(a.length < 2)     // if size < 2 return 
      return; 
     int[] b = new int[a.length]; 
     MergeSortAtoA(a, b, 0, a.length); 
    } 

    static void MergeSortAtoA(int[] a, int[] b, int ll, int ee) 
    { 
     if(ee - ll > 1) { 
      int rr = (ll + ee)>>1;   // midpoint, start of right half 
      MergeSortAtoB(a, b, ll, rr); 
      MergeSortAtoB(a, b, rr, ee); 
      Merge(b, a, ll, rr, ee);  // merge b to a 
     } 
    } 

    static void MergeSortAtoB(int[] a, int[] b, int ll, int ee) 
    { 
     if(ee - ll > 1) { 
      int rr = (ll + ee)>>1;   //midpoint, start of right half 
      MergeSortAtoA(a, b, ll, rr); 
      MergeSortAtoA(a, b, rr, ee); 
      Merge(a, b, ll, rr, ee);  // merge a to b 
     } else if((ee - ll) == 1) {   // if just one element 
      b[ll] = a[ll];     // copy a to b 
     } 
    } 

    static void Merge(int[] a, int[] b, int ll, int rr, int ee) { 
     int o = ll;       // b[]  index 
     int l = ll;       // a[] left index 
     int r = rr;       // a[] right index 
     while(true){      // merge data 
      if(a[l] <= a[r]){    // if a[l] <= a[r] 
       b[o++] = a[l++];   // copy a[l] 
       if(l < rr)     // if not end of left run 
        continue;    //  continue (back to while) 
       while(r < ee){    // else copy rest of right run 
        b[o++] = a[r++]; 
       } 
       break;      //  and return 
      } else {      // else a[l] > a[r] 
       b[o++] = a[r++];   // copy a[r] 
       if(r < ee)     // if not end of right run 
        continue;    //  continue (back to while) 
       while(l < rr){    // else copy rest of left run 
        b[o++] = a[l++]; 
       } 
       break;      //  and return 
      } 
     } 
    } 

    public static void main(String[] args) { 
     int[] a = new int[10000000]; 
     Random r = new Random(); 
     for(int i = 0; i < a.length; i++) 
      a[i] = r.nextInt(); 
     long bgn, end; 
     bgn = System.currentTimeMillis(); 
     MergeSort(a); 
     end = System.currentTimeMillis(); 
     for(int i = 1; i < a.length; i++){ 
      if(a[i-1] > a[i]){ 
       System.out.println("failed"); 
       break; 
      } 
     } 
     System.out.println("milliseconds " + (end-bgn)); 
    } 
} 

這兩種方法都需要約1秒10萬個整數我的系統上進行排序(Win 7的,英特爾3770K 3.5千兆赫,NetBeans的8.1的Java 1.8.0_65-B17)。

相關問題