一个关于特殊的排序问题的研究

6 篇文章 0 订阅
4 篇文章 0 订阅

在下面这个文章中的一个问题:

http://topic.csdn.net/u/20110928/15/0ef60bfb-8cb8-471d-a0f0-2b63f6680400.html?seed=1608405708&r=75815377#r_75815377


一个未排序整数数组,有正负数,重新排列使负数排在正数前面,并且要求不改变原来的 相对顺序 比如: input: 1,7,-5,9,-12,15 ans: -5,-12,1,7,9,15 要求时间复杂度O(N),空间O(1)

想了一种递归的方法:

1、扫描一次数组,找出分界线的位置,p,也就是说,排序完成以后,数组在p以及后面的位置上的所有数字都是正数。

2、第二次扫描由p划分开的两个字数组,这是左边包含的正数的个数和右边包含的负数的个数相等,直接通过一遍扫描可以进行一一对应的互换。为了进行后续的递归操作,这里的互换需要进行特殊的互换,互换的同时对数字取反。

3、对于每一个子数组来说,为了维持数字本来的顺序不变,例如前面的数组刚刚互换过来的负数已经被取反成为了正数,这样只需要递归的对子数组重复1的步骤进行排序即可。

4、所有的递归完成以后,将左边的所有数字置为负数,右边的所有数字置为正数。over


代码如下:


package test;

import java.util.Random;

public class SortFushu {
	int negs = 0;
	int len = 0;
	int first = 0, last = 0;
	int start = 0, end = 0;

	void sort(int[] d, int start, int end) {
		if (start >= end)
			return;
		len = end - start + 1;
		negs = 0;
		for (int i = start; i <= end; i++) {
			if (d[i] < 0)
				negs++;
		}
		if (negs == 0 || negs == len)
			return;
		first = start;
		last = start + negs;
		while (first < start + negs && last <= end) {
			if (d[first] > 0 && d[last] < 0) {
				int tmp = -d[first];
				d[first] = -d[last];
				d[last] = tmp;
				first++;
				last++;
			} else {
				if (d[first] < 0)
					first++;
				if (d[last] > 0)
					last++;
			}
		}
		int negs1 = negs;
		sort(d, start, start + negs - 1);
		sort(d, start + negs1, end);

	}

	void sort(int[] d) {
		int tag = 0;
		for (int i = 0; i < d.length; i++) {
			if (d[i] < 0)
				tag++;
		}
		sort(d, 0, d.length - 1);
		for (int i = 0; i < tag; i++) {
			d[i] = -1 * Math.abs(d[i]);
		}
		for (int i = tag; i < d.length; i++) {
			d[i] = Math.abs(d[i]);
		}

	}

	void sort1(int[] d) {
		int[] d1 = new int[d.length];
		System.arraycopy(d, 0, d1, 0, d.length);
		for (int i = 0; i < d.length; i++) {
			if (d[i] < 0)
				negs++;
		}
		first = 0;
		last = negs;

		for (int i = 0; i < d1.length; i++) {
			if (d1[i] < 0)
				d[first++] = d1[i];
			else
				d[last++] = d1[i];
		}

	}

	public static void main(String[] args) {
		// int[] d = { -1, 2, 3, 4, -3, 9, -5, 8, 9, -12, 15 };
		int n = 90000000;
		int[] d1 = new int[n];
		Random r = new Random();
		for (int i = 0; i < d1.length; i++) {
			d1[i] = 0;
			while (d1[i] == 0) {
				d1[i] = r.nextInt();
			}
		}
		long time = System.currentTimeMillis();
		new SortFushu().sort(d1);
		System.out.println(System.currentTimeMillis() - time);
		// for (int i = 0; i < d.length; i++) {
		// System.out.print(d[i] + "\t");
		// }
		// System.out.println();

	}
}



算法复杂度分析:

时间复杂度:F[n]=n+2*f[n/2]        O(nlogn)

空间复杂度:G[n]=1+G[n/2]         O(logn)


上面的方法sort1实现了一个简单的做法:使用另外的一个一样大小的数组,首先复制,然后通过两次的扫描完成排序

时间复杂度:    O(n)

空间复杂度:    O(n)


两种算法的比较:

时间上来说:

计算10000000数组大小的排序时间:

sort:4498ms

sort1:239ms

可见sort1要快很多


空间占用来说,对java虚拟机设置最大内存为-Xmx512m

sort:能够计算的最大的数组长度为:8900,0000(数组本身占用的空间为356M)

sort1:能够计算的最大的数组长度为:4350,0000(数组本身占用的空间为174M)


可见sort算法空间利用率更高,相同的条件下更够计算更大的数据。



附录,关于时间复杂度的计算主方法:

http://en.wikipedia.org/wiki/Master_theorem












  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值