不改变正负数之间的相对顺序重新排列数组,使得负数位于正数之前;
(1)举例:
如:1,7,-5,2,-9,3变成 -5,-9,1,7,2,3
(2)方法一:
从头到尾扫描数组,每次碰到一个正数时,就把位于这个数字之后的所有数字到往前挪动一位。挪动之后在数组的末尾有一个空位,把这个正数填进去。整体的时间复杂度为O(n^2),空间复杂度为O(1)
(3)方法二 :
快速排序中的划分partition,双向扫描,一个指针从左往右扫描直到遇到一个正数,另一个指针从右往左扫描直到遇到一个负数,然后交换两个数。但是遗憾的是这样会改变正负数之间的相对顺序。不能达到要求。
(4)方法三:
建立2个大小为n的队列,一个存储正数,一个存储负数,遍历数组,将正数添加到正数队列,负数添加到负数队列。然后分别将负数队列,以及正数队列出队到数组中。
时间复杂度为O(n),空间复杂度为O(n);
(5)方法四:
1)思想:
从右往左扫描,寻找最大最近的负数区间,以及该负数区间左边最大最近的正数区间,然后将这两个区间利用循环右移的方法移动,使得负数区间在正数区间的前面。
继续寻找最大最近的负数区间(在上一个负数区间的基础上),以及最大最近的正数区间。然后继续循环右移;。。。。。。。
(利用的是循环右移中,a,bcd->bcd,a中,bcd的相对顺序没有发生变化)
2)举例:
1,3,-1,2,-5,6(从右往左扫描,最大最近的负数区间为-5,它左边的最大最近正数区间为2)-》
1,3,-1,-5,2,6-》(最大最近的负数区间为-1,-5,2,其左边最大最近的正数区间为1,3)-》
-1,-5,1,3,2,6
3)实现:
/*字符串str[left,right]逆序。*/
void reverse(int *str ,int left ,int right){
char temp;
while(left<right){
temp=str[left];
str[left]=str[right];
str[right]=temp;
left++;right--;
}
}
/*将字符串str[left,right]循环右移k位*/
void loopShift(int * str, int left,int right,int k){
reverse(str,left,right-left-k);
reverse(str,right-k+1,right);
reverse(str,left,right);
}
void movesort(int a[], int len)
{
int n0, n1;
int p0, p1;
n0 = len-1;
while(n0>0)
{
while(n0>0 && a[n0]>0) n0--;
//从右往前寻找第一个负数
n1 = n0;//n0为最大最近负数区间的右边界
while(n1 -1>=0 && a[n1-1]<0) n1--;
//n1为最大最近负数区间的左边界
//n1-1是最大最近的负数区间的左边的第一个正数。
p0 = n1 - 1;//p0为最近最大正数区间的右边界
p1 = p0;//p1为最大最近的正数区间的左边界。
while(p1-1>=0 && a[p1-1]>=0) p1--;
if (n1>0 && p1>=0)
{
loopShift(a,p1,n0,n0-n1+1);
}else
break;
n0--;
}
}