不改变相对顺序,负数左边正数右边




不改变正负数之间的相对顺序重新排列数组,使得负数位于正数之前;

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值