调整数组元素顺序

简介: 调整数组元素顺序

前言


有一个整数数组,我们想按照特定规则对数组中的元素进行排序,比如:数组中的所有奇数位于数组的前半部分。


本文将带大家实现这个算法,欢迎各位感兴趣的开发者阅读本文。


实现思路


我们通过一个实例来分析下:假设有这样一个数组:[2, 4, 5, 6, 7, 8, 9, 11],将奇数移动到最前面后,就是:[11, 9, 5, 7, 6, 8, 4, 2]


通过观察后,我们发现在扫描这个数组的时候,如果发现有偶数出现在奇数的前面, 就交换他们的顺序,交换之后就符合要求了。


因此,我们可以维护两个指针:


  • 第一个指针初始化时指向数组的第一个数字,它只向后移动;
  • 第二个指针初始化时指向数组的最后一个数字,它只向前移动;


在两个指针相遇之前,第一个指针总是位于第二个指针的前面。如果第一个指针指向的数字是偶数,并且第二个指针指向的数字是奇数,则交换这两个数字。


接下来,我们来通过图来描述下上述例子交换指针的过程,如下所示:


  • 第一个指针永远指向偶数,如果不为偶数就向后移动;
  • 第二个指针永远指向奇数,如果不为奇数就向前移动;
  • 当两个指针各自指向的数都符合条件时,就交换两个元素的位置;
  • 交换完成后,重复上述步骤,直至两个指针相遇或者第一个指针位于第二个指针之后则代表问题已得到解决。


640.png

                            image-20220418224313591


实现代码


有了思路之后,我们来看下实现代码,如下所示:


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);


执行结果如下所示:

640.png

                              image-20220418230700388


最后,我们来测试下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);


640.png

                                image-20220418230947578


  • 能被3整除的数在数组的最前面
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);


640.png

                                   image-20220418231124400


示例代码


文中所举代码的完整版请移步:


  • AdjustArrayOrder.ts[1]
  • adjustArrayOrder-test.ts[2]


写在最后


至此,文章就分享完毕了。


我是神奇的程序员,一位前端开发工程师。


如果你对我感兴趣,请移步我的个人网站[3],进一步了解。

  • 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注😊
  • 文中链接可从文末参考资料中获取
相关文章
|
19天前
最短代码实现随机打乱数组各个元素的顺序
最短代码实现随机打乱数组各个元素的顺序
|
C++
【C/C++】用指针方法对10个整数按由大到小顺序排序
##下面我们将对21 12 45 43 87 897 534 67 90 75这10个数,用下面的程序进行由大到小排序。
317 0
【C/C++】用指针方法对10个整数按由大到小顺序排序
|
算法 容器
12.调整数组顺序,使得奇数在前,偶数在后
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
94 0
|
算法 Go
算法练习第十题——寻找重复数(不修改数组)
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
|
算法
Day1——数组 二分查找、移除一个数
Day1——数组 二分查找、移除一个数
87 0
Day1——数组 二分查找、移除一个数
找出数组中单独的元素
此类题目需要非常熟悉位操作及位运算,同时要画图思考,才能将思路整理得很清楚。 或许有很多读者对我提出疑问,他们会认为这只是针对我举例的数组,才会有这种结果。而我想说:你们可以有时间尝试换一换数组中的元素,并且打乱顺序,也是可以做到的。本篇博客的目的主要是阐明逻辑,因为思路很重要!
100 0
找出数组中单独的元素
获取最小操作次数使数组元素相等
获取最小操作次数使数组元素相等(算法题)
一道题,最小操作次数使数组元素相等引发的思考
给你一个长度为 n 的整数数组,每次操作将会使 n - 1 个元素增加 1 。返回让数组所有元素相等的最小操作次数。
89 0
一道题,最小操作次数使数组元素相等引发的思考
6176. 出现最频繁的偶数元素
6176. 出现最频繁的偶数元素
107 0
6176. 出现最频繁的偶数元素