实施合并排序,即标准实施,将排序算法保持在原位。
就地意味着它不会像标准情况下那样为合并操作占用额外的内存。
例子:
Input: arr[] = {2, 3, 4, 1}
Output: 1 2 3 4
Input: arr[] = {56, 2, 45}
Output: 2 45 56
方法1:
- 维护两个指针,这些指针指向必须合并的段的起点。
- 比较指针所在的元素。
- 如果element1
那么element1在正确的位置,只需增加指针1即可。 - 否则,将element1和element2之间的所有元素(包括element1但不包括element2)右移1,然后将element2放在element1的先前位置(即,向右移位之前) 。将所有指针加1 。
下面是上述方法的实现:
C++
// C++ program in-place Merge Sort
#include
using namespace std;
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
// Inplace Implementation
void merge(int arr[], int start, int mid, int end)
{
int start2 = mid + 1;
// If the direct merge is already sorted
if (arr[mid] <= arr[start2]) {
return;
}
// Two pointers to maintain start
// of both arrays to merge
while (start <= mid && start2 <= end) {
// If element 1 is in right place
if (arr[start] <= arr[start2]) {
start++;
}
else {
int value = arr[start2];
int index = start2;
// Shift all the elements between element 1
// element 2, right by 1.
while (index != start) {
arr[index] = arr[index - 1];
index--;
}
arr[start] = value;
// Update all the pointers
start++;
mid++;
start2++;
}
}
}
/* l is for left index and r is right index of the
sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
if (l < r) {
// Same as (l + r) / 2, but avoids overflow
// for large l and r
int m = l + (r - l) / 2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
/* UTILITY FUNCTIONS */
/* Function to print an array */
void printArray(int A[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}
/* Driver program to test above functions */
int main()
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int arr_size = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, 0, arr_size - 1);
printArray(arr, arr_size);
return 0;
}
Java
// Java program in-place Merge Sort
public class GFG {
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
// Inplace Implementation
static void merge(int arr[], int start, int mid,
int end)
{
int start2 = mid + 1;
// If the direct merge is already sorted
if (arr[mid] <= arr[start2]) {
return;
}
// Two pointers to maintain start
// of both arrays to merge
while (start <= mid && start2 <= end) {
// If element 1 is in right place
if (arr[start] <= arr[start2]) {
start++;
}
else {
int value = arr[start2];
int index = start2;
// Shift all the elements between element 1
// element 2, right by 1.
while (index != start) {
arr[index] = arr[index - 1];
index--;
}
arr[start] = value;
// Update all the pointers
start++;
mid++;
start2++;
}
}
}
/* l is for left index and r is right index of the
sub-array of arr to be sorted */
static void mergeSort(int arr[], int l, int r)
{
if (l < r) {
// Same as (l + r) / 2, but avoids overflow
// for large l and r
int m = l + (r - l) / 2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
/* UTILITY FUNCTIONS */
/* Function to print an array */
static void printArray(int A[], int size)
{
int i;
for (i = 0; i < size; i++)
System.out.print(A[i] + " ");
System.out.println();
}
/* Driver program to test above functions */
public static void main(String[] args)
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int arr_size = arr.length;
mergeSort(arr, 0, arr_size - 1);
printArray(arr, arr_size);
}
// This code is contributed by ANKITRAI1
}
Python3
# Python program in-place Merge Sort
# Merges two subarrays of arr.
# First subarray is arr[l..m]
# Second subarray is arr[m+1..r]
# Inplace Implementation
def merge(arr, start, mid, end):
start2 = mid + 1
# If the direct merge is already sorted
if (arr[mid] <= arr[start2]):
return
# Two pointers to maintain start
# of both arrays to merge
while (start <= mid and start2 <= end):
# If element 1 is in right place
if (arr[start] <= arr[start2]):
start += 1
else:
value = arr[start2]
index = start2
# Shift all the elements between element 1
# element 2, right by 1.
while (index != start):
arr[index] = arr[index - 1]
index -= 1
arr[start] = value
# Update all the pointers
start += 1
mid += 1
start2 += 1
'''
* l is for left index and r is right index of
the sub-array of arr to be sorted
'''
def mergeSort(arr, l, r):
if (l < r):
# Same as (l + r) / 2, but avoids overflow
# for large l and r
m = l + (r - l) // 2
# Sort first and second halves
mergeSort(arr, l, m)
mergeSort(arr, m + 1, r)
merge(arr, l, m, r)
''' UTILITY FUNCTIONS '''
''' Function to pran array '''
def printArray(A, size):
for i in range(size):
print(A[i], end=" ")
print()
''' Driver program to test above functions '''
if __name__ == '__main__':
arr = [12, 11, 13, 5, 6, 7]
arr_size = len(arr)
mergeSort(arr, 0, arr_size - 1)
printArray(arr, arr_size)
# This code is contributed by 29AjayKumar
C#
// C# program in-place Merge Sort
// sum.
using System;
class GFG {
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
// Inplace Implementation
static void merge(int[] arr, int start, int mid,
int end)
{
int start2 = mid + 1;
// If the direct merge is already sorted
if (arr[mid] <= arr[start2]) {
return;
}
// Two pointers to maintain start
// of both arrays to merge
while (start <= mid && start2 <= end) {
// If element 1 is in right place
if (arr[start] <= arr[start2]) {
start++;
}
else {
int value = arr[start2];
int index = start2;
// Shift all the elements between element 1
// element 2, right by 1.
while (index != start) {
arr[index] = arr[index - 1];
index--;
}
arr[start] = value;
// Update all the pointers
start++;
mid++;
start2++;
}
}
}
/* l is for left index and r is right index of the
sub-array of arr to be sorted */
static void mergeSort(int[] arr, int l, int r)
{
if (l < r) {
// Same as (l + r) / 2, but avoids overflow
// for large l and r
int m = l + (r - l) / 2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
/* UTILITY FUNCTIONS */
/* Function to print an array */
static void printArray(int[] A, int size)
{
int i;
for (i = 0; i < size; i++)
Console.Write(A[i] + " ");
Console.WriteLine();
}
/* Driver code */
public static void Main(String[] args)
{
int[] arr = { 12, 11, 13, 5, 6, 7 };
int arr_size = arr.Length;
mergeSort(arr, 0, arr_size - 1);
printArray(arr, arr_size);
}
}
// This code is contributed by Princi Singh
Java
// Java program for the above approach
import java.io.*;
import java.util.*;
class InPlaceMerge {
// Calculating next gap
private static int nextGap(int gap)
{
if (gap <= 1)
return 0;
return (int)Math.ceil(gap / 2.0);
}
// Function for swapping
private static void swap(int[] nums, int i, int j)
{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
// Merging the subarrays using shell sorting
// Time Complexity: O(nlog n)
// Space Complexity: O(1)
private static void inPlaceMerge(int[] nums, int start,
int end)
{
int gap = end - start + 1;
for (gap = nextGap(gap); gap > 0;
gap = nextGap(gap)) {
for (int i = start; i + gap <= end; i++) {
int j = i + gap;
if (nums[i] > nums[j])
swap(nums, i, j);
}
}
}
// merge sort makes log n recursive calls
// and each time calls merge()
// which takes nlog n steps
// Time Complexity: O(n*log n + 2((n/2)*log(n/2)) +
// 4((n/4)*log(n/4)) +.....+ 1)
// Time Complexity: O(logn*(n*log n))
// i.e. O(n*(logn)^2)
// Space Complexity: O(1)
private static void mergeSort(int[] nums, int s, int e)
{
if (s == e)
return;
// Calculating mid to slice the
// array in two halves
int mid = (s + e) / 2;
// Recursive calls to sort left
// and right subarrays
mergeSort(nums, s, mid);
mergeSort(nums, mid + 1, e);
inPlaceMerge(nums, s, e);
}
// Driver Code
public static void main(String[] args)
{
int[] nums = new int[] { 12, 11, 13, 5, 6, 7 };
mergeSort(nums, 0, nums.length - 1);
System.out.println(Arrays.toString(nums));
}
}
5 6 7 11 12 13
注:上述方法的时间复杂度为O(N 2),因为合并是O(n 2)。标准合并排序的时间复杂度较小,为O(n Log n)。
方法二:
这个想法:我们开始比较彼此相距遥远而不是相邻的元素。基本上,我们使用外壳排序将两个排序后的数组合并在一起,并增加O(1)个空间。
mergeSort():
- 计算中二将数组分为两半(左子数组和右子数组)
- 在左子数组和右子数组上递归调用合并排序以对其进行排序
- 调用合并函数合并左子数组和右子数组
合并():
- 对于每次通过,我们都计算间隙并比较间隙右侧的元素。
- 以n / 2的上限值开始间隔,其中n是左右子数组的组合长度。
- 每次通过,间隙减小到间隙/ 2的上限。
- 拿一个指针我传递数组。
- 如果第(i + gap)个元素小于(或大于按降序排序时的第i个元素),请交换第i个和第(i + gap)个元素。
- 当(i + gap)达到n时停止。
Input: 10, 30, 14, 11, 16, 7, 28
Note: Assume left and right subarrays has been sorted so we are merging sorted subarrays [10, 14, 30] and [7, 11, 16, 28]
Start with
gap = ceiling of n/2 = 7/2 = 4
[This gap is for whole merged array]
10, 14, 30, 7, 11, 16, 28
10, 14, 30, 7, 11, 16, 28
10, 14, 30, 7, 11, 16, 28
10, 14, 28, 7, 11, 16, 30
gap = ceiling of 4/2 = 2
10, 14, 28, 7, 11, 16, 30
10, 14, 28, 7, 11, 16, 30
10, 7, 28, 14, 11, 16, 30
10, 7, 11, 14, 28, 16, 30
10, 7, 11, 14, 28, 16, 30
gap = ceiling of 2/2 = 1
10, 7, 11, 14, 28, 16, 30
7, 10, 11, 14, 28, 16, 30
7, 10, 11, 14, 28, 16, 30
7, 10, 11, 14, 28, 16, 30
7, 10, 11, 14, 28, 16, 30
7, 10, 11, 14, 16, 28, 30
Output: 7, 10, 11, 14, 16, 28, 30
下面是上述方法的实现:
Java
// Java program for the above approach
import java.io.*;
import java.util.*;
class InPlaceMerge {
// Calculating next gap
private static int nextGap(int gap)
{
if (gap <= 1)
return 0;
return (int)Math.ceil(gap / 2.0);
}
// Function for swapping
private static void swap(int[] nums, int i, int j)
{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
// Merging the subarrays using shell sorting
// Time Complexity: O(nlog n)
// Space Complexity: O(1)
private static void inPlaceMerge(int[] nums, int start,
int end)
{
int gap = end - start + 1;
for (gap = nextGap(gap); gap > 0;
gap = nextGap(gap)) {
for (int i = start; i + gap <= end; i++) {
int j = i + gap;
if (nums[i] > nums[j])
swap(nums, i, j);
}
}
}
// merge sort makes log n recursive calls
// and each time calls merge()
// which takes nlog n steps
// Time Complexity: O(n*log n + 2((n/2)*log(n/2)) +
// 4((n/4)*log(n/4)) +.....+ 1)
// Time Complexity: O(logn*(n*log n))
// i.e. O(n*(logn)^2)
// Space Complexity: O(1)
private static void mergeSort(int[] nums, int s, int e)
{
if (s == e)
return;
// Calculating mid to slice the
// array in two halves
int mid = (s + e) / 2;
// Recursive calls to sort left
// and right subarrays
mergeSort(nums, s, mid);
mergeSort(nums, mid + 1, e);
inPlaceMerge(nums, s, e);
}
// Driver Code
public static void main(String[] args)
{
int[] nums = new int[] { 12, 11, 13, 5, 6, 7 };
mergeSort(nums, 0, nums.length - 1);
System.out.println(Arrays.toString(nums));
}
}
[5, 6, 7, 11, 12, 13]
时间复杂度: O(log n * nlog n)
注意: mergeSort方法进行log n次递归调用,每次调用merge都需要nlog n时间来合并2个排序的子数组