我在其他地方的算法论坛上发现了一个问题。
我有一个带有随机数的数组(例如,[5, 2, 7, 9, 2, 3, 8, 4]
)应该返回给我,然后按奇数排序。赔率/赔率的顺序并不重要,因此在示例中它可能是[5, 7, 9, 3, 2, 2, 8, 4]
。
我的第一个想法是使用.reduce()
函数将它们分成两个不同的数组,然后将它们连接在一起,但这项任务有一些复杂性。
添加的任务规则是排序应保持一个恒定的额外空间,并在适当的位置修改数组。它还应该使用一种与数组大小一致的算法。
哪种算法?
根据Wikipedia's list来判断,有许多算法可以一致地扩展并使用恒定的空间量。我还发现this website有一个很好的冒泡排序可供使用(也在下面发布),看起来很稳定并遵循我的规则(我认为?)。
我不确定这是否是正确使用的算法,或者根本不知道如何处理这部分任务。
气泡:
function comparator(a, b) {
return a - b;
}
/**
* Bubble sort algorithm.<br><br>
* Complexity: O(N^2).
*
* @example
* var sort = require('path-to-algorithms/src/' +
* 'sorting/bubblesort').bubbleSort;
* console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
*
* @public
* @module sorting/bubblesort
* @param {Array} array Input array.
* @param {Function} cmp Optional. A function that defines an
* alternative sort order. The function should return a negative,
* zero, or positive value, depending on the arguments.
* @return {Array} Sorted array.
*/
function bubbleSort(array, cmp) {
cmp = cmp || comparator;
var temp;
for (var i = 0; i < array.length; i += 1) {
for (var j = i; j > 0; j -= 1) {
if (cmp(array[j], array[j - 1]) < 0) {
temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
return array;
}
答案 0 :(得分:18)
没有比较排序会线性扩展。幸运的是,您可以使用数组中的两个索引来执行此操作。这是基本的想法。
给定一个已填充的数组a
。
startIndex = 0
endIndex = a.length - 1
while (startIndex < endIndex)
{
// Skip over odd numbers at the front of the array
while (startIndex < endIndex && (a[startIndex] % 2) != 0)
++startIndex;
if (startIndex >= endIndex)
break;
// startIndex points to an even number
// now look for the first odd number at the end of the array
while (startIndex < endIndex && (a[endIndex] % 2) == 0)
--endIndex;
if (startIndex >= endIndex)
break;
// swap the two items, placing the even number
// towards the end of the array, and the odd number
// towards the front.
temp = a[startIndex];
a[startIndex] = a[endIndex];
a[endIndex] = temp;
// and adjust the indexes
++startIndex;
--endIndex;
}
所以,给出你的示例数组:
[5, 2, 7, 9, 2, 3, 8, 4]
首次通过循环,它发现索引1处的'2'是偶数。然后它从末尾向后搜索并在索引5处找到'3'。它交换它们:
[5, 3, 7, 9, 2, 2, 8, 4]
下一次循环,startIndex
将为2,endIndex
将为4. startIndex
增加超过'7'和'9',此时{{1}等于startIndex
,你就会脱离循环。
对于类似问题和类似算法,请参阅Dutch national flag problem。
答案 1 :(得分:10)
尝试使用简单排序,它可以提供您期望的结果
var data = [5, 2, 7, 9, 2, 3, 8, 4];
data.sort(function(a, b) {
return b % 2 - a % 2
});
console.log(data);
// [5, 7, 9, 3, 2, 2, 8, 4]
// % is mod, 5 % 2 = 1; 2 % 2 = 0;
答案 2 :(得分:5)
只需通过一个有条件地产生简单交换的索引,在O(1)空间的O(n)时间内,您可以执行以下操作。请注意,我已使用数组解构来交换。人们也可以选择使用临时变量。
function sortByParity(a){
var ec = 0; // Even count
for (var i = 0; i < a.length; i++){
a[i] & 1 ? [a[i],a[i-ec]] = [a[i-ec],a[i]] // If odd then swap accordingly
: ec++; // If even increment even count
}
return a;
}
var arr = [5,2,7,9,2,3,8,1,6,4],
brr = [0,2,4,6,8,1,3,5,7,9],
crr = [1,2,3,4,5,6,7,8,9,0];
console.log(JSON.stringify(sortByParity(arr)));
console.log(JSON.stringify(sortByParity(brr)));
console.log(JSON.stringify(sortByParity(crr)));
&#13;
编辑:因为@Nina Scholz建议通过计算赔率可以以类似的方式实现相同的算法,但看起来可能更简单。 (e & 1
实际上与e % 2
相同,用于测试奇偶校验。赔率将导致1(真),而均衡将导致0(假))
function sortByParity(arr){
var oc = 0;
arr.forEach((e,i,a) => e & 1 && ([a[i], a[oc++]] = [a[oc], a[i]]));
return arr;
}
var arr = [5,2,7,9,2,3,8,1,6,4],
brr = [0,2,4,6,8,1,3,5,7,9],
crr = [1,2,3,4,5,6,7,8,9,0];
console.log(JSON.stringify(sortByParity(arr)));
console.log(JSON.stringify(sortByParity(brr)));
console.log(JSON.stringify(sortByParity(crr)));
&#13;
答案 3 :(得分:4)
您可以使用与常用排序算法类似的方法,在恒定空间中对数组进行排序。
有一个变量来标记数组当前已排序部分的索引,然后处理它们之间的项目,或者将它们留在适当的位置(如果它们已经是奇怪的 - 就位已经排序) ,如果他们是平等的,或者将它们移到最后。
此算法为saveMessageToVariable
,空间要求是数组的大小。这两者都与阵列的大小成线性关系。
O(n)
&#13;
答案 4 :(得分:4)
已经发布了大量实现,所以我想指出这个问题在基本上任何基础设施中是如何解决的。
在攻击这个问题时,看看快速排序是有益的。或者不是快速排序,而是快速排序&#34;分区&#34;子操作,这解决了基本相同的问题。
&#34;分区&#34;子操作完成以下任务:给定一系列数字和一个枢轴,就地置换序列的元素,使得小于枢轴的所有数字都在序列的左侧,并且所有大于枢轴的数字都在序列的右侧。 (数字等于枢轴在中间结束,但除非你尝试真正的真正难以弄错,否则这将自动发生。)
这几乎完全我们在这里尝试做的事情:就地置换元素,使得它们基于二元测试分成两面。对于小于的快速排序;对于这个问题,它很奇怪。
因此,如果您正在查看这种性质的问题(基于二进制谓词的就地分区),最方便的攻击方法是复制粘贴代码库的分区操作。唯一相关的考虑因素是这里没有任何支点,所以请记住quicksort将其移至的位置,并且不要跳过该索引。
答案 5 :(得分:3)
如果您接受复制内存,可以使用普通的旧JavaScript函数执行此操作,因为您不希望子数组自行排序:
var res = [];
for(var i = 0; i < input.length; ++i)
If (input [i] % 2)
res.unshift (input[i])
else
res.push(input [i])
答案 6 :(得分:2)
是的,你首先想到计算奇数偶数的想法很好:
var input = [5, 2, 7, 9, 2, 3, 8, 4];
var result = input.filter(x => x%2).sort().concat(input.filter(x => x%2 === 0).sort());
console.log(result);
答案 7 :(得分:2)
从前面开始一个指针,它停在偶数值,另一个从最后一个停在奇数值。交换这两个值并继续,直到两个指针相互交叉。
此外,该算法具有复杂度O(n)。
function SortThisArray(arr) {
var startIndex = 0;
var endIndex = arr.length - 1;
while(startIndex < endIndex) {
if(arr[startIndex] % 2 == 0 && arr[endIndex] % 2 == 1) {
var temp = arr[startIndex];
arr[startIndex] = arr[endIndex];
arr[endIndex] = temp;
}
if(arr[startIndex] % 2 == 1)
startIndex++;
if(arr[endIndex] % 2 == 0)
endIndex--;
}
return arr;
}
答案 8 :(得分:2)
这是一个寻找连续的偶数和不均匀数字的提议。找到后,那对交换。
算法保持奇数和偶数组的顺序。
基本上,如果找到一对,它使用索引计数器和带有反向跟踪机制的while循环,那么如果索引大于零,则递减。
例如,这是数组的遍历:
array comment --------------------- -------------------------------- 5 7 2 8 7 9 2 1 4 6 8 found even odd couple at index 3 ^ ^ swap items, decrement index by 1 5 7 2 7 8 9 2 1 4 6 8 found even odd couple at index 2 ^ ^ 5 7 7 2 8 9 2 1 4 6 8 found even odd couple at index 4 ^ ^ 5 7 7 2 9 8 2 1 4 6 8 found even odd couple at index 3 ^ ^ 5 7 7 9 2 8 2 1 4 6 8 found even odd couple at index 6 ^ ^ 5 7 7 9 2 8 1 2 4 6 8 found even odd couple at index 5 ^ ^ 5 7 7 9 2 1 8 2 4 6 8 found even odd couple at index 4 ^ ^ 5 7 7 9 1 2 8 2 4 6 8 final result
var a = [5, 2, 7, 8, 7, 9, 2, 1, 4, 6, 8],
i = 0,
temp;
while (i < a.length - 1) {
if (!(a[i] % 2) && a[i + 1] % 2) {
temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
i && i--;
continue;
}
i++;
}
console.log(a); // [5, 7, 7, 9, 1, 2, 8, 2, 4, 6, 8]
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
这基本相同,但对已访问过的项目的迭代次数较少。
var a = [0, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 1],
i = 0,
j,
temp;
while (i < a.length - 1) {
j = i;
while (!(a[j] % 2) && a[j + 1] % 2) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
if (!j) {
break;
}
j--;
}
i++;
}
console.log(a);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
答案 9 :(得分:2)
据我所知,这是最简单的方法 - 如果您需要解释,请阅读@Dinesh Verma的答案
它是单次传递,仅使用3个变量作为额外存储
function sort(list)
{
var bottom=0
var top=list.length-1
var swap
while(bottom < top)
{
if (list[bottom] % 2 == 1)
++bottom
else if (list[top] % 2 == 0)
--top
else {
swap = list[bottom]
list[bottom] = list[top]
list[top] = swap
}
}
return list
}
答案 10 :(得分:0)
在这种情况下,最简单和最简单的方法是使用“按位操作数”进行访问 每个数组元素的最低有效位以及排序方法:
function sortArray(array) {
let safe = [];
let mysort = Array.prototype.sort;
let mysplice = Array.prototype.splice;
function zipit(arg){return arg[0];}
array.forEach(function(e){safe.push(e & 1);});
let odds = array.filter(function(e){
return (e & 1);}).sort(function(a,b){return a-b;});
let evens = array.filter(function(e){
return !(e & 1);}).sort(function(a,b){return b-a;});
let res = safe.map(function(ele,x){ return ( ele ) ? zipit(mysplice.call(odds,0,1)) : zipit(mysplice.call(evens,0,1));});
return res;
}
console.log(sortArray([2,3,2,1,5,6,7,8]));
就是这样。你得到一个完美的订单&amp;排序的赔率数组,......甚至。