Javascript의 sort ()는 어떻게 작동합니까?


94

다음 코드는이 배열을 숫자 순서로 어떻게 정렬합니까?

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

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

계산 결과가 ...

Less than 0 : "a"가 "b"보다 낮은 인덱스로 정렬됩니다.
0 : "a"와 "b"는 동일한 것으로 간주되며 정렬이 수행되지 않습니다.
0보다 큼 : "b"가 "a"보다 낮은 인덱스로 정렬됩니다.

정렬 과정에서 배열 정렬 콜백 함수가 여러 번 호출됩니까?

그렇다면 매번 함수에 어떤 두 숫자가 전달되는지 알고 싶습니다. 처음에는 "25"(a)와 "8"(b), "7"(a) 및 "41"(b)를 사용했다고 가정했습니다.

25 (a)-8 (b) = 17 (0보다 크므로 "b"를 "a"보다 낮은 인덱스로 정렬) : 8, 25

7 (a)-41 (b) = -34 (0보다 작으므로 "a"를 "b"보다 낮은 인덱스로 정렬 : 7, 41

두 세트의 숫자는 서로를 기준으로 어떻게 정렬됩니까?

고군분투하는 초보자를 도와주세요!


5
나는 이것이 왜곡 된 의미가되기를 바랍니다!
cw84

답변:


51

정렬 과정에서 배열 정렬 콜백 함수가 여러 번 호출됩니까?

그렇다면 매번 함수에 어떤 두 숫자가 전달되는지 알고 싶습니다.

다음을 통해 자신을 찾을 수 있습니다.

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

편집하다

이것은 내가 얻은 출력입니다.

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

8
대신 console.log를 실행하여 firebug 또는 html DIV 요소의 .innerHTML + = "comparing"+ a + ","+ b + "\ n";
Joshua

2
이 위키와 같은 사이트임을 기억하고 우리는 :) 더 잘 만들기 위해 다른 사람에게 답변을 편집 할 수 있습니다
파블로 페르난데스

7
새로운 ES6 구문에 대한 참고 사항 : array.sort((a,b) => a - b);유효한 구문
Sterling Archer

1
정렬 함수가 -ve를 반환하면 스왑하고 + ve하면 스왑되지 않습니다 ??
Mahi

2
@ShekharReddy 여전히 연산자를 사용하여 비교할 수 있습니다. 답변을 업데이트했습니다.
OscarRyz

44

JavaScript 인터프리터에는 일종의 정렬 알고리즘 구현이 내장되어 있습니다. 정렬 작업 중에 몇 번 비교 함수를 호출합니다. 비교 함수가 호출되는 횟수는 특정 알고리즘, 정렬 할 데이터 및 정렬 전 순서에 따라 다릅니다.

일부 정렬 알고리즘은 일반적인 경우보다 훨씬 더 많은 비교를 수행하기 때문에 이미 정렬 된 목록에서 제대로 수행되지 않습니다. 다른 사람들은 미리 정렬 된 목록에 잘 대처하지만 실적이 저조하도록 "속일 수있는"다른 경우가 있습니다.

단일 알고리즘이 모든 목적에 완벽하지 않기 때문에 일반적으로 사용되는 정렬 알고리즘이 많이 있습니다. 일반 정렬에 가장 자주 사용되는 두 가지는 Quicksortmerge sort 입니다. Quicksort는 종종 두 가지 중 더 빠르지 만 병합 정렬에는 전체적으로 더 나은 선택을 할 수있는 몇 가지 좋은 속성이 있습니다. 병합 정렬은 안정적 이지만 Quicksort는 그렇지 않습니다. 두 알고리즘 모두 병렬화 가능하지만 병합 정렬이 작동하는 방식은 병렬 구현을 더 효율적으로 만들고 나머지는 모두 동일합니다.

특정 JavaScript 인터프리터는 이러한 알고리즘 중 하나 또는 완전히 다른 것을 사용할 수 있습니다. 인 ECMAScript 표준은 산법을 지정하지 않는 순응 구현 사용해야합니다. 심지어 안정성에 대한 필요성을 명시 적으로 부인합니다.


1
FWIW, 기본 Quicksort는 성능 저하로 "속일 수있는"알고리즘 중 하나입니다. 간단한 형식에서는 이미 정렬되었거나 정확히 반전 된 목록에 대해 O (N ^ 2) 성능이 있습니다. 대부분의 라이브러리 Quicksort 알고리즘에는 이러한 일반적인 최악의 시나리오를 피하는 데 도움이되는 여러 가지 명확하지 않은 최적화가 있습니다.
Adisak

3
JavaScriptCore는 정렬되는 배열을 수정하는 비교기 함수에 대해 결정적으로 동작해야하기 때문에 정렬을 위해 실제로 AVL 트리를 사용합니다.
olliej


11

값 쌍이 한 번에 한 쌍씩 비교됩니다. 비교되는 쌍은 구현 세부 사항입니다. 모든 브라우저에서 동일하다고 가정하지 마십시오. 콜백은 무엇이든 될 수 있습니다 (따라서 문자열이나 로마 숫자 또는 1,0, -1을 반환하는 함수를 생각 해낼 수있는 다른 모든 항목을 정렬 할 수 있습니다).

JavaScript의 종류와 관련하여 명심해야 할 점은 안정성이 보장되지 않는다는 것입니다.


5

정렬 과정에서 배열 정렬 콜백 함수가 여러 번 호출됩니까?

네, 바로 그 거예요. 콜백은 배열의 요소 쌍을 비교하는 데 필요에 따라 순서를 결정하는 데 사용됩니다. 비교 함수의 구현은 숫자 정렬을 처리 할 때 비정형 적이 지 않습니다. 의 세부 사양 거나 일부 다른 더 읽기 사이트.


4

정렬 과정에서 배열 정렬 콜백 함수가 여러 번 호출됩니까?

이것은 비교 정렬이므로 N 개의 항목이 주어지면 콜백 함수는 Quicksort 와 같은 빠른 정렬을 위해 평균 (N * Lg N) 번 호출되어야합니다 . 사용 된 알고리즘이 Bubble Sort 와 같은 경우 콜백 함수가 평균 (N * N) 번 호출됩니다.

비교 정렬을위한 최소 호출 수는 (N-1)이며 이는 이미 정렬 된 목록을 감지하기위한 것입니다 (예 : 스왑이 발생하지 않는 경우 거품 정렬에서 일찍 종료).


3

깊은 지식

결과가 음수이면 a가 b보다 먼저 정렬됩니다.

결과가 양수이면 b가 a보다 먼저 정렬됩니다.

결과가 0이면 두 값의 정렬 순서가 변경되지 않습니다.

노트:

이 코드는 정렬 메서드 내부의 단계별보기입니다.

산출:

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

이 코드를 실행하십시오. 처음부터 끝까지 정확한 단계별 정렬 과정을 볼 수 있습니다.

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);

복사하여 콘솔에 붙여 넣었는데 정의되지 않은 상태로 반환되었습니다.
iPzard

0

의 동작 Array#sort과 비교기를 명확히하기 위해 시작 프로그래밍 과정에서 배운 이 순진한 삽입 정렬을 고려하십시오 .

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);

알고리즘으로 삽입 정렬의 선택을 무시하고 하드 코딩 된 비교기 : arr[j-1] > arr[j]. 여기에는 토론과 관련된 두 가지 문제가 있습니다.

  1. >연산자는 배열 요소하지만 객체가 응답하지 않는 등의 정렬 할 수있는 여러 가지의 쌍 호출 >(우리가 사용 된 경우 같은 사실이 될 것입니다 합리적인 방법으로 -).
  2. 숫자로 작업하는 경우에도 여기에서 구워진 오름차순 정렬 이외의 다른 배열을 원할 때가 있습니다.

comparefn익숙한 인수를 추가하여 이러한 문제를 해결할 수 있습니다 .

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));

이제 순진한 정렬 루틴이 일반화되었습니다. 이 콜백이 언제 호출되었는지 정확히 알 수 있으며 첫 번째 우려 사항에 답할 수 있습니다.

정렬 과정에서 배열 정렬 콜백 함수가 여러 번 호출됩니까? 그렇다면 매번 함수에 어떤 두 숫자가 전달되는지 알고 싶습니다.

아래 코드를 실행하면 함수가 여러 번 호출되고 console.log어떤 숫자가 전달되었는지 확인할 수 있습니다 .

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))
);

물어:

두 세트의 숫자는 서로를 기준으로 어떻게 정렬됩니까?

용어를 정확하게에 ab없는 세트 (그들이있는 거 번호 귀하의 예제에서) 배열의 라고요 객체 - 숫자.

진실은 구현에 따라 다르기 때문에 정렬 방법 은 중요하지 않습니다 . 삽입 정렬과 다른 정렬 알고리즘을 사용했다면 비교기가 다른 숫자 쌍에서 호출 될 수 있지만 정렬 호출이 끝날 때 JS 프로그래머에게 중요한 것은 결과 배열이 다음에 따라 정렬된다는 것입니다. comparator, comparator는 당신이 언급 한 계약을 준수하는 값을 반환한다고 가정합니다 (<0 when a < b, 0 when a === band> 0 when a > b).

내 사양을 위반하지 않는 한 내 정렬의 구현을 자유롭게 변경할 수있는 것과 같은 의미에서 ECMAScript의 구현은 언어 사양 의 범위 내에서 정렬 구현을 자유롭게 선택할 수 있으므로 Array#sort다른 비교기 호출을 생성 할 가능성이 높습니다. 다른 엔진에서. 논리가 특정 일련의 비교에 의존하는 코드를 작성하지 않을 것입니다 (비교기가 처음에 부작용을 생성해서는 안 됨).

예를 들어 V8 엔진 (작성 당시)은 배열이 미리 계산 된 요소 수보다 클 때 Timsort를 호출 하고 작은 배열 청크에 이진 삽입 정렬 을 사용합니다 . 그러나 그것은 불안정하고 다른 인수 순서와 비교기에 호출을 줄 가능성이있는 quicksort 를 사용했습니다 .

다른 정렬 구현은 비교기 함수의 반환 값을 다르게 사용하기 때문에 비교기가 계약을 준수하지 않을 때 놀라운 동작이 발생할 수 있습니다. 예제는 이 스레드 를 참조하십시오 .


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

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

산출

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

내 브라우저 (Google Chrome 버전 70.0.3538.77 (공식 빌드) (64 비트))에서 첫 번째 반복에서 인수 a는 배열 의 두 번째 요소 이고 인수 b는 배열 의 첫 번째 요소 입니다.

비교 함수가 반환되는 경우

  1. b보다 음수 값은 a로 앞으로 이동합니다.
  2. a보다 양의 값이 b로 이동합니다.
  3. 0 (0) a와 b는 그대로 유지됩니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.