#javascript #mergesort
#javascript #сортировка слиянием
Вопрос:
Я пытаюсь создать исправленную версию, но каждый раз сталкиваюсь с ошибками. mergeSort
Я несколько раз запускал debugger, и похоже, что все сортируется правильно до последнего шага, на котором я перехожу к строке в loader.js досье.
Кто-нибудь может помочь мне проверить это? Заранее спасибо!
Array.prototype.mergeSort = function(callback) {
if (this.length <= 1) return this;
if (!callback) {
callback = function(x, y) {
if (x > y) return -1;
else if (x < y) return 1;
else return 0;
};
}
const mid = Math.floor(this.length / 2);
const sortedLeft = this.slice(0, mid).mergeSort(callback);
const sortedRight = this.slice(mid).mergeSort(callback);
return sortedLeft.merge(sortedRight, callback);
};
Array.prototype.merge = function(arr, callback) {
let merged = [];
while (this.length > 0 || arr.length > 0) {
if (callback(this[0], arr[0]) < 0) {
merged.push(arr.shift());
break;
} else if (callback(this[0], arr[0]) >= 0) {
merged.push(this.shift());
break;
}
}
merged = merged.concat(this);
merged = merged.concat(arr);
return merged;
};
Комментарии:
1. Примечание стороны; ваша первая
callback = ...
часть фактически такая же, какreturn y - x;
2. Второе примечание;
} else if (callback(this[0], arr[0]) >= 0) {
это просто оператор else в паре с первым if .3. Понял по обоим пунктам, немного почистил его, но по какой-то причине все еще возникают проблемы.
4. @Taplar: не совсем, например
return y - x
, не обрабатывает строки, тогда как функция сравнения OP по умолчанию выполняет.5. @chqrlie если значения являются строковыми, вычитание в первую очередь не подходит, и вместо этого следует использовать собственный
localeCompare
.
Ответ №1:
Цикл слияния должен останавливаться, когда любой из списков пуст: вместо while (this.length > 0 || arr.length > 0)
того, чтобы вы должны написать:
while (this.length > 0 amp;amp; arr.length > 0)
Кроме того, вы не должны break
переходить из цикла после каждого сохранения в merge
массив, и излишне сравнивать элементы дважды.
Вот исправленная версия:
Array.prototype.merge = function(arr, callback) {
let merged = [];
while (this.length > 0 amp;amp; arr.length > 0) {
if (callback(this[0], arr[0]) < 0) {
merged.push(arr.shift());
} else {
merged.push(this.shift());
}
}
merged = merged.concat(this);
return merged.concat(arr);
};
Однако обратите внимание, что ваш merge
метод сортирует массив в порядке убывания, а callback
функция по умолчанию также сравнивает элементы в порядке убывания, в результате чего массив сортируется в порядке возрастания по совпадению. Возможно, вы захотите упростить это и принять null
функцию обратного merge
вызова.
Вот более общая версия:
Array.prototype.mergeSort = function(callback) {
if (this.length <= 1)
return this;
const mid = this.length >> 1;
const sortedLeft = this.slice(0, mid).mergeSort(callback);
const sortedRight = this.slice(mid).mergeSort(callback);
return sortedLeft.merge(sortedRight, callback);
};
Array.prototype.merge = function(arr, callback) {
let merged = [];
if (callback) {
while (this.length > 0 amp;amp; arr.length > 0) {
if (callback(this[0], arr[0]) <= 0) {
merged.push(this.shift());
} else {
merged.push(arr.shift());
}
}
} else {
while (this.length > 0 amp;amp; arr.length > 0) {
if (this[0] <= arr[0]) {
merged.push(this.shift());
} else {
merged.push(arr.shift());
}
}
}
return merged.concat(this).concat(arr);
};