Java 常见例子

归并排序是一种分而治之的算法。它基于以下思想:将未排序的数组划分为多个子数组,直到每个子数组由单个元素组成,然后以产生排序数组的方式合并这些子数组。归并排序的过程步骤可以概括如下:

  • 划分: 将未排序的数组划分为多个子数组,直到每个子数组只包含单个元素。
  • 合并:将子数组合并为有序数组,然后合并直至获得原始数组。
  • 合并技术: 考虑并比较两个子数组的第一个元素。对于升序排序,从子数组中取出值较小的元素,并成为排序数组的新元素。重复此过程,直到两个子数组都被清空并且合并后的数组成为排序数组。

示例:

为了理解合并排序,让我们考虑一个未排序的数组[4, 9, -4](下图中第 11 个过程后创建的右侧数组)并讨论按升序对数组进行排序所采取的每个步骤。

在第一步,将数组[4, 9, -4]分为两个子数组。第一个子数组包含 [4, 9],第二个子数组包含 [-4]。由于第一个子数组中的元素数量大于1,因此将其进一步分为分别由元素[4][9]组成的子数组。由于所有子数组的元素个数均为 1,因此无法对数组进行进一步划分。

在合并过程中,将上一步形成的子数组合并在一起,使用上面提到的过程形成一个排序数组。首先,将[4][9]子数组合并在一起,形成排序子数组[4, 9]。然后将[4, 9][-4]子数组合并在一起形成最终的排序数组[-4, 4, 9]

Java 归并排序

归并排序的实现

public class MyClass {
  // 合并排序函数 - 分割数组
  //并调用merge函数对数组进行排序和合并
  //归并排序是一个递归函数
  static void mergesort(int Array[], int left, int right) {
    if (left < right) { 
      int mid = left + (right - left)/2;
      mergesort(Array, left, mid);
      mergesort(Array, mid+1, right);
      merge(Array, left, mid, right);
    }
  }

  //合并函数执行排序和合并操作
  //用于合并排序函数
  static void merge(int Array[], int left, int mid, int right) {
    // 创建两个临时数组来保存 split
    //主数组的元素
    int n1 = mid - left + 1; //LeftArray 中的元素数量
    int n2 = right - mid;     //RightArray 中的元素数量
    int LeftArray[] = new int[n1];
    int[] RightArray = new int [n2];

    for(int i=0; i < n1; i++) { 
      LeftArray[i] = Array[left + i];
    }
    
    for(int i=0; i < n2; i++) { 
      RightArray[i] = Array[mid + i + 1];
    }

    //下面的x,y,z代表索引号
    //分别为LeftArray、RightArray和Array
    int x=0, y=0, z=left;
    while(x < n1 && y < n2) {
      if(LeftArray[x] < RightArray[y]) { 
        Array[z] = LeftArray[x]; 
        x++; 
      }
      else { 
       Array[z] = RightArray[y];  
       y++; 
      }
      z++;
    }

    //复制LeftArray的剩余元素
    while(x < n1) { 
       Array[z] = LeftArray[x];  
       x++;  
       z++;
    }

    //复制RightArray的剩余元素
    while(y < n2) { 
      Array[z] = RightArray[y]; 
      y++;  
      z++; 
    }
  }

  //打印数组的函数
  static void PrintArray(int Array[]) { 
    int n = Array.length; 
    for (int i=0; i<n; i++) 
      System.out.print(Array[i] + " "); 
    System.out.println(); 
  } 

  //测试代码
  public static void main(String[] args) {
    int[] MyArray = {10, 1, 23, 50, 4, 9, -4};
    int n = MyArray.length;
    System.out.println("原始数组");
    PrintArray(MyArray);

    mergesort(MyArray, 0, n-1);
    System.out.println("\n排序数组");
    PrintArray(MyArray); 
  }
} 

上面的代码将给出以下输出:

原始数组
10 1 23 50 4 9 -4 

排序数组
-4 1 4 9 10 23 50 

时间复杂度:

在所有情况下(最差、平均和最佳),合并排序始终划分数组,直到所有子数组都包含单个元素,并花费线性时间来合并这些子数组。划分过程的时间复杂度为θ(logN),合并过程的时间复杂度为θ(N)。因此,在所有情况下,归并排序的时间复杂度都是θ(NlogN)