J'ai essayé d'écrire un algorithme de tri de fusion en Java:
static void merge(int[] sort, int l, int m, int r) { int[] cache_array = new int[r - l + 1]; int l_cache = l; int _mid = m + 1; for (int i = 0; i < r - l + 1; i++) { if (l > m) { cache_array[i] = sort[_mid]; _mid++; } else { if (_mid > r) { cache_array[i] = sort[l]; l++; } else { if (sort[l] >= sort[_mid]) { cache_array[i] = sort[l]; l++; } else { if (sort[_mid] > sort[l]) { cache_array[i] = sort[_mid]; _mid++; }}}} } for (int i = 0; i < cache_array.length; i++) { sort[i + l_cache] = cache_array[i]; } } static void mergeSort(int[] sort, int l, int r) { if (l < r) { int mid = (int)Math.floor((l + r - 1) / 2); mergeSort(sort, l, mid); mergeSort(sort, mid + 1, r); merge(sort, l, mid, r); } } public static void main(String[] args) { int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 }; mergeSort(a, 0, a.length - 1); for (int i : a) { System.out.println(i); } }
Mais il trie simplement une partie du tableau et remplace le reste par des zéros. J'ai essayé de changer le cache_array en LinkedList mais rien n'a changé et après avoir essayé le débogage, je n'ai rien trouvé non plus. J'apprécierais que vous m'aidiez et / ou me montriez un autre algorithme de tri Mergesort qui fonctionne pour Java. (J'ai utilisé cet algorithme car il fonctionnait pour Python et je voulais donc utiliser un code similaire en Java)
3 Réponses :
Voici comment j'écris l'algorithme de tri de fusion.
public static int[] mergeSort(int[] sort) { if(sort.length > 1) { int mid = sort.length / 2; int[] left = Arrays.copyOf(sort, mid); int[] right = Arrays.copyOfRange(sort, mid, sort.length); // sort the left and right arrays mergeSort(left); mergeSort(right); // Merge the arrays merge(sort, left, right); } } private static void merge(int[] sort, int[] leftArray, int[] rightArray) { // These values are just to keep track of our position in each of the 3 // arrays int l = 0; // left array int r = 0; // right array int o = 0; // the actual array being sorted while(l < leftArray.length && r < rightArray.length) { if(leftArray[l] < righArray[r]) { sort[o++] = leftArray[l++]; } else { sort[o++] = leftArray[r++]; } } // Now that we are out of the while loop we know that either the // left or right array has all of its values in sort, so we just // need to put the rest of the values in the array that doesn't have // all of its elements in sort with the following code. while(l < leftArray.length) { sort[o++] = leftArray[l++]; } while(r < rightArray.length) { sort[o++] = rightArray[r++]; } }
Votre proposition n'aide pas l'OP à identifier l'erreur dans son code. De plus, votre code tente de trier le tableau par ordre croissant tandis que l'OP le trie par ordre décroissant.
Le prototype de votre mergeSort
doit être public static void mergeSort (int [] sort)
ou vous devez renvoyer sort
. De plus, la branche else
de l'instruction if
dans merge
doit copier depuis rightArray
, et non depuis leftArray code>.
Le bogue dans votre code est difficile à repérer:
merge
itère pour i
de 0
à r - l + 1
exclu, ce qui serait correct si r
et l
restaient constants pendant la boucle, mais vous incrémentez l
à chaque fois que vous copiez à partir de la partie gauche, réduisant le nombre d'itérations. En conséquence, la boucle se termine tôt, laissant les éléments restants dans cache_array
avec leur valeur par défaut 0
. Il existe plusieurs sources de confusion dans le code:
r
dans la tranche est déroutante: elle nécessite des ajustements +1
/ -1
pour calculer les longueurs de tranche et le index du milieu. Math.floor ()
est inutile: l'arithmétique d'entiers utilise la division d'entiers en java. l
et m
est déroutant car ceux-ci perdent leur signification si la valeur est modifiée. Utilisez d'autres variables d'index pour parcourir les tableaux. {
entre les mots clés else
et if
introduit des niveaux d'indentation inutiles. cache_array
ne seraient pas modifiés. Cette dernière condition entraînerait des erreurs dans ce cas. Voici une version modifiée:
// merge adjacent slices of the `sort` array. // left slice has elements from `l` included to `m` excluded // right slice has elements from `m` included to `r` excluded static void merge(int[] sort, int l, int m, int r) { int len = r - l; int[] cache_array = new int[len]; for (int i = 0, ll = l, mm = m; i < len; i++) { if (ll >= m) { cache_array[i] = sort[mm]; mm++; } else if (mm >= r) { cache_array[i] = sort[ll]; ll++; } else if (sort[ll] >= sort[mm]) { cache_array[i] = sort[ll]; ll++; } else { cache_array[i] = sort[mm]; mm++; } } for (int i = 0; i < len; i++) { sort[l + i] = cache_array[i]; } } static void mergeSort(int[] sort, int l, int r) { if (r - l > 1) { int mid = l + (r - l) / 2; mergeSort(sort, l, mid); mergeSort(sort, mid, r); merge(sort, l, mid, r); } } public static void main(String[] args) { int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 }; mergeSort(a, 0, a.length); for (int i : a) { System.out.println(i); } }
Merci pour votre réponse en détail. Je pourrais corriger le code et maintenant ça marche!
Je l'implémente généralement comme ceci:
/// <summary> /// Mergesort /// best-case: O(n* log(n)) /// average-case: O(n* log(n)) /// worst-case: O(n* log(n)) /// </summary> /// <returns>The sorted array.</returns> /// <param name="array">array.</param> public static int[] MergeSort(int[] array) { // Exit condition for recursion if (array.length <= 1) return array; // Middle index of list to sort int m = array.length / 2; // Define left and right sub-listså int[] left_array = new int[m]; int[] right_array = new int[array.length - m]; // Initialize left list for (int i = 0; i < m; i++) left_array[i] = array[i]; // Initialize right list for (int i = m, x = 0; i < array.length; i++, x++) right_array[x] = array[i]; // Recursively sort left half of the list left_array = MergeSort(left_array); // Recursively sort right half of the list right_array = MergeSort(right_array); // Merge sorted sub-lists return Merge(left_array, right_array); } /// <summary> /// Merge the specified left_array and right_array. /// </summary> /// <returns>The merge.</returns> /// <param name="left_array">Left array.</param> /// <param name="right_array">Right array.</param> public static int[] Merge(int[] left_array, int[] right_array) { int[] m = new int[left_array.length + right_array.length]; int index_l = 0; int nl, nr; nl = left_array.length - 1; nr = right_array.length - 1; for (int i = 0; i <= nl + nr + 1; i++) { if (index_l > nl) { m[i] = (right_array[i - index_l]); continue; } if (index_l < i - nr) { m[i] = (left_array[index_l]); index_l++; continue; } if (left_array[index_l] <= (right_array[i - index_l])) { m[i] = (left_array[index_l]); index_l++; } else { m[i] = (right_array[i - index_l]); } } return m; }
Il y a quelques mois, j'ai écrit tous les algorithmes de tri courants et c'est ce que j'ai obtenu. Un peu inexact mais juste pour voir comment cette implémentation fonctionne. Les autres algorithmes sont ici.
Pour obtenir un ordre décroissant, je pense qu'il vous suffit d'échanger les opérateurs de comparaison.
Votre code implémente une approche différente: les OP trient le tableau en place tandis que votre code produit un nouveau tableau trié et laisse le tableau d'origine intact, sauf pour les tableaux avec un seul élément ou aucun élément. Notez également que votre approche nécessite un espace supplémentaire O (N.log (N)) , ce qui est inutile. Un espace supplémentaire O (N) devrait suffire.
Oh alors je reprendrai ma réponse!