快速稳定排序算法的javascript实现
我希望对大约200-300个对象的数组进行排序,根据特定键和给定顺序(asc/desc)进行排序。结果的顺序必须是一致和稳定的 使用哪种算法最好,您能提供一个javascript实现的示例吗快速稳定排序算法的javascript实现,javascript,algorithm,sorting,Javascript,Algorithm,Sorting,我希望对大约200-300个对象的数组进行排序,根据特定键和给定顺序(asc/desc)进行排序。结果的顺序必须是一致和稳定的 使用哪种算法最好,您能提供一个javascript实现的示例吗 谢谢 因为您正在寻找稳定的东西,所以合并排序应该可以 代码可在上述网站上找到: function mergeSort(arr) { if (arr.length < 2) return arr; var middle = parseInt(arr.length /
谢谢 因为您正在寻找稳定的东西,所以合并排序应该可以 代码可在上述网站上找到:
function mergeSort(arr)
{
if (arr.length < 2)
return arr;
var middle = parseInt(arr.length / 2);
var left = arr.slice(0, middle);
var right = arr.slice(middle, arr.length);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right)
{
var result = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length)
result.push(left.shift());
while (right.length)
result.push(right.shift());
return result;
}
函数合并排序(arr)
{
如果(arr.length<2)
返回arr;
var middle=parseInt(arr.length/2);
var left=arr.slice(0,中间);
var right=arr.slice(中间,arr.length);
返回merge(mergeSort(左)、mergeSort(右));
}
函数合并(左、右)
{
var结果=[];
while(left.length&&right.length){
如果(左[0],则可以从非稳定排序函数获得稳定排序
在排序之前,您将获得所有元素的位置。
在排序条件下,如果两个元素相等,则按位置排序
function stableSort(arr, cmpFunc) {
//wrap the arr elements in wrapper objects, so we can associate them with their origional starting index position
var arrOfWrapper = arr.map(function(elem, idx){
return {elem: elem, idx: idx};
});
//sort the wrappers, breaking sorting ties by using their elements orig index position
arrOfWrapper.sort(function(wrapperA, wrapperB){
var cmpDiff = cmpFunc(wrapperA.elem, wrapperB.elem);
return cmpDiff === 0
? wrapperA.idx - wrapperB.idx
: cmpDiff;
});
//unwrap and return the elements
return arrOfWrapper.map(function(wrapper){
return wrapper.elem;
});
}
塔达!你有一个稳定的类型
如果您想更多地了解这项技术以及如何实现它,我已经在我的博客上写了一篇关于它的文章:计数排序比合并排序快(它在O(n)时间内执行),并且用于整数
Math.counting_sort = function (m) {
var i
var j
var k
var step
var start
var Output
var hash
k = m.length
Output = new Array ()
hash = new Array ()
// start at lowest possible value of m
start = 0
step = 1
// hash all values
i = 0
while ( i < k ) {
var _m = m[i]
hash [_m] = _m
i = i + 1
}
i = 0
j = start
// find all elements within x
while ( i < k ) {
while ( j != hash[j] ) {
j = j + step
}
Output [i] = j
i = i + 1
j = j + step
}
return Output
}
Math.counting\u sort=函数(m){
变量i
var j
变量k
变步长
var启动
无功输出
var散列
k=米长
输出=新数组()
哈希=新数组()
//从最低可能值m开始
开始=0
步骤=1
//散列所有值
i=0
而(i
例如:
var uArray = new Array ()<br/>
var sArray = new Array ()<br/><br/>
uArray = [ 10,1,9,2,8,3,7,4,6,5 ]<br/>
sArray = Math.counting_sort ( uArray ) // returns a sorted array
var uArray=new数组()
var sArray=新数组()
uArray=[10,1,9,2,8,3,7,4,6,5]
sArray=Math.counting\u sort(uArray)//返回已排序的数组
我知道这个问题已经回答了一段时间了,但我的剪贴板中正好有一个很好的用于Array和jQuery的稳定合并排序实现,所以我将与大家分享,希望将来的搜索者会发现它很有用
它允许您指定自己的比较函数,就像普通的Array.sort
实现一样
实施
//向数组和jQuery原型添加稳定的合并排序
//注意:我们将其封装在一个封闭的容器中,这样它就不会污染全球环境
//名称空间,但我们没有将其放在$(document).ready中,因为它是
//不依赖于DOM
(功能(){
//向数组和jQuery公开
Array.prototype.mergeSort=jQuery.fn.mergeSort=mergeSort;
函数合并排序(比较){
var length=这个.length,
中间=数学楼层(长度/2);
如果(!比较){
比较=功能(左、右){
if(左<右)
返回-1;
如果(左==右)
返回0;
其他的
返回1;
};
}
如果(长度<2)
归还这个;
返回合并(
此.slice(0,中间).mergeSort(比较),
this.slice(中间,长度).mergeSort(比较),
比较
);
}
函数合并(左、右、比较){
var结果=[];
while(left.length>0 | | right.length>0){
if(left.length>0&&right.length>0){
if(比较(左[0],右[0])0){
结果。推(左[0]);
左=左。切片(1);
}
否则如果(右。长度>0){
结果.推送(右[0]);
右=右。切片(1);
}
}
返回结果;
}
})();
示例用法
var排序=[
“手指”,
“三明治”,
“三明治”,
"五块猪皮",,
“一个叫史蒂夫的家伙”,
“一些面条”,
“拖把和扫帚”,
“薯片品牌®薯片”
].mergeSort(函数(左、右){
lval=left.toLowerCase();
rval=right.toLowerCase();
console.log(lval、rval);
如果(左心室<右心室)
返回-1;
else if(lval==rval)
返回0;
其他的
返回1;
});
排序==[“5块猪皮”、“一个叫史蒂夫的家伙”、“手指”、“拖把和扫帚”、“薯片品牌®薯片”、“三明治”、“三明治”、“一些面条”];
从
var a=[34203,37462009848198764,9];
函数合并排序(arr)
{
如果(arr.length<2)
返回arr;
var middle=parseInt(arr.length/2);
var left=arr.slice(0,中间);
var right=arr.slice(中间,arr.length);
返回merge(mergeSort(左)、mergeSort(右));
}
函数合并(左、右)
{
var结果=[];
while(left.length&&right.length){
if(left[0]这是一个稳定的实现。它通过使用本机排序来工作,但在元素比较相等的情况下,您可以使用原始索引位置打破联系
function stableSort(arr, cmpFunc) {
//wrap the arr elements in wrapper objects, so we can associate them with their origional starting index position
var arrOfWrapper = arr.map(function(elem, idx){
return {elem: elem, idx: idx};
});
//sort the wrappers, breaking sorting ties by using their elements orig index position
arrOfWrapper.sort(function(wrapperA, wrapperB){
var cmpDiff = cmpFunc(wrapperA.elem, wrapperB.elem);
return cmpDiff === 0
? wrapperA.idx - wrapperB.idx
: cmpDiff;
});
//unwrap and return the elements
return arrOfWrapper.map(function(wrapper){
return wrapper.elem;
});
}
不彻底的测试
var res = stableSort([{a:1, b:4}, {a:1, b:5}], function(a, b){
return a.a - b.a;
});
console.log(res);
暗示了这一点,但没有发布给codez
但是,根据我的说法,它并不快。我修改了a以接受自定义比较器函数,而且速度更快。我必须按任意列对多维数组进行排序,然后再按另一列进行排序。我使用此函数对:
function sortMDArrayByColumn(ary, sortColumn){
//Adds a sequential number to each row of the array
//This is the part that adds stability to the sort
for(var x=0; x<ary.length; x++){ary[x].index = x;}
ary.sort(function(a,b){
if(a[sortColumn]>b[sortColumn]){return 1;}
if(a[sortColumn]<b[sortColumn]){return -1;}
if(a.index>b.index){
return 1;
}
return -1;
});
}
函数sortMDArrayByColumn(ary,sortColumn){
//将序列号添加到数组的每一行
//这是增加排序稳定性的部分
对于(var x=0;xb[sortColumn]){return 1;}
if(a[sortColumn]b.索引){
返回1;
}
返回-1;
});
}
请注意,ari.sort从不返回零,这是“sort”函数的一些实现做出可能不正确决定的地方
这也非常快。您也可以使用Timsort。这是一个非常复杂的算法(400多行,因此这里没有源代码),因此请查看或使用现有的Java之一
var res = stableSort([{a:1, b:4}, {a:1, b:5}], function(a, b){
return a.a - b.a;
});
console.log(res);
function sortMDArrayByColumn(ary, sortColumn){
//Adds a sequential number to each row of the array
//This is the part that adds stability to the sort
for(var x=0; x<ary.length; x++){ary[x].index = x;}
ary.sort(function(a,b){
if(a[sortColumn]>b[sortColumn]){return 1;}
if(a[sortColumn]<b[sortColumn]){return -1;}
if(a.index>b.index){
return 1;
}
return -1;
});
}
(a, b) => {
/* some way to compare a and b, returning -1, 0, or 1 */
};
(i, j) => {
let a = arrayToBeSorted[i], b = arrayToBeSorted[j];
/* some way to compare a and b, returning -1 or 1 */
return i - j; // fallback when a == b
}
/**
* - `array`: array to be sorted
* - `comparator`: closure that expects indices `i` and `j`, and then
* compares `array[i]` to `array[j]` in some way. To force stability,
* end with `i - j` as the last "comparison".
*
* Example:
* ```
* let array = [{n: 1, s: "b"}, {n: 1, s: "a"}, {n:0, s: "a"}];
* const comparator = (i, j) => {
* const ni = array[i].n, nj = array[j].n;
* return ni < nj ? -1 :
* ni > nj ? 1 :
* i - j;
* };
* stableSortInPlace(array, comparator);
* // ==> [{n:0, s: "a"}, {n:1, s: "b"}, {n:1, s: "a"}]
* ```
*/
function stableSortInPlace(array, comparator) {
return sortFromIndices(array, findIndices(array, comparator));
}
function stableSortedCopy(array, comparator){
let indices = findIndices(array, comparator);
let sortedArray = [];
for (let i = 0; i < array.length; i++){
sortedArray.push(array[indices[i]]);
}
return sortedArray;
}
function findIndices(array, comparator){
// Assumes we don't have to worry about sorting more than
// 4 billion elements; if you know the upper bounds of your
// input you could replace it with a smaller typed array
let indices = new Uint32Array(array.length);
for (let i = 0; i < indices.length; i++) {
indices[i] = i;
}
// after sorting, `indices[i]` gives the index from where
// `array[i]` should take the value from, so to sort
// move the value at at `array[indices[i]]` to `array[i]`
return indices.sort(comparator);
}
// If I'm not mistaken this is O(2n) - each value is moved
// only once (not counting the vacancy temporaries), and
// we also walk through the whole array once more to check
// for each cycle.
function sortFromIndices(array, indices) {
// there might be multiple cycles, so we must
// walk through the whole array to check.
for (let k = 0; k < array.length; k++) {
// advance until we find a value in
// the "wrong" position
if (k !== indices[k]) {
// create vacancy to use "half-swaps" trick,
// props to Andrei Alexandrescu
let v0 = array[k];
let i = k;
let j = indices[k];
while (j !== k) {
// half-swap next value
array[i] = array[j];
// array[i] now contains the value it should have,
// so we update indices[i] to reflect this
indices[i] = i;
// go to next index
i = j;
j = indices[j];
}
// put original array[k] back in
// and update indices
array[i] = v0;
indices[i] = i;
}
}
return array;
}
function stableSort(arr, compare) {
var original = arr.slice(0);
arr.sort(function(a, b){
var result = compare(a, b);
return result === 0 ? original.indexOf(a) - original.indexOf(b) : result;
});
return arr;
}
var stableSort = (arr, compare) => arr
.map((item, index) => ({item, index}))
.sort((a, b) => compare(a.item, b.item) || a.index - b.index)
.map(({item}) => item)
stableSort([5,6,3,2,1], (a, b) => a - b)
// sorted by weight
var input = [
{ height: 100, weight: 80 },
{ height: 90, weight: 90 },
{ height: 70, weight: 95 },
{ height: 100, weight: 100 },
{ height: 80, weight: 110 },
{ height: 110, weight: 115 },
{ height: 100, weight: 120 },
{ height: 70, weight: 125 },
{ height: 70, weight: 130 },
{ height: 100, weight: 135 },
{ height: 75, weight: 140 },
{ height: 70, weight: 140 }
]
stableSort(input, (a, b) => a.height - b.height)
// Items with the same height are still sorted by weight
// which means they preserved their relative order.
var stable = [
{ height: 70, weight: 95 },
{ height: 70, weight: 125 },
{ height: 70, weight: 130 },
{ height: 70, weight: 140 },
{ height: 75, weight: 140 },
{ height: 80, weight: 110 },
{ height: 90, weight: 90 },
{ height: 100, weight: 80 },
{ height: 100, weight: 100 },
{ height: 100, weight: 120 },
{ height: 100, weight: 135 },
{ height: 110, weight: 115 }
]
input.sort((a, b) => a.height - b.height)
var unstable = [
{ height: 70, weight: 140 },
{ height: 70, weight: 95 },
{ height: 70, weight: 125 },
{ height: 70, weight: 130 },
{ height: 75, weight: 140 },
{ height: 80, weight: 110 },
{ height: 90, weight: 90 },
{ height: 100, weight: 100 },
{ height: 100, weight: 80 },
{ height: 100, weight: 135 },
{ height: 100, weight: 120 },
{ height: 110, weight: 115 }
]