数组调整

本文探讨两种数组调整方法。一种是将负数排在零之前,零排在负数之前,可以使用快速排序的Partition方法或三指针法。另一种方法是保持负数和正数原有顺序,将负数移到前面,正数移到后面,可通过辅助数组和二分搜索法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、一个整数数组存在若干的正数、负数和零,如何调整使负数排在零的前边,零排在负数的前边。

很容易想到使用快速排序的Partition方法,选择0作为基准,先将非负数调整到左边,正数调整到右边,然后对于非负数在进行一次调整。

void ArrayArrange(int* pData, int len){
	assert(pData!=NULL);
	int positiveIndex = 0;
	int nonpositiveIndex = 0;
	while (positiveIndex < len){
		if (pData[positiveIndex]<=0){
			if (positiveIndex!=nonpositiveIndex){
				pData[positiveIndex] ^= pData[nonpositiveIndex];
				pData[nonpositiveIndex] ^= pData[positiveIndex];
				pData[positiveIndex] ^= pData[nonpositiveIndex];
			}
			nonpositiveIndex++;
		}
		positiveIndex++;
	}
	int zeroIndex = 0;
	int nevigateIndex = 0;
	while (zeroIndex < nonpositiveIndex){
		if (pData[zeroIndex] < 0){
			if (zeroIndex!=nevigateIndex){
				pData[nevigateIndex] = pData[zeroIndex];
				pData[zeroIndex] = 0;
			}
			nevigateIndex++;
		}
		zeroIndex++;
	}
}

另法:使用三个index,positiveIndex指示下一个正数位置,zeroIndex指示下一个0位置,negitiveIndex指示下一个负数位置,然后只需扫描一遍数组。

void ArrayArrange(int*pData, int len){
	assert(pData!=NULL);
	int positiveIndex = 0;
	int zeroIndex = 0;
	int negitiveIndex = 0;
	while (positiveIndex < len){
		if (pData[positiveIndex]==0){
			if (zeroIndex != positiveIndex){
				pData[positiveIndex] = pData[zeroIndex];
				pData[zeroIndex] = 0;
			}
			zeroIndex++;
		} else if (pData[positiveIndex]<0){
			if (negitiveIndex!=positiveIndex){
				int tmp = pData[negitiveIndex];
				pData[negitiveIndex] = pData[positiveIndex];
				if (tmp == 0){
					if (zeroIndex != positiveIndex){
						pData[positiveIndex] = pData[zeroIndex];
					}
					pData[zeroIndex] = 0;
				} else {
					pData[positiveIndex] = tmp;
				}
			}
			zeroIndex++;
			negitiveIndex++;
		}
		positiveIndex++;
	}
}


 

2、变原

快排的Partition对数组进行调整之后,正数和负数的相对位置发生变化。

初步想法是使用两个辅助数组,一个保存负数的顺序,一个保存正数的顺序(如果存在0,可以使用一个计数器保存0的个数),遍历一遍数组,将数组分成负数部分和正数部分,然后再根据这两个数组填充回原数组。

网上搜了一下别人的实现方法,捋了捋:

(递归,二分搜索法)先遍历一遍数组,然后可以得到负数的数目n和正数的数目p,将数组分成两部分,前半部分L1含n个元素,后半部分L2含p个元素,则L1中正数的数目和L2种负数的数目相等,如果两部分已经是负数在前正数在后且相对位置不变的状态,则将L1中后半部分正数和L2中前半部分负数对应交换,则得到的数据序列将是满足负数排在前边,且原先负数和正数的排列顺序不变。

 

//将数组里的负数排在数组的前面,正数排在数组的后面。并且返回数组中负数的个数
int ArrayArrangeCore(int* pData, int len){
	if (len == 0)
		return 0;
	if (len == 1)
		return pData[0]<0?1:0;
	int negitiveCount = 0;
	for (int i=0; i<len; i++)
		if (pData[i] < 0)
			negitiveCount++;
	if (negitiveCount==0 || negitiveCount==len)	//数组中全是负数或者没有负数,此时的序列已经满足条件
		return negitiveCount;
	int leftCount = ArrayArrangeCore(pData, negitiveCount);	//左半部分中负数数目
	int rightCount = ArrayArrangeCore(pData+negitiveCount, len-negitiveCount);	//右半部分中负数数目
	for (int i=0; i<(negitiveCount-leftCount); i++){
		//交换前后数组中的正负值
		pData[leftCount+i] ^= pData[negitiveCount+i];
		pData[negitiveCount+i] ^= pData[leftCount+i];
		pData[leftCount+i] ^= pData[negitiveCount+i];
	}
	return negitiveCount;
}
//将数组里的负数排在数组的前面,正数排在数组的后面。但不改变原先负数和正数的排列顺序。
void ArrayArrange(int* pData, int len, bool b1, bool b2){
	assert(pData!=NULL);
	ArrayArrangeCore(pData, len);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值