📜  使用 O(1) 额外空间合并和 O(n lg n) 时间的合并排序 [仅限无符号整数]

📅  最后修改于: 2021-09-16 11:02:29             🧑  作者: Mango

我们已经讨论了归并排序。如何修改算法以便合并在 O(1) 额外空间中工作,并且算法仍然在 O(n Log n) 时间内工作。我们可以假设输入值只是整数。

例子:

Input : 5 4 3 2 1
Output : 1 2 3 4 5

Input : 999 612 589 856 56 945 243
Output : 56 243 589 612 856 945 999

对于整数类型,可以使用一些模数和除法的数学技巧就地进行归并排序。这意味着在一个索引处存储两个元素值,并且可以使用模数和除法来提取。

首先,我们必须找到一个大于数组所有元素的值。现在我们可以将原始值存储为模数,将第二个值存储为除法。假设我们想将arr[i]arr[j]都存储在索引 i(在 arr[i] 中的意思)。首先,我们必须找到一个大于 arr[i] 和 arr[j] 的“maxval” 。现在我们可以存储为arr[i] = arr[i] + arr[j]*maxval 。现在arr[i]%maxval将给出arr[i]的原始值, arr[i]/maxval将给出 arr[j] 的值。所以下面是合并排序的实现。

方法:(欧氏除法)

合并中可能出现的问题:

1.如果当前数字是Integer.MAX,那么通常大于当前元素的新编码值将导致整数溢出和数据损坏(在Python中没有数字大小的限制,因此不会发生此问题)。

2. 不处理负数(即,当用另一个 -ve 数(选择最小的)编码一个 -ve 数(当前)时,不能保留符号,因为两个数都有 -ve 符号。也必须使用绝对值当计算股息 = 除数*商+余数(除数 = maxele,商 = 最小,余数 = 原始)并且必须恢复符号时,由于符号保留问题,它仍然可能不起作用。

3. 仅适用于无符号整数,例如通常为非负的索引。

4. AUX = O(n) 在最坏的情况下,假设在像Python这样没有字/整数大小限制的语言中,当输入数组元素几乎在 Integer.MAX 时,那么编码值可能需要 2x 位空间来表示新的数字,整个 2x 位空间可以变成 +1x 数组大小,这几乎就像创建一个 AUX 数组,但是以间接的方式。

5. mod 和 Division 操作是最昂贵的,因此降低了整体性能(在一定程度上)。

C++
// C++ program to sort an array using merge sort such
// that merge operation takes O(1) extra space.
#include 
using namespace std;
void merge(int arr[], int beg, int mid, int end, int maxele)
{
    int i = beg;
    int j = mid + 1;
    int k = beg;
    while (i <= mid && j <= end) {
        if (arr[i] % maxele <= arr[j] % maxele) {
            arr[k] = arr[k] + (arr[i] % maxele) * maxele;
            k++;
            i++;
        }
        else {
            arr[k] = arr[k] + (arr[j] % maxele) * maxele;
            k++;
            j++;
        }
    }
    while (i <= mid) {
        arr[k] = arr[k] + (arr[i] % maxele) * maxele;
        k++;
        i++;
    }
    while (j <= end) {
        arr[k] = arr[k] + (arr[j] % maxele) * maxele;
        k++;
        j++;
    }
 
    // Obtaining actual values
    for (int i = beg; i <= end; i++)
        arr[i] = arr[i] / maxele;
}
 
// Recursive merge sort with extra parameter, naxele
void mergeSortRec(int arr[], int beg, int end, int maxele)
{
    if (beg < end) {
        int mid = (beg + end) / 2;
        mergeSortRec(arr, beg, mid, maxele);
        mergeSortRec(arr, mid + 1, end, maxele);
        merge(arr, beg, mid, end, maxele);
    }
}
 
// This functions finds max element and calls recursive
// merge sort.
void mergeSort(int arr[], int n)
{
   int maxele = *max_element(arr, arr+n) + 1;
   mergeSortRec(arr, 0, n-1, maxele);
}
 
int main()
{
    int arr[] = { 999, 612, 589, 856, 56, 945, 243 };
    int n = sizeof(arr) / sizeof(arr[0]);
     
    mergeSort(arr, n);
 
    cout << "Sorted array \n";
    for (int i = 0; i < n; i++)
        cout << arr[i] << " ";
    return 0;
}


Java
// Java program to sort an array
// using merge sort such that
// merge operation takes O(1)
// extra space.
import java.util.Arrays;
 
class GFG
{
 
    static void merge(int[] arr, int beg,
                        int mid, int end,
                        int maxele)
    {
        int i = beg;
        int j = mid + 1;
        int k = beg;
        while (i <= mid && j <= end)
        {
            if (arr[i] % maxele <=
                arr[j] % maxele)
            {
                arr[k] = arr[k] + (arr[i]
                        % maxele) * maxele;
                k++;
                i++;
            }
            else
            {
                arr[k] = arr[k] +
                        (arr[j] % maxele)
                        * maxele;
                k++;
                j++;
            }
        }
        while (i <= mid)
        {
            arr[k] = arr[k] + (arr[i]
                    % maxele) * maxele;
            k++;
            i++;
        }
        while (j <= end)
        {
            arr[k] = arr[k] + (arr[j]
                    % maxele) * maxele;
            k++;
            j++;
        }
 
        // Obtaining actual values
        for (i = beg; i <= end; i++)
        {
            arr[i] = arr[i] / maxele;
        }
    }
 
    // Recursive merge sort
    // with extra parameter, naxele
    static void mergeSortRec(int[] arr, int beg,
            int end, int maxele)
    {
        if (beg < end)
        {
            int mid = (beg + end) / 2;
            mergeSortRec(arr, beg,
                        mid, maxele);
            mergeSortRec(arr, mid + 1,
                        end, maxele);
            merge(arr, beg, mid,
                    end, maxele);
        }
    }
 
    // This functions finds
    // max element and calls
    // recursive merge sort.
    static void mergeSort(int[] arr, int n)
    {
        int maxele = Arrays.stream(arr).max().getAsInt() + 1;
        mergeSortRec(arr, 0, n - 1, maxele);
    }
 
    // Driver code
    public static void main(String[] args)
    {
 
        int[] arr = {999, 612, 589,
                    856, 56, 945, 243};
        int n = arr.length;
 
        mergeSort(arr, n);
 
        System.out.println("Sorted array ");
        for (int i = 0; i < n; i++)
        {
            System.out.print(arr[i] + " ");
        }
    }
}
 
// This code is contributed by 29AjayKumar


Python3
# Python3 program to sort an array using
# merge sort such that merge operation
# takes O(1) extra space.
def merge(arr, beg, mid, end, maxele):
     
    i = beg
    j = mid + 1
    k = beg
     
    while (i <= mid and j <= end):
        if (arr[i] % maxele <= arr[j] % maxele):
            arr[k] = arr[k] + (arr[i] %
                    maxele) * maxele
            k += 1
            i += 1
        else:
            arr[k] = arr[k] + (arr[j] %
                    maxele) * maxele
            k += 1
            j += 1
             
    while (i <= mid):
        arr[k] = arr[k] + (arr[i] %
                maxele) * maxele
        k += 1
        i += 1
    while (j <= end):
        arr[k] = arr[k] + (arr[j] %
                maxele) * maxele
        k += 1
        j += 1
 
    # Obtaining actual values
    for i in range(beg, end + 1):
        arr[i] = arr[i] // maxele
 
# Recursive merge sort with extra
# parameter, naxele
def mergeSortRec(arr, beg, end, maxele):
     
    if (beg < end):
        mid = (beg + end) // 2
        mergeSortRec(arr, beg, mid, maxele)
        mergeSortRec(arr, mid + 1, end, maxele)
        merge(arr, beg, mid, end, maxele)
 
# This functions finds max element and
# calls recursive merge sort.
def mergeSort(arr, n):
     
   maxele = max(arr) + 1
   mergeSortRec(arr, 0, n - 1, maxele)
 
# Driver Code
if __name__ == '__main__':
 
    arr = [ 999, 612, 589, 856, 56, 945, 243 ]
    n =  len(arr)
    mergeSort(arr, n)
 
    print("Sorted array")
     
    for i in range(n):
        print(arr[i], end = " ")
 
# This code is contributed by mohit kumar 29


C#
// C# program to sort an array
// using merge sort such that
// merge operation takes O(1)
// extra space.
using System;
using System.Linq;
 
class GFG
{
static void merge(int []arr, int beg,
                  int mid, int end,
                  int maxele)
{
    int i = beg;
    int j = mid + 1;
    int k = beg;
    while (i <= mid && j <= end)
    {
        if (arr[i] %
            maxele <= arr[j] % maxele)
        {
            arr[k] = arr[k] + (arr[i] %
                     maxele) * maxele;
            k++;
            i++;
        }
        else
        {
            arr[k] = arr[k] +
                    (arr[j] % maxele) *
                              maxele;
            k++;
            j++;
        }
    }
    while (i <= mid)
    {
        arr[k] = arr[k] + (arr[i] %
                 maxele) * maxele;
        k++;
        i++;
    }
    while (j <= end)
    {
        arr[k] = arr[k] + (arr[j] %
                 maxele) * maxele;
        k++;
        j++;
    }
 
    // Obtaining actual values
    for ( i = beg; i <= end; i++)
        arr[i] = arr[i] / maxele;
}
 
// Recursive merge sort
// with extra parameter, naxele
static void mergeSortRec(int []arr, int beg,
                         int end, int maxele)
{
    if (beg < end)
    {
        int mid = (beg + end) / 2;
        mergeSortRec(arr, beg,
                     mid, maxele);
        mergeSortRec(arr, mid + 1,
                     end, maxele);
        merge(arr, beg, mid,
              end, maxele);
    }
}
 
// This functions finds
// max element and calls
// recursive merge sort.
static void mergeSort(int []arr, int n)
{
    int maxele = arr.Max() + 1;
    mergeSortRec(arr, 0, n - 1, maxele);
}
 
//Driver code
public static void Main ()
{
    int []arr = {999, 612, 589,
                 856, 56, 945, 243};
    int n = arr.Length;
 
    mergeSort(arr, n);
 
    Console.WriteLine("Sorted array ");
    for (int i = 0; i < n; i++)
        Console.Write( arr[i] + " ");
}
}
 
// This code is contributed
// by inder_verma.


Javascript


输出:
Sorted array 
56 243 589 612 856 945 999

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程