算法,不改变正负数之间相对顺序重新排列数组.时间O(N),空间O(1)

来源:互联网 发布:it技术书籍 编辑:程序博客网 时间:2024/05/16 17:22
大概思路:
1,遍历数组,找到最小值,最大值,以及负数元素个数,然后设 s = 最小值绝对值,m = 最大值 + 1,k = 负数元素个数 - 1。

2,遍历数组,改变每个元素,设该元素为a, 改变后为 c = a+s + (m+s)*n, 其中,n为该元素在按照题目要求排序后的位置,其实不难得到,遍历过程中分别用两个变量保存当前正负元素的排序号,如果当前元素是负数,则第一个变量+1然后付值给n,如果是正数,则第二个变量+1然后付值给n,注意,第一个变量从0开始计数,第二个从k开始计数。

3,再次遍历数组,设每个元素为c,则c对(m+s)取余数后得到b,由于b= a+s => a = b-s,然后 (c -b)/(m+s) 得到n,也就是该元素的排序号,用此排序号进行占位排序,一个替一个一直到最大号。


简单的说如果把数组先变成正数,
A ={-1,8,-2,-3,2,7} , 最大元素 8 设m=8+1=9, -3最小设s=3,都加3=> {2,11,1,0,5,10}=B。

然后是用最大元素11加上1=12,即m+s=9+3=12 作为参数用于改变数组B每个元素,C={2+12*1, 11+12*4(也就是初始数组元素8到最后应该排在第4位), 1+12*2, 0+12*3, 5*12*5, 10*12*6}
初始数组A最大元素8=>m=8+1=9,也就是说m+s=9+3=12大于任何一个数组B中的元素,那么通过构造C中元素c=a+s+(m+s)*n我们不但能够存储原有A中元素a,还可以存储排序后的排号n.
原理等同于那个把整数变成浮点数的方法,但是我这里通过计算还原原来的元素以及排序号,c%(m+s)得到a+s,a可以还原,(c-a-s)/(m+s)得到排序号。

代码如下:

#include <limits>#include <iostream>using namespace std;int main(int argc, char **argv){const size_t size = 6;int A[size] = {-3,1,8,-2,1,2};//first step, find min, max int min = numeric_limits<int>::max();int max = numeric_limits<int>::min();//and number of elements which is less than 0//later used as unsigned elements new positionsize_t unsignedCnt = 0; for(size_t i = 0; i < size; ++i){if(A[i] < min)min = A[i];if(A[i] > max)max = A[i];if(A[i] < 0)++unsignedCnt;}++max;if(min < 0)min = -min;//signed elements first positionsize_t signedCnt = 0;//new position indexsize_t cnt = 0;for(size_t i = 0; i < size; ++i){//update element to make them greater than 0//and include a final position in if(A[i] < 0)cnt = ++signedCnt;elsecnt = ++unsignedCnt;//update element//cnt starts from 1A[i] = A[i] + min + (min + max) * cnt;}//in-place key index sortingfor(size_t i = 0; i < size; ++i){//if the element already put in right position continueif(A[i] <= max) continue;else{int temp = 0;int prev = A[i];size_t id = 0;do{temp = prev % (max + min);id = (prev - temp)/(min + max) - 1;prev = A[id];A[id] = temp - min;}while(id != i);}}for(size_t i = 0; i < size; ++i){cout << A[i]<<endl;}return 0;}


原创粉丝点击