思路1:直接遍历数组遇到偶数就移动到下一个奇数后(类似插入排序)但是这种算法的时间复杂度会很高,每碰到一个偶数就要移动O(n)个单位。算法复杂度O(n^2);非常低效率
优化思路1,提供一个相同长度的大小的数组,原数组遍历,遇到偶数放到新数组的最后一个位置,奇数顺序放入新数组。这样算法复杂度会降低到O(n),但需要空间复杂度O(n)的支持
再度优化,直接定义两个指针,一个从前向后找偶数,一个从后向前找奇数,当两个指针都找到对应的数字时,那就交换位置,直到两个指针相遇为止。
public void reOrderArray(int [] array) {
if(array.length <= 1 || array == null) return ;
int pBegin = 0 ;
int pEnd = array.length-1;
while(pBegin < pEnd){
//偶数二进制最后一位一定为0
while(pBegin < pEnd && (array[pBegin] & 1) != 0){
pBegin++;
}
while(pBegin < pEnd && (array[pEnd] & 1)== 0){
pEnd--;
}
if(pBegin < pEnd){
int temp = array[pBegin];
array[pBegin] = array[pEnd];
array[pEnd] = temp;
}
}
}
扩展:如果现在需求变成负数在前非负数再后怎么办?或者改成被三整除的数在前,不被整除的再后怎么处理。此时我们就要对方法进行解耦,我们把判断的依据当成参数去传进去。
public void reOrderArray1(int [] array, Compares c){
//把它解耦成分组和分组选择,我们把分组的选择定义成接口,
//如果是偶数在前奇数再后,那么就实现分组选择的接口中的方法,
if(array.length <= 1 || array == null) return ;
int pBegin = 0 ;
int pEnd = array.length-1;
while(pBegin < pEnd){
//偶数二进制最后一位一定为0
while(pBegin < pEnd && c.judge(array[pBegin])){
pBegin++;
}
while(pBegin < pEnd && !c.judge(array[pBegin])){
pEnd--;
}
if(pBegin < pEnd){
int temp = array[pBegin];
array[pBegin] = array[pEnd];
array[pEnd] = temp;
}
}
}
interface Compares{
boolean judge(int number);
}
class isEven implements Compares{
//具体实现
@Override
public boolean judge(int number) {
return (number & 1) == 0;
}
}
但是这样始终有一个缺陷,它无法实现稳定性。
思路2:
所以如果最终我们要让这种算法稳定,还是要使用双指针从前向后遍历,一个找奇数一个找偶数,找到则交换。但是同样我们也可以运用到解耦这个思想
public void reOrderArray(int [] array){
if(array.length < 2 || array == null) return;
//插入排序的思想来解决稳定性
int findEven = 0;
int findOdd = 0;
while(findEven < array.length) {
while (findEven < array.length && (array[findEven] & 1) != 0) {
findEven++;
}
findOdd = findEven + 1;
while (findOdd < array.length && (array[findOdd] & 1) == 0) {
findOdd++;
}
//找到第一个奇数之后,从偶数开始到奇数-1的位置向后移动,
// 然后把奇数放到之前偶数的位置上
if(findOdd < array.length){
int temp = array[findOdd];
for (int i = findOdd - 1; i >= findEven; i--) {
array[i+1] = array[i];
}
array[findEven++] = temp;
}else{
break;
}
}
}