Javascript'in sort () nasıl çalışır?


95

Aşağıdaki kod bu diziyi sayısal sıraya göre nasıl sıralamaktadır?

var array=[25, 8, 7, 41]

array.sort(function(a,b){
  return a - b
})

Biliyorum ki hesaplamanın sonucu ...

0'dan küçük : "a", "b" den daha düşük bir dizin olacak şekilde sıralanır.
Sıfır: "a" ve "b" eşit kabul edilir ve sıralama yapılmaz.
0'dan büyük: "b", "a" dan daha düşük bir dizin olacak şekilde sıralanır.

Dizi sıralaması geri çağrı işlevi, sıralama sırasında birçok kez çağrılır mı?

Öyleyse, her seferinde işleve hangi iki sayının aktarıldığını bilmek istiyorum. Önce "25" (a) ve "8" (b), ardından "7" (a) ve "41" (b) aldığını varsaydım, bu yüzden:

25 (a) - 8 (b) = 17 (sıfırdan büyük, bu nedenle "b" yi "a" dan daha düşük bir dizin olacak şekilde sıralayın): 8, 25

7 (a) - 41 (b) = -34 (sıfırdan küçük, bu nedenle "a" yı "b" den daha düşük bir dizin olacak şekilde sıralayın: 7, 41

İki sayı kümesi daha sonra birbirlerine göre nasıl sıralanır?

Lütfen mücadele eden bir acemiye yardım edin!


5
Umarım bu biraz anlamsızdır!
cw84

Yanıtlar:


51

Dizi sıralaması geri çağrı işlevi, sıralama sırasında birçok kez çağrılır mı?

Evet

Öyleyse, her seferinde işleve hangi iki sayının aktarıldığını bilmek istiyorum

Kendini şu şekilde bulabilirsin:

array.sort((a,b) => {
  console.log(`comparing ${a},${b}`);
  return a > b ? 1
               : a === b ? 0 
                         : -1;
});

DÜZENLE

Elimdeki çıktı bu:

25,8
25,7
8,7
25,41

8
bunun yerine firebug veya html DIV öğesinin .innerHTML + = "karşılaştırması" + a + "," + b + "\ n" için bir console.log yapın;
Joshua

2
Bu wiki benzeri sitede olduğunu unutmayın ve biz :) bunları daha iyi hale getirmek için başkalarına cevapları düzenleyebilirsiniz
Pablo Fernandez

7
Yeni ES6 sözdizimi için sadece bir not: array.sort((a,b) => a - b);geçerli sözdizimi
Sterling Archer

1
sıralama işlevi geri dönerse -ve sonra değiştirir ve + ve sonra değişmez ??
Mahi

2
@ShekharReddy karşılaştırmak için yine de operatörleri kullanabilirsiniz. Cevabı güncelledim.
OscarRyz

44

JavaScript yorumlayıcısının içinde yerleşik bir tür sıralama algoritması uygulaması vardır. Sıralama işlemi sırasında karşılaştırma işlevini birkaç kez çağırır. Karşılaştırma işlevinin çağrılma sayısı, belirli algoritmaya, sıralanacak verilere ve sıralamadan önceki sıraya bağlıdır.

Bazı sıralama algoritmaları, tipik durumda olduğundan çok daha fazla karşılaştırma yapmalarına neden olduğundan, önceden sıralanmış listelerde kötü performans gösterir. Diğerleri önceden sıralanmış listelerle iyi başa çıkabilir, ancak kötü performans göstermeleri için "kandırılabilecekleri" başka durumlar da vardır.

Ortak kullanımda olan birçok sıralama algoritması vardır çünkü tek bir algoritma tüm amaçlar için mükemmel değildir. Genel sıralama için en sık kullanılan ikisi Hızlı sıralama ve birleştirme sıralamasıdır . Quicksort genellikle ikisinden daha hızlıdır, ancak birleştirme sıralaması onu daha iyi bir genel seçim haline getirebilecek bazı güzel özelliklere sahiptir. Birleştirme sıralaması kararlıdır , ancak Hızlı Sırala değildir. Her iki algoritma da paralelleştirilebilir, ancak birleştirme sıralaması çalışma şekli paralel bir uygulamayı daha verimli hale getirir, diğer her şey eşittir.

Özel JavaScript yorumlayıcınız bu algoritmalardan birini veya tamamen başka bir şeyi kullanabilir. ECMAScript standart algoritma hangi belirtmez bir uyumlu uygulama kullanmalıdır. Hatta istikrar ihtiyacını açıkça reddediyor.


1
FWIW, temel Quicksort, kötü performans göstermesi için "kandırılabilen" algoritmalardan biridir. Basit formda, önceden sıralanmış veya tam olarak tersine çevrilmiş listeler için O (N ^ 2) performansına sahiptir. Çoğu kütüphane Quicksort algoritması, bu yaygın en kötü durum senaryolarından kaçınmaya yardımcı olan bir dizi açık olmayan optimizasyona sahiptir.
Adisak

3
JavaScriptCore, sıralanmakta olan diziyi değiştiren karşılaştırıcı işlevlerin karşısında belirleyici davranmak gerektiğinden, aslında sıralama için bir AVL ağacı kullanır.
olliej

ECMAScript standardı artık kararlılık gerektiriyor .
ggorlen

11

Değer çiftleri, birer birer karşılaştırılır. Karşılaştırılan çiftler bir uygulama ayrıntısıdır - her tarayıcıda aynı olacaklarını varsaymayın. Geri arama herhangi bir şey olabilir (böylece dizeleri veya Roma rakamlarını veya 1,0, -1 döndüren bir işlev bulabileceğiniz başka herhangi bir şeyi sıralayabilirsiniz).

JavaScript sıralamasıyla ilgili akılda tutulması gereken bir şey, kararlı olmasının garanti edilmemesidir.


5

Dizi sıralaması geri çağrı işlevi, sıralama sırasında birçok kez çağrılır mı?

Evet, aynen öyle. Geri arama, hangi sırada olmaları gerektiğini belirlemek için dizideki öğe çiftlerini karşılaştırmak için kullanılır. Karşılaştırma işlevinin bu uygulaması, sayısal bir sıralama ile uğraşırken atipik değildir. Ayrıntılar spec veya üzerinde bazı diğer daha okunabilir siteleri.


4

Dizi sıralaması geri çağrı işlevi, sıralama sırasında birçok kez çağrılır mı?

Bu N öğe verilen bir karşılaştırma sıralama olduğundan, geri arama işlevi hızlı sıralama gibi ortalama (N * Lg K) kez çağrılması gereken Quicksort . Kullanılan algoritma Kabarcık Sıralama gibi bir şeyse , geri arama işlevi ortalama (N * N) kez çalıştırılacaktır.

Bir karşılaştırma sıralaması için minimum çağrı sayısı (N-1) 'dir ve bu yalnızca önceden sıralanmış bir listeyi tespit etmek içindir (yani, takas olmazsa Kabarcık Sıralamasında erken çıkış).


3

Derin Bilgi

Sonuç negatifse a, b'den önce sıralanır.

Sonuç pozitifse b, a'dan önce sıralanır.

Sonuç 0 ise, iki değerin sıralama düzeninde hiçbir değişiklik yapılmaz.

NOT:

Bu kod, adım adım sıralama yönteminin içindeki görünümdür .

ÇIKTI:

let arr = [90, 1, 20, 14, 3, 55];
var sortRes = [];
var copy = arr.slice();		//create duplicate array
var inc = 0;	//inc meant increment
copy.sort((a, b) => {
	sortRes[inc] = [ a, b, a-b ];
	inc += 1;
	return a - b;
});
var p = 0;
for (var i = 0; i < inc; i++) {
	copy = arr.slice();
	copy.sort((a, b) => {
		p += 1;
		if (p <= i ) {
			return a - b;
		}
		else{
			return false;
		}
	});
	p = 0;
	console.log(copy +' \t a: '+ sortRes[i][0] +' \tb: '+ sortRes[i][1] +'\tTotal: '+ sortRes[i][2]);
}


0

bu kodu çalıştırın. Baştan sona sıralama sürecini adım adım tam olarak görebilirsiniz.

var array=[25, 8, 7, 41]
var count = 1;
array.sort( (a,b) => { 
console.log(`${count++}). a: ${a} | b: ${b}`);
return a-b;
});
console.log(array);

kopyalanıp konsola yapıştırıldı ve tanımsız olarak döndü.
iPzard

0

Davranışını Array#sortve karşılaştırıcısını açıklığa kavuşturmaya yardımcı olmak için , başlangıç ​​programlama kurslarında öğretilen bu saf ekleme sıralamasını düşünün :

const sort = arr => {
  for (let i = 1; i < arr.length; i++) {
    for (let j = i; j && arr[j-1] > arr[j]; j--) {
      [arr[j], arr[j-1]] = [arr[j-1], arr[j]];
    }
  }
};

const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array);
console.log("" + array);

Üzerinde algoritma, odak noktası olarak ekleme tür seçim yok sayılması kodlanmış karşılaştırıcı: arr[j-1] > arr[j]. Bunun tartışmayla ilgili iki sorunu vardır:

  1. >Operatör dizi öğelerinin ancak nesneler yanıt vermeyen gibi sıralamak isteyebilirsiniz birçok şeyi çiftleri üzerinde çağrılır >(biz kullanıldığında aynı doğru olurdu makul bir şekilde -).
  2. Sayılarla çalışıyor olsanız bile, çoğu zaman burada pişirilen yükselen türden başka bir düzenleme istersiniz.

comparefnAşina olduğunuz bir argüman ekleyerek bu sorunları çözebiliriz :

const sort = (arr, comparefn) => {
  for (let i = 1; i < arr.length; i++) {
    for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
      [arr[j], arr[j-1]] = [arr[j-1], arr[j]];
    }
  }
};

const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array, (a, b) => a - b);
console.log("" + array);

sort(array, (a, b) => b - a);
console.log("" + array);

const objArray = [{id: "c"}, {id: "a"}, {id: "d"}, {id: "b"}];
sort(objArray, (a, b) => a.id.localeCompare(b.id));
console.log(JSON.stringify(objArray, null, 2));

Şimdi saf sıralama rutini genelleştirildi. İlk endişelerinizi yanıtlayarak bu geri aramanın tam olarak ne zaman çağrıldığını görebilirsiniz:

Dizi sıralaması geri çağrı işlevi, sıralama sırasında birçok kez çağrılır mı? Öyleyse, her seferinde işleve hangi iki sayının aktarıldığını bilmek istiyorum

Aşağıdaki kodu çalıştırmak, evet, işlevin birçok kez çağrıldığını ve console.loghangi numaraların aktarıldığını görmek için kullanabilirsiniz :

const sort = (arr, comparefn) => {
  for (let i = 1; i < arr.length; i++) {
    for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
      [arr[j], arr[j-1]] = [arr[j-1], arr[j]];
    }
  }
};

console.log("on our version:");
const array = [3, 0, 4, 5];
sort(array, (a, b) => console.log(a, b) || (a - b));
console.log("" + array);

console.log("on the builtin:");
console.log("" + 
  [3, 0, 4, 5].sort((a, b) => console.log(a, b) || (a - b))
);

Sen sor:

İki sayı kümesi daha sonra birbirlerine göre nasıl sıralanır?

Terminoloji konusunda kesin olmak gerekirse ave sayı kümelerib değildir - bunlar dizideki nesnelerdir (örneğinizde sayılardır).

Gerçek şu ki, nasıl sıralandıkları önemli değil çünkü uygulamaya bağlı. Eklemeli sıralamadan farklı bir sıralama algoritması kullansaydım, karşılaştırıcı muhtemelen farklı sayı çiftlerinde çalıştırılırdı, ancak sıralama çağrısının sonunda JS programcısı için önemli olan değişmez, sonuç dizisinin şuna göre sıralanmasıdır. karşılaştırıcı, karşılaştırıcının belirttiğiniz sözleşmeye uyan değerler döndürdüğünü varsayarak (<0 ne zaman a < b, 0 ne zaman a === bve> 0 ne zaman a > b).

Aynı anlamda, benim spesifikasyonumu ihlal etmediğim sürece türümün uygulamasını değiştirme özgürlüğüne sahip olduğum gibi, ECMAScript uygulamaları, dil spesifikasyonu sınırları içinde sıralama uygulamasını seçmekte özgürdür , bu nedenle Array#sortmuhtemelen farklı karşılaştırıcı çağrılar üretecektir. farklı motorlarda. Mantığın belirli bir karşılaştırma dizisine dayandığı durumlarda kod yazılmaz (ya da karşılaştırıcı ilk etapta yan etkiler üretmemelidir).

Örneğin, V8 motoru (yazma sırasında) dizi önceden hesaplanan bazı öğelerden daha büyük olduğunda Timsort'u çağırır ve küçük dizi parçaları için ikili bir ekleme sıralaması kullanır . Bununla birlikte, kararsız olan ve muhtemelen karşılaştırıcıya farklı bir argüman ve çağrı dizisi verecek olan hızlı sıralama kullanırdı .

Farklı sıralama uygulamaları, karşılaştırıcı işlevinin dönüş değerini farklı şekilde kullandığından, karşılaştırıcı sözleşmeye uymadığında bu şaşırtıcı davranışlara yol açabilir. Bir örnek için bu konuya bakın .


-2
var array=[25, 8, 7, 41]

array.sort(function(a,b){
  console.log(`a = ${a} , b = ${b}`);
  return a - b
});

ÇIKTI

  • a = 8, b = 25
  • a = 7, b = 8
  • a = 41, b = 7
  • a = 41, b = 8
  • a = 41, b = 25

Tarayıcımda (Google Chrome Sürüm 70.0.3538.77 (Resmi Yapı) (64-bit)) ilk yinelemede, a bağımsız değişkeni dizideki İkinci öğedir ve bağımsız değişken b bir dizinin İlk öğesidir .

Karşılaştırma işlevi dönerse

  1. Negatif Değer, b'den daha ileriye doğru a'ya taşınır.
  2. a'dan daha pozitif değer, b'ye ileriye taşınır.
  3. 0 (Sıfır) hem a & b olduğu gibi kalacaktır.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.