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

题目:


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

方法一:


分析:该方法使用的是容器,准确的来讲不属于数组,因此用方法一来做此题很可能不会得分!

源代码:

#include<iostream>
#include<vector>

using std::cout;
using std::endl;
using std::vector;
using std::swap;

void Method1(vector<int> &vec)
{
	if (vec.empty() || vec.size() == 1)
		return;

	vector<int> vec_odd;
	vector<int> vec_even;

	for (auto it = vec.begin(); it != vec.end(); it++)
	{
		if ((*it & 0x1) != 0)//使用位运算代替求余运算,提高效率
			vec_odd.push_back(*it);
		else
			vec_even.push_back(*it);
	}

	vec.clear();
	for (auto it = vec_odd.cbegin(); it != vec_odd.cend(); it++)
		vec.push_back(*it);
	for (auto it = vec_even.cbegin(); it != vec_even.cend(); it++)
		vec.push_back(*it);

}

void Method2(vector<int> &vec)
{
	vector<int> vec_odd;
	vector<int> vec_even;

	for (auto it = vec.begin(); it != vec.end(); it++)
	{
		if ((*it & 0x1) != 0)
			vec_odd.push_back(*it);
		else
			vec_even.push_back(*it);
	}

	vec.swap(vec_odd);
	for (auto it = vec_even.cbegin(); it != vec_even.cend(); it++)
		vec.push_back(*it);

}

void Method3(vector<int> &vec)
{
	vector<int> vec_odd;
	vector<int> vec_even;

	for (auto it = vec.begin(); it != vec.end(); it++)
	{
		if ((*it & 0x1) != 0)
			vec_odd.push_back(*it);
		else
			vec_even.push_back(*it);
	}

	vec.assign(vec_odd.cbegin(), vec_odd.cend());
	vec.insert(vec.cend(), vec_even.cbegin(), vec_even.cend());
}

void test1()
{
	vector<int> vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	Method1(vec);
	for (auto it = vec.cbegin(); it != vec.cend(); it++)
		cout << *it << "  ";
	cout << endl;
}

void test2()
{
	vector<int> vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	Method2(vec);
	for (auto it = vec.cbegin(); it != vec.cend(); it++)
		cout << *it << "  ";
	cout << endl;
}

void test3()
{
	vector<int> vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	Method3(vec);
	for (auto it = vec.cbegin(); it != vec.cend(); it++)
		cout << *it << "  ";
	cout << endl;
}

int main()
{
	test1();
	test2();
	test3();

	system("pause");
	return 0;
}

运行结果:
1  3  5  7  9  0  2  4  6  8
1  3  5  7  9  0  2  4  6  8
1  3  5  7  9  0  2  4  6  8
请按任意键继续. . .

方法二:


此方法效率比较低,其思想如下:
如果前一个数是偶数,后一个数数是基数,则将两者进行交换;
如果前一个数是偶数,后一个数也是偶数,则寻找数组中下一个奇数,并将中间所有的偶数看做一个整体与后一个奇数交换位置;

代码如下:
#include<iostream>

using std::cout;
using std::endl;
using std::swap;

void Change(int arr[], int len)
{
	//挖坑法
	if (arr == NULL || len <= 1)
		return;


	for (int i = 0, j = 0; i < len - 1 && j < len;)
	{
		if (((arr[i] & 0x1) == 0) && ((arr[i+1] & 0x1) != 0))//偶数在前,奇数在后
		{
			swap(arr[i], arr[i+1]);
			++i;
		}
		else if ((arr[i] & 0x1) == 0 && (arr[i+1] & 0x1) == 0)//相邻的两个数都是偶数,则找下一个奇数的位置,然后将所有相邻的偶数看成一个整体向后移动
		{
			j = i + 1;
			while (((arr[j] & 0x1) == 0) )
				++j;
			if (j < len)
			{
				for (int k = j; k > i; k--)
					swap(arr[k - 1], arr[k]);
			}
			++i;
		}
	}
}

int main()
{
	int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	for (int i = 0; i < 10; i++)
		cout << arr[i] << "  ";
	cout << endl;

	Change(arr, 10);

	for (int i = 0; i < 10; i++)
		cout << arr[i] << "  ";
	cout << endl;

	system("pause");
	return 0;
}

运行结果:
0  1  2  3  4  5  6  7  8  9
1  3  5  7  9  0  2  4  6  8
请按任意键继续. . .

方法三:


使用两个指针,第一个指针指向数组的第一个元素,它只能向后移动,第二个指针指向数组的第二个元素,它只能向前移动。在两个指针相遇之前,第一个指针总是在第二个指针前面。如果第一个指针指向的是基数,则向后移动直至指向偶数为止,如果后一个指针指向的是偶数,则向前移动,直至后一个指针指向一个基数为止。然后交换。

源代码如下:
#include<iostream>

using std::cout;
using std::endl;
using std::swap;

void Change3(int arr[], int len)
{
	if (arr == NULL || len <= 1)
		return;
	
	int *p = arr;
	int *q = arr + len - 1;

	while (p < q)
	{
		while ((*p & 0x1) != 0 && p < q)//如果p指向奇数,则向后移动
			++p;
		while ((*q & 0x1) == 0 && p < q)//如果q指向偶数,则向前移动
			--q;
		if (p < q)//如果p指向偶数,q指向奇数,则交换
			swap(*p, *q);
	}
}

int main()
{
	int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	for (int i = 0; i < 10; i++)
		cout << arr[i] << "  ";
	cout << endl;

	Change3(arr, 10);

	for (int i = 0; i < 10; i++)
		cout << arr[i] << "  ";
	cout << endl;
	
	system("pause");
	return 0;
}

运行结果如下:
0  1  2  3  4  5  6  7  8  9
9  1  7  3  5  4  6  2  8  0
请按任意键继续. . .

分析:此种方法效率较高,且容易实现,但是在交换数据之后打乱了原有的整数顺序,而方法一和二维持了原有的数据的顺序。


方法四:


保留逻辑框架,使用指针函数针对不同功能实现不同的算法;

源代码如下:

#include<iostream>

using std::endl;
using std::cout;
using std::swap;

void Change4(int arr[], int len, bool(*func)(int num))
{
	if (arr == NULL || len <= 1)
		return;

	int *p = arr;
	int *q = arr + len - 1;

	while (p < q)
	{
		while (!(*func)(*p) && p < q)//如果p指向奇数,则向后移动
			++p;
		while ((*func)(*q) && p < q)//如果q指向偶数,则向前移动
			--q;
		if (p < q)//如果p指向偶数,q指向奇数,则交换
			swap(*p, *q);
	}
}

bool isEven(int num)
{
	return (num & 0x1) == 0;
}

int main()
{
	int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	for (int i = 0; i < 10; i++)
		cout << arr[i] << "  ";
	cout << endl;

	Change4(arr, 10, isEven);

	for (int i = 0; i < 10; i++)
		cout << arr[i] << "  ";
	cout << endl;

	system("pause");
	return 0;
}

运行结果和方法三一致!

官方源代码:

#include<iostream>

using std::endl;
using std::cout;
using std::swap;

void Change4(int arr[], int len, bool(*func)(int num))
{
	if (arr == NULL || len <= 1)
		return;

	int *p = arr;
	int *q = arr + len - 1;

	while (p < q)
	{
		while (!(*func)(*p) && p < q)//如果p指向奇数,则向后移动
			++p;
		while ((*func)(*q) && p < q)//如果q指向偶数,则向前移动
			--q;
		if (p < q)//如果p指向偶数,q指向奇数,则交换
			swap(*p, *q);
	}
}

bool isEven4(int num)
{
	return (num & 0x1) == 0;
}

int main4()
{
	int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	for (int i = 0; i < 10; i++)
		cout << arr[i] << "  ";
	cout << endl;

	Change4(arr, 10, isEven4);

	for (int i = 0; i < 10; i++)
		cout << arr[i] << "  ";
	cout << endl;

	system("pause");
	return 0;
}


运行结果:
Test1 begins:
Test for solution 1:
1       2       3       4       5       6       7
1       7       3       5       4       6       2
Test for solution 2:
1       2       3       4       5       6       7
1       7       3       5       4       6       2
Test2 begins:
Test for solution 1:
2       4       6       1       3       5       7
7       5       3       1       6       4       2
Test for solution 2:
2       4       6       1       3       5       7
7       5       3       1       6       4       2
Test3 begins:
Test for solution 1:
1       3       5       7       2       4       6
1       3       5       7       2       4       6
Test for solution 2:
1       3       5       7       2       4       6
1       3       5       7       2       4       6
Test4 begins:
Test for solution 1:
1
1
Test for solution 2:
1
1
Test5 begins:
Test for solution 1:
2
2
Test for solution 2:
2
2
Test6 begins:
Test for solution 1:


Test for solution 2:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值