** edit ** Сначала взглянем на собственный метод массива .sort ().Он оставляет исходный массив без изменений и принимает функцию сравнения.Последнее делает .sort () довольно мощным.
var input = [28,32,21,11,8,2,14,32,64];
var low2high = function ( a , b ) {
return a > b;
};
var high2low = function ( a , b ) {
return a < b;
};
var resultHigh2low = input.sort( high2low ); // [ 64,32,32,28,21,14,11,8,2 ];
var resultLow2high = input.sort( low2high ); // [ 2,8,11,14,21,28,32,32,64 ];
Так что, если мы хотим использовать bubbleSort (ссылка предоставлена TJ Crowder, см. Комментарии OP), мы можем написать следующее:
// javascript bubbleSort implementation
var bubbleSort = function ( list , comparison ) {
var swapped;
var i;
var val;
list = [].concat( list ); // do not destroy original
comparison = ( typeof comparison == "function" ) ? comparison : function(a,b){return a > b;}
do {
i = list.length;
while ( --i ) {
if ( i && comparison( list[ i ] , comparison[ i-1] ) ) {
val = list[ i ];
list[ i ] = list[ i - 1 ];
list[ i - 1] = val;
swapped = true;
}
}
} while ( swapped );
return list;
}
// using comparison functions from previous example.
var resultHigh2low = bubbleSort( input , high2low ); // [ 64,32,32,28,21,14,11,8,2 ];
var resultLow2high = bubbleSort( input , low2high ); // [ 2,8,11,14,21,28,32,32,64 ];
Давайте пройдемся по ней шаг за шагом:
var bubbleSort = function ( list , comparison ) {
..code..
}
Наша функция принимает 2 параметра, первый - массив, а второй - опциональную функцию сравнения.
var swapped;
var i = list.length;
var val;
Мы сохраняем длину списка впеременную i
и объявим 2 пустые переменные (swapped
и val
), которые мы будем использовать позже.
list = [].concat( list ); // do not destroy original
Мы клонируем список, используя [].concat( array )
, и перезаписываем локальную *Переменная 1020 * оставляет исходную нетронутой.
comparison = ( typeof comparison == "function" ) ? comparison : function(a,b){return a > b;}
Мы проверяем аргумент typeof
comparison
, если это function
, мы используем этот аргумент, в противном случае мы откатимся сами по себе comparison
функция.Наша резервная функция сравнения вернет true
, если a
больше b
.
do {
..code..
} while ( swapped );
Цикл do / while будет запущен хотя бы один раз, наша переменная swapped
в настоящее время undefined
так что это будет истолковано как ложное.Если наша функция comparison
возвращает значение true, происходит перестановка, и переменная swapped
будет установлена в значение true, поэтому она будет повторяться снова.
while ( --i ) {
..code..
}
Здесь я выполняю цикл от длины списка вниз, *Оператор 1041 * ставится перед переменной i
, чтобы гарантировать, что она обрабатывается первой перед чем-либо, i--
сработает после оценки while
, что приведет к ошибочным результатам, поскольку list[ list.length ]
не существует.Я всегда так делаю (возможно, плохой хаббит), но если это вас смущает, переходите к абсолютной прозрачности.
if ( i && comparison( list[ i ] , comparison[ i-1] ) ) {
..code..
}
Сначала мы проверяем, имеет ли i
истинное значение (0 оценивается как ложное) изатем мы запускаем функцию comparison
, передавая list[ i ]
и list[ i - 1 ]
как параметры a
и b
.Если функция comparison
возвращает true
, мы выполняем своп.
val = list[ i ];
list[ i ] = list[ i - 1 ];
list[ i - 1] = val;
swapped = true;
Здесь я выполняю своп без использования метода .splice()
, это просто образованное предположение, но я считаю, чтоназначения выполняются быстрее, чем вызовы функций.Я использую переменную val
в качестве заполнителя.После того, как своп завершен, я установил для swapped
значение true, поэтому наш цикл do / while будет продолжен.
return list;
Хорошо ... вернем результат.
Я исключил некоторыепроверяет, например, что мы делаем, когда длина списка равна нулю и еще много чего.По сути, при написании вспомогательных функций нам также необходимо иметь дело с обработкой ошибок.Как, например, выдача TypeError, когда переданный аргумент сравнения не является функцией, гарантируя, что метод сравнения возвращает логическое значение и т. Д.