web-dev-qa-db-fra.com

Quand se produira le pire cas de tri par fusion?

Je sais que le pire des cas sur mergesort est O (nlogn), le même que le cas moyen.

Cependant, si les données sont ascendantes ou descendantes, cela se traduit par le nombre minimum de comparaisons , et par conséquent le fusionnement devient plus rapide que les données aléatoires. Ma question est donc la suivante: quel type de données d'entrée produit le nombre maximal de comparaisons qui aboutissent à une fusion plus lente?

La réponse à this question dit:

Pour certains algorithmes de tri (par exemple, tri rapide), l'ordre initial des éléments peut affecter le nombre d'opérations à effectuer. Cependant, il ne fait aucun changement pour mergesort car il devra de toute façon faire exactement le même nombre d'opérations: diviser récursivement en petits tableaux puis les fusionner à nouveau, en un temps total de Θ (nlogn).

Mais c'est faux. Au point où nous avons deux sous-réseaux et nous voulons les fusionner si les données initiales sont triées, nous n'aurons que n/2 comparaisons. Il s'agit de tous les éléments du premier sous-tableau avec uniquement le premier élément du deuxième tableau. Cependant, nous pouvons faire plus que cela. Je cherche ces données d'entrée.

28
Jim Blum

Le pire cas de tri par fusion sera celui où le tri par fusion devra faire nombre maximal de comparaisons.

Je vais donc essayer de construire le pire des cas de manière ascendante:

  1. Supposons que le tableau à l'étape finale après le tri soit {0,1,2,3,4,5,6,7}

  2. Dans le pire des cas, le tableau avant cette étape doit être {0,2,4,6,1,3,5,7} car ici sous-tableau gauche = {0,2,4,6} et sous-tableau droit = ​​{1,3,5,7} entraînera des comparaisons maximales. ( Stockage des elemets alternatifs dans les sous-réseaux gauche et droit )

    Raison: Chaque élément du tableau sera comparé au moins une fois.

  3. Application de la même logique ci-dessus pour les sous-tableaux gauche et droit pour les étapes précédentes: Pour le tableau {0,2,4,6} le pire des cas sera si le tableau précédent est {0,4} et {2,6} et pour le tableau {1,3,5,7} le pire des cas sera pour {1,5} et {3,7}.

  4. Maintenant, appliquez la même chose pour les tableaux des étapes précédentes: Pour les pires cas : {0,4} doit être {4,0}, {2,6} doit être {6,2}, {1,5} doit être {5,1}{3,7} doit être {7,3}. Eh bien, si vous regardez clairement, cette étape est pas nécessaire parce que si la taille de set/array est 2, chaque élément sera comparé au moins une fois même si le tableau de taille 2 est trié.

Aller maintenant de haut en bas et analyser la situation

Applying Merge Sort using Divide and Conquer

Input array arr[] = [4,0,6,2,5,1,7,3]
                           /  \
                          /    \
                  [4,0,6,2] and [5,1,7,3]
                     / \           / \
                    /   \         /   \
                 [4,0] [6,2]    [5,1] [7,3]       Every pair of 2 will be compared atleast once therefore maximum comparison here
                   |     |        |     |
                   |     |        |     |
                 [0,4] [2,6]    [1,5] [3,7]      Maximum Comparison:Every pair of set is used in comparison     
                   \     /        \     /                        
                    \   /          \   /
                 [0,2,4,6]      [1,3,5,7]        Maximum comparison again: Every pair of set compared
                      \             /
                       \           / 
                     [0,1,2,3,4,5,6,7]          

Maintenant, vous pouvez appliquer la même logique pour n'importe quel tableau de taille n

Voici le programme qui implémente la logique ci-dessus.

Remarque: Le programme ci-dessous n'est pas valable uniquement pour des puissances de 2. C'est une méthode généralisée pour fournir le pire des cas pour tout tableau de taille n. Vous pouvez essayer différents tableaux pour la saisie par vous-même.

class MergeWorstCase
{
    public static void print(int arr[])
    {
        System.out.println();
        for(int i=0;i<arr.length;i++)
            System.out.print(arr[i]+" ");
        System.out.println();
    }
    public static void merge(int[] arr, int[] left, int[] right) {
        int i,j;
        for(i=0;i<left.length;i++)
                arr[i]=left[i];
        for(j=0;j<right.length;j++,i++)
                arr[i]=right[j];
    }

    //Pass a sorted array here
    public static void seperate(int[] arr) { 

            if(arr.length<=1)
                return;

            if(arr.length==2)
            {
                int swap=arr[0];
                arr[0]=arr[1];
                arr[1]=swap;
                return;
            }

        int i,j;
        int m = (arr.length + 1) / 2;
        int left[] = new int[m];
        int right[] = new int[arr.length-m];

        for(i=0,j=0;i<arr.length;i=i+2,j++) //Storing alternate elements in left subarray
            left[j]=arr[i];

        for(i=1,j=0;i<arr.length;i=i+2,j++) //Storing alternate elements in right subarray
            right[j]=arr[i];

        seperate(left);
        seperate(right);
        merge(arr, left, right);
    }
    public static void main(String args[])
    {
        int arr1[]={0,1,2,3,4,5,6,7};
        seperate(arr1);
        System.out.print("For array 1:");
        print(arr1);
        int arr2[]={0,1,2,3,4,5,6,7,8};
        seperate(arr2);
        System.out.print("For array 2:");
        print(arr2);            
    }
}

Sortie:

For array 1:
4 0 6 2 5 1 7 3 
For array 2:
8 0 4 6 2 5 1 7 3 
66
Jerky

Algorithme

Un algorithme soigné qu'un de mes professeurs m'a donné résout cela en utilisant une approche opposée. Plutôt que de diviser le tableau initial en blocs de plus en plus petits, vous pouvez commencer avec un cas de base et suivre un modèle récursif.

Le cas de base est [1] et [2, 1], qui sont les exemples des pires tableaux de taille 1 et 2. À partir de là, vous créez des tableaux pour 3 et 4 comme suit.

  1. Prenez deux tableaux de tailles n et m, tels que n + m = x, où x est la taille que vous recherchez
  2. Combinez-les, avec le tableau de plus petite taille placé en haut
  3. Doublez chaque élément du tableau supérieur
  4. Doublez chaque élément et soustrayez 1 du tableau du bas

En utilisant cet algorithme, voici la série d'étapes pour les tableaux de taille 3 et 4.

Exemples

Taille 3

  1. Prenez [1] + [2, 1]
  2. Vous recevez [1 | 2, 1]
  3. [2 | 2, 1]
  4. [2 | 3, 1] -> [2, 3, 1]

Taille 4

  1. Prenez [2, 1] + [2, 1]
  2. Vous recevez [2, 1 | 2, 1]
  3. [4, 2 | 2, 1]
  4. [4, 2 | 3, 1] -> [4, 2, 3, 1]

Taille 7

  1. Prenez [2, 3, 1] + [4, 2, 3, 1]
  2. Vous recevez [2, 3, 1 | 4, 2, 3, 1]
  3. [4, 6, 2 | 4, 2, 3, 1]
  4. [4, 6, 2 | 7, 3, 5, 1] -> [4, 6, 2, 7, 3, 5, 1]

Il est facile de voir comment vous pouvez adopter cette approche et créer facilement des tailles de tableau énormes.

Programme

Voici une fonction python qui implémente cet algorithme.

import math

def worstCaseArrayOfSize(n):
    if n == 1:
        return [1]
    else:
        top = worstCaseArrayOfSize(int(math.floor(float(n) / 2)))
        bottom = worstCaseArrayOfSize(int(math.ceil(float(n) / 2)))
        return map(lambda x: x * 2, top) + map(lambda x: x * 2 - 1, bottom)
4
Morgan Wilde