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