调整数组顺序使奇数位于偶数前面

面试题14:调整数组顺序使奇数位于偶数前面

一.题目描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

二.分析问题

解法1

这个题目要求把奇数放在数组的前半部分,偶数放在数组的后半部分,因此所有的奇数应该位于偶数的前面。也就是说我们在扫描这个数组的时候,如果发现有偶数出现在奇数的前面,我们可以交换它们的顺序,交换之后就符合要求了。

因此我们可以维护两个指针,第一个指针初始化时指向数组的第一个数字,它只向后移动;第二个指针初始化时指向数组的最后一个数字,它只向前移动。在两个指针相遇之前,第一个指针总是位于第二个指针的前面。如果第一个指针指向的数字是偶数,并且第二个指针指向的数字是奇数,我们就交换这两个数字。

下面以一个具体的例子比如输入数组{1,2,3,4,5}来分析这种思路。

(a)把第一个指针指向数组的第一个数字,第二个指针指向最后一个数字。

(b)向后移动第一个指针直至它指向偶数2,此时第二个指针指向奇数5,不需要移动。

(c)交换两个指针指向的数字。

(d)向后移动第一个指针直至它指向偶数4,向前移动第二个指针直至它指向奇数3。由于第二个指针移到了第一个指针的前    面,表明所有的奇数都位于偶数的前面。

解法1的改进

如果把题目改成把数组中的数按照大小分为两部分,所有负数都在非负数的前面,该怎么做?

如果再把题目改改,变成把数组中的数分为两部分,能被3整除的数都在不能被3整除的数的前面。怎么办?

我们发现要解决这两个新的问题,其实只需要修改函数ReorderOddEven中的两处判断的标准,而大的逻辑框架完全不需要改动。因此我们可以把这个逻辑框架抽象出来,而把判断的标准变成一个函数指针,也就是用一个单独的函数来判断数字是不是符合标准。这样我们就把整个函数解耦成两部分:一是判断数字应该在数组前半部分还是后半部分的标准,二是拆分数组的操作。

三.代码

解法1

#include<stdio.h>
#include<stdlib.h>

void ReorderOddEven(int* pData, unsigned int Length)
{
	if (pData == NULL || Length == 0)
	{
		return;
	}
	int* p1 = pData;
	int* p2 = pData + Length + 1;

	while (p1 < p2)
	{
		/*向后移动p1,直到它指向偶数*/
		while (p1 < p2 && (*p1 & 0x1) != 0)
		{
			p1++;
		}

		/*向前移动p2,直到它指向奇数*/
		while (p1 < p2 && (*p2 & 0x1) == 0)
		{
			p2--;
		}

		if (p1 < p2)
		{
			int temp = *p1;
			*p1 = *p2;
			*p2 = temp;
		}
	}
}

void Show(int* arr,int Length)
{
	for (int i = 0; i < Length; ++i)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
	int arr[] = { 1,2,3,4,5,9,0,3,44};
	int len = sizeof(arr) / sizeof(int);
	Show(arr, len);
	ReorderOddEven(arr, len);
	Show(arr, len);
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值