时间:2022-11-15 09:47:00 | 栏目:JavaScript代码 | 点击:次
有一个整数数组,我们想按照特定规则对数组中的元素进行排序,比如:数组中的所有奇数位于数组的前半部分。
本文将带大家实现这个算法,欢迎各位感兴趣的开发者阅读本文。
我们通过一个实例来分析下:假设有这样一个数组:[2, 4, 5, 6, 7, 8, 9, 11],将奇数移动到最前面后,就是:[11, 9, 5, 7, 6, 8, 4, 2]。
通过观察后,我们发现在扫描这个数组的时候,如果发现有偶数出现在奇数的前面, 就交换他们的顺序,交换之后就符合要求了。
因此,我们可以维护两个指针:
在两个指针相遇之前,第一个指针总是位于第二个指针的前面。如果第一个指针指向的数字是偶数,并且第二个指针指向的数字是奇数,则交换这两个数字。
接下来,我们来通过图来描述下上述例子交换指针的过程,如下所示:
有了思路之后,我们来看下实现代码,如下所示:
export class AdjustArrayOrder { // 指向数组元素的两个指针:一个指向数组头部、一个指向数组尾部 private begin = 0; private end = 0; // 调整数组中奇数与偶数元素的位置:奇数位于偶数前面 reorderOddEven(arr: Array<number>): void { this.end = arr.length - 1; while (this.begin < this.end) { // 向后移动begin(转成二进制跟1做与运算,运算结果为0就表示为偶数),直至其指向偶数 while (this.begin < this.end && (arr[this.begin] & 0x1) !== 0) { this.begin++; } // 向前移动end(转成二进制跟1做与运算,运算结果为1就表示为奇数),直至其指向奇数 while (this.begin < this.end && (arr[this.end] & 0x1) === 0) { this.end--; } // begin指向了偶数,end指向了奇数 if (this.begin < this.end) { // 交换两个元素的顺序 [arr[this.begin], arr[this.end]] = [arr[this.end], arr[this.begin]]; } } // 重置指针位置 this.begin = 0; this.end = 0; } }
如果数组中的元素不按照奇前偶后排列,我们需要将其按照大小进行划分,所有负数都排在非负数的前面,应该怎么做?
聪明的开发者可能已经想到了方案:双指针的思路还是不变,我们只需修改内层while循环的的判断条件即可。
这样回答没有问题,确实解决了这个问题,那么如果再改改题目,我们需要把数组中的元素分为两部分,能被3整除的数都在不能被3整除的数前面,应该怎么做?
经过思考后,我们发现这个问题无论再怎么改变都有一个共同的部分:双指针的逻辑永远不会变。变化的只是判断条件,那么我们就可以把变化的部分提取成函数,当作参数让调用者传进来,这样就完美的解决了这个问题,也正是我们所提及的代码的可扩展性。
最后,我们来看下实现代码,如下所示:
// 元素排序 reorder(arr: Array<number>, checkFun: (checkVal: number) => boolean): void { this.end = arr.length - 1; while (this.begin < this.end) { // 向后移动begin while (this.begin < this.end && !checkFun(arr[this.begin])) { this.begin++; } // 向前移动end while (this.begin < this.end && checkFun(arr[this.end])) { this.end--; } // begin与end都指向了正确的位置 if (this.begin < this.end) { // 交换两个元素的顺序 [arr[this.begin], arr[this.end]] = [arr[this.end], arr[this.begin]]; } }
我们先来测试下奇数在偶数之前的函数处理代码能否正常执行,如下所示:
const adjustArrayOrder = new AdjustArrayOrder(); // 奇数在前 const arr = [2, 4, 5, 6, 7, 8, 9, 11]; adjustArrayOrder.reorderOddEven(arr); console.log(arr);
执行结果如下所示:
最后,我们来测试下reorder函数能否正常执行:
// 负数在前 const checkMinusNumber = function (val: number) { return val > 0; }; const arr = [2, 4, 5, 6, 7, -8, -10 - 12, -2]; adjustArrayOrder.reorder(arr, checkMinusNumber); console.log(arr);
const checkDivisible = function (val: number) { return val % 3 !== 0; }; const arr = [2, 4, 5, 6, 3, 6, 9, 12]; adjustArrayOrder.reorder(arr, checkDivisible); console.log(arr);
文中所举代码的完整版请移步: