web-dev-qa-db-fra.com

JavaScript rapide

Je cherche sur le Web depuis un moment et je me demande s’il existe une implémentation «stable» de facto de quicksort qui est généralement utilisée? Je peux écrire le mien mais pourquoi réinventer la roue ...

16
flavour404

Vous pouvez facilement "stabiliser" un type instable en utilisant un motif decorate-sort-undecorate

function stableSort(v, f)
{
    if (f === undefined) {
        f = function(a, b) {
            a = ""+a; b = ""+b;
            return a < b ? -1 : (a > b ? 1 : 0);
        }
    }
    var dv = [];
    for (var i=0; i<v.length; i++) {
        dv[i] = [v[i], i];
    }
    dv.sort(function(a, b){
              return f(a[0], b[0]) || (a[1] - b[1]);
            });
    for (var i=0; i<v.length; i++) {
        v[i] = dv[i][0];
    }
}

l'idée est d'ajouter l'index comme dernier terme de tri afin qu'il n'y ait plus deux éléments identiques et que, si tout le reste est identique, l'index d'origine sera le facteur discriminant.

13
6502
  1. Placez vos objets dans un tableau.
  2. Appelez Array.sort() . C'est très rapide.

    var array = [3,7,2,8,2,782,7,29,1,3,0,34];
    array.sort();
    console.log(array); // prints [0, 1, 2, 2, 29, 3, 3, 34, 7, 7, 782, 8]
    

Pourquoi cela s’imprime-t-il dans l’ordre lexicographique? C’est ainsi que array.sort() fonctionne par défaut, par exemple si vous ne fournissez pas de fonction de comparaison. Réparons cela.

    var array = [3,7,2,8,2,782,7,29,1,3,0,34];
    array.sort(function (a, b)
    {
        return a-b;
    });
    console.log(array); // prints [0, 1, 2, 2, 3, 3, 7, 7, 8, 29, 34, 782]
15
Matt Ball

Quicksort (récursif)

function quicksort(array) {
  if (array.length <= 1) {
    return array;
  }

  var pivot = array[0];
  
  var left = []; 
  var right = [];

  for (var i = 1; i < array.length; i++) {
    array[i] < pivot ? left.Push(array[i]) : right.Push(array[i]);
  }

  return quicksort(left).concat(pivot, quicksort(right));
};

var unsorted = [23, 45, 16, 37, 3, 99, 22];
var sorted = quicksort(unsorted);

console.log('Sorted array', sorted);

12
Benny Neugebauer

Un équivalent fonctionnel

En célébration de Javascript fonctionnel, qui semble être le dans la chose

pour le moment, en particulier compte tenu de l’extraordinaire addition de sucre syntaxique ES6 +. Fonctions de flèche et de déstructuration Je propose un équivalent fonctionnel très propre et court de la fonction quicksort. Je ne l'ai pas testé pour ses performances ni comparé à la fonction de tri rapide intégrée, mais cela pourrait aider ceux qui ont du mal à comprendre l'utilisation pratique d'un tri rapide. Compte tenu de sa nature déclarative, il est très facile de voir what se produit comme opposé à comment cela fonctionne.

Voici une version de JSBin sans commentaires https://jsbin.com/zenajud/edit?js,console

function quickSortF(arr) {
    // Base case
    if (!arr.length) return []

    // This is a ES6 addition, it uses destructuring to pull out the 
    // first value and the rest, similar to how other functional languages
    // such as Haskell, Scala do it. You can then use the variables as 
    // normal below
    const [head, ...tail] = arr,
          // here we are using the arrow functions, and taking full 
          // advantage of the concise syntax, the verbose version of
          // function(e) => { return e < head } is the same thing
          // so we end up with the partition part, two arrays,
          // one smaller than the pivot and one bigger than the 
          // pivot, in this case is the head variable
          left = tail.filter( e => e < head),
          right = tail.filter( e => e >= head)

       // this is the conquer bit of divide-and-conquer
       // recursively run through each left and right array
       // until we hit the if condition which returns an empty
       // array. These results are all connected using concat,
       // and we get our sorted array.
       return quickSortF(left).concat(head, quickSortF(right))           

}

const q7 = quickSortF([11,8,14,3,6,2,7]) 
//[2, 3, 6, 7, 8, 11, 14]
const q8 =  quickSortF([11,8,14,3,6,2,1, 7])
//[1, 2, 3, 6, 7, 8, 11, 14]
const q9 = quickSortF([16,11,9,7,6,5,3, 2])
//[2, 3, 5, 6, 7, 9, 11, 16]

console.log(q7,q8,q9)

Les commentaires devraient en fournir assez s’il n’est déjà pas clair ce qui se passe. Le code actuel est très court, sans commentaires, et vous avez peut-être remarqué que je suis not / un fan du point-virgule. :)

7
Faktor 10

Dans ce blog http://www.nczonline.net/blog/2012/11/27/computer-science-in-javascript-quicksort/ qui a signalé que Array.sort est implémenté en tri rapide ou fusionner le tri en interne.

Quicksort est généralement considéré comme efficace et rapide, de même que Utilisé par V8 comme implémentation de Array.prototype.sort () sur des tableaux Comportant plus de 23 éléments. Pour moins de 23 éléments, le V8 utilise l'insertion Triée [2]. Merge Sort est un concurrent du tri rapide, car il est également Efficace et rapide, mais présente l’avantage supplémentaire d’être stable. C’est la raison Pour laquelle Mozilla et Safari l’utilisent pour l’implémentation de Array.prototype.sort ().

et lorsque vous utilisez Array.sort, vous devez renvoyer -1 0 1 au lieu de true ou false dans Chrome. 

arr.sort(function(a,b){
  return a<b;
});
// maybe--> [21, 0, 3, 11, 4, 5, 6, 7, 8, 9, 10, 1, 2, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22]
arr.sort(function(a,b){
  return a > b ? -1 : a < b ? 1 : 0;
});
// --> [22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
6
jinwei

var array = [8, 2, 5, 7, 4, 3, 12, 6, 19, 11, 10, 13, 9];
quickSort(array, 0, array.length -1);
document.write(array);


function  quickSort(arr, left, right)
{
	var i = left;
	var j = right;
	var tmp;
	pivotidx = (left + right) / 2; 
	var pivot = parseInt(arr[pivotidx.toFixed()]);  
	/* partition */
	while (i <= j)
	{
		while (parseInt(arr[i]) < pivot)
		i++;
		while (parseInt(arr[j]) > pivot)
			j--;
		if (i <= j)
		{
			tmp = arr[i];
			arr[i] = arr[j];
			arr[j] = tmp;
			i++;
			j--;
		}
	}

	/* recursion */
	if (left < j)
		quickSort(arr, left, j);
	if (i < right)
		quickSort(arr, i, right);
	return arr;
}

4
Andriy

En utilisant ES6 reste, écartez:

smaller = (a, list) => list.filter(x => x <= a)
larger = (a, list) => list.filter(x => x > a)
qsort = ([x, ...list]) => (!isNaN(x))
    ? [...qsort(smaller(x, list)), x, ...qsort(larger(x, list))]
    : []
2
GChamon

Cet algorithme fonctionne presque aussi vite que l'implémentation par défaut De Array.prototype.sort en chrome.

function quickSort(t){
    _quickSort(t,0,t.length-1,0,t.length-1);
}

function _quickSort(t, s, e, sp, ep){   
    if( s>=e )  return;
    while( sp<ep && t[sp]<t[e] ) sp++;  
    if( sp==e )
        _quickSort(t,s,e-1,s,e-1);  
    else{
        while(t[ep]>=t[e] && sp<ep ) ep--;      
        if( sp==ep ){
            var temp = t[sp];
            t[sp] = t[e];
            t[e] = temp;
            if( s!=sp ){
                _quickSort(t,s,sp-1,s,sp-1);
            }
            _quickSort(t,sp+1,e,sp+1,e);            
        }else{
            var temp = t[sp];
            t[sp] = t[ep];
            t[ep] = temp;
            _quickSort(t,s,e,sp+1,ep);
        }
    }
}

quickSort time (ms): 738 
javaScriptTaille de temps (ms): 603

var m = randTxT(5000,500,-1000,1000);
VS(m);

function VS(M){
    var t;
    t = Date.now();
    for(var i=0;i<M.length;i++){
        quickSort(M[i].slice());
    }console.log("quickSort time (ms): "+(Date.now()-t));

    t = Date.now();
    for(var i=0;i<M.length;i++){
        M[i].slice().sort(compare);
    }console.log("javaScriptSort time (ms): "+(Date.now()-t));
}

function compare(a, b) {
    if( a<b )
        return -1;
    if( a==b )
        return 0;
    return 1;
}

function randT(n,min,max){
    var res = [], i=0;
    while( i<n ){
        res.Push( Math.floor(Math.random()*(max-min+1)+min) );
        i++;
    }
    return res; 
}
function randTxT(n,m,min,max){
    var res = [], i=0;
    while( i<n ){
        res.Push( randT(m,min,max) );
        i++;
    }
    return res; 
}
1
user3870075

Encore une autre démonstration de tri rapide, qui prend le milieu du tableau comme pivot sans raison particulière.

const QuickSort = function (A, start, end) {
    // 
    if (start >= end) {
        return;
    }
    // return index of the pivot
    var pIndex = Partition(A, start, end);
    // partition left side
    QuickSort(A, start, pIndex - 1);
    // partition right side
    QuickSort(A, pIndex + 1, end);
}

const Partition = function (A, start, end) {
    if (A.length > 1 == false) {
        return 0;
    }
    let pivotIndex = Math.ceil((start + end) / 2);
    let pivotValue = A[pivotIndex];
    for (var i = 0; i < A.length; i++) {
        var leftValue = A[i];
        // 
        if (i < pivotIndex) {
            if (leftValue > pivotValue) {
                A[pivotIndex] = leftValue;
                A[i] = pivotValue;
                pivotIndex = i;
            }
        }
        else if (i > pivotIndex) {
            if (leftValue < pivotValue) {
                A[pivotIndex] = leftValue;
                A[i] = pivotValue;
                pivotIndex = i;
            }
        }
    }
    return pivotIndex;

}

const QuickSortTest = function () {
    const arrTest = [3, 5, 6, 22, 7, 1, 8, 9];
    QuickSort(arrTest, 0, arrTest.length - 1);
    console.log("arrTest", arrTest);
}
// 
QuickSortTest();
1
Teoman shipahi

Version Slim:

function swap(arr,a,b){
    let temp = arr[a]
    arr[a] = arr[b]
    arr[b] = temp
    return 1
}

function qS(arr, first, last){
    if(first > last) return

    let p = first
    for(let i = p; i < last; i++)
        if(arr[i] < arr[last]) 
            p += swap(arr, i, p)

    swap(arr, p, last)

    qS(arr, first, p - 1)
    qS(arr, p + 1, last)
}

Testé avec des tableaux de valeurs aléatoires, et semble toujours être plus rapide que Array.sort ()

0
Matteo Marongiu

Tri rapide (ES6)

function quickSort(arr) {
    if (arr.length < 2) {
        return arr;
    }
    const pivot = arr[Math.floor(Math.random() * arr.length)];

    let left = [];
    let right = [];
    let equal = [];

    for (let val of arr) {
        if (val < pivot) {
            left.Push(val);
        } else if (val > pivot) {
            right.Push(val);
        } else {
            equal.Push(val);
        }
    }
    return [
        ...quickSort(left),
        ...equal,
        ...quickSort(right)
    ];
}

Quelques notes:

  • Un pivot aléatoire maintient l'algorithme efficace même lorsque les données sont triées.
  • Autant qu'il serait agréable d'utiliser Array.filter au lieu d'utiliser la boucle for of, comme certaines des réponses fournies ici, cela augmentera la complexité temporelle (vous pouvez utiliser Array.reduce à la place).
0
Lior Elrom

Ça y est !!!

function typeCheck(a, b){
  if(typeof a === typeof b){
    return true;
  }else{
    return false;
  }
}

function qSort(arr){
  if(arr.length === 0){
    return [];
  }

  var leftArr = [];
  var rightArr = [];
  var pivot = arr[0];

  for(var i = 1; i < arr.length; i++){
    if(typeCheck(arr[i], parseInt(0))){
      if(arr[i] < pivot){
        leftArr.Push(arr[i]);
      }else { rightArr.Push(arr[i]) } 
    }else{
      throw new Error("All must be integers");
    }
  }

  return qSort(leftArr).concat(pivot, qSort(rightArr));

}

var test = [];

for(var i = 0; i < 10; i++){
  test[i] = Math.floor(Math.random() * 100 + 2);
}

console.log(test);
console.log(qSort(test));
0
Adib Mohsin