首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

【竞赛】排序算法的最快实现-继续,该怎么处理

2012-02-27 
【竞赛】排序算法的最快实现-继续由于早上帖子不能访问,我只能忍痛结掉了。并根据现有的成绩分配了积分。澄清

【竞赛】排序算法的最快实现-继续
由于早上帖子不能访问,我只能忍痛结掉了。并根据现有的成绩分配了积分。

澄清一下这个竞赛的目的,是为了大家共同拿到几个排序的好的算法,注意是几个,而不是一个。
在不同的情况下,各个算法的表现是不同的。

新的测试代码可以自行定义测试的次数和随机的种子。 可以对测试结果自动排序。
下面给出新的测试代码框架。

完整代码太长,需要的请到这里获取, 其中包括已经在另一个帖子给出算法的测试。 http://blog.zhaoxq.java2000.net/v16

Java code
package sort;import java.util.Arrays;import java.util.Map;import java.util.Random;import java.util.TreeMap;/** * CSDN 排序竞赛 * @version 2008-06-24 07:31 */class TestSort {  static int MAX = 1000000; // 最大数据量  static int[] nums = new int[MAX]; // 特意移到类一级,免得他们需要时没有这个  static Map<Long, String> map = new TreeMap<Long, String>(); // 排序的结果,纳秒为单位了。  static long seed = 20080623;  private static void init() {    Random r = new Random(seed);    for (int i = 0; i < MAX; i++) {      nums[i] = r.nextInt(MAX);    }  }  private static String showResult() { // 这里随便选了几个进行排序结果的测试    return nums[1] + " " + nums[1234] + " " + nums[23456] + " " + nums[67890] + " " + nums[MAX - 1];  }  public static void main(String[] args) {    Random ran = new Random();    for (int i = 1; i <= 1; i++) { // 此处定义循环测试的次数      seed = ran.nextInt(999999999);      test();    }    for (String str : map.values()) {      System.out.print(str);    }  }  public static void test() {    long begin;    long end;    //    // 测试代码框架开始    init();    begin = System.nanoTime();    sort_JDK(nums);    end = System.nanoTime();    map.put((end - begin), String.format("%20s%15d %s\r\n", "sort_JDK=", (end - begin), showResult()));    // 测试代码框架结束    // 其它的测试代码将按照顺序逐个放到后面进行测试。    // 某些方法没有使用我提供的标准调用,造成我手工修改,引起不必要的问题。    // 请大家查看我测试的完整代码,并根据你的需求进行完善与修改。   }  public static int[] sort_JDK(int[] nums) {    Arrays.sort(nums);    return nums;  }}



请大家整理好自己的算法帖子,命名方法为
public static int[] sort_${CSDN_USERNAME}(int[] nums) 
比如
public static int[] sort_java2000_net(int[] nums) 
public static int[] sort_talent_marquis(int[] nums) {




[解决办法]

[解决办法]
看高手实现..........
[解决办法]
继续跟贴,记号!!
[解决办法]
关注一下 ...............
[解决办法]
继续关注 ...............
[解决办法]
单纯的数组排序似乎意义不大,
以前也专门研究过一段时间,
发现排序效率和给定的序列初始顺序有很大的关系,
而且对于中小规模序列,效率并没有实质性的提高,
例如十万个数据(对于中小规模的系统),
如果最好的排序算法与最差的算法差了100ms,
其实对于用户来说几乎毫无意义。
我在实际应用中最关心按索引排序,
例如有10000个学生Stru的实例,首先有个学号排序(id,这可以从数据库中通过sort获得),
后来要按照他们年龄或者身高排序,同时要记录原有的学号顺序。

[解决办法]
各种方法都有了,最后一种没见过。
个人感觉可以考虑空间换时间
[解决办法]
支持·
学习·
[解决办法]
改的john_sheep的,恐怕他的很难超越了.
改的好像还没以前的快,数分布的太均匀了.........
Java code
import java.util.Random;public class MarquisSort{    private static int[] resultData;        public static void main( String[] args )    {        int MAX = 100000;        int[] nums = new int[ MAX ];        Random r = new Random( 20080623 );        for( int i = 0; i < MAX; i++ )        {            nums[ i ] = r.nextInt( MAX );        }        long begin = System.currentTimeMillis();        int[] data = sort( nums );        long end = System.currentTimeMillis();        System.out.println( ( end - begin ) ); // 以这个时间为标准,越小越好。    }    public static int[] sort_vtudiv( int[] nums )    {                   int[] temp = new int[nums.length];        int max = getMax(temp)+1;        for(int i:nums)        {            temp[i]++;        }        int pos=0;        for (int i=0;i<max;i++)        {            if (temp[i]>0)            {                for(int l=0;l<temp[i];l++)                    nums[pos++]=i;            }        }        return nums;    }        private static int getMax( int[] data )    {        int max = 0;        for( int i=data.length;;i--)        {            if( 0!=data[i] )            {                max = i;                break;                            }        }        return max;    }} 


[解决办法]
mark!!!
[解决办法]
晕,大意了,没有注意到最大值已经定义了,在这种情况下,肯定是计数的天下,如果没有定义最大值,我还是相信基数是第一的(在整数的情况下)
[解决办法]

Java code
int max = nums.length;
[解决办法]
不好意思,态度不太好,向楼主和大家郑重认错,写了代码出来。 
核心思路是准备20080623个桶,把数字丢进去,再顺次取出来,复杂度O(n) 


C# code
using System;

namespace ConsoleApplication1
{
class Program
{
static int MaxRange = 20080623;
static void Main(string[] args)
{
Test(10*10000);
Console.Read();
Test(100*10000);
Console.Read();
Test(1000*10000);
Console.Read();
}
public static void Test(int MAX)
{
int[] nums = new int[MAX];
Random r = new Random(MaxRange);
for (int i = 0; i < MAX; i++)
{
nums[i] = r.Next(MAX);
}
long begin = System.DateTime.Now.Ticks;
Sort(nums);
long end = System.DateTime.Now.Ticks;
Console.WriteLine("总共" + MAX/10000 + "万数据,用时" + System.TimeSpan.FromTicks(end - begin).Milliseconds + "豪秒");
}

public static void Sort(int[] a)
{

int[] p = new int[MaxRange + 1];
for (int i = 0; i <= MaxRange; i++)
{
p[i] = 0;
}
for (int i = 0; i <a.Length; i++)
{
p[a[i]]++;
}
for (int i = 0, j = 0; i <= MaxRange; i++)
{
while (p[i] > 0)
{
a[j++] = i;
p[i]--;
}
}

}


}
}







10万需要187毫秒 
100万需要250毫秒 
1000万需要984毫秒 

可见需要时间和楼主给定的20080623范围有关,和数据量没关系。
[解决办法]
学习。。这样的帖子才是真正有意义的帖子。顶了。
[解决办法]
看来大家想法都是一样的,都是利用整数与平均分布这两个特性。
俺也想到了,就是动作慢了点。

我稍稍测试了一下:
cpu 的 / * + - 最耗时,
其次是 内存的变量赋值 耗时,
其次是 比较两个整数
然后是 ++ --
再然后是 分配内存

楼上前5名的算法都是一样的,有一个共同的特性:计算非常少,赋值次数很少(2n,无法避免的赋值次数)……

俺是想不到更快的方法了,关注中,说不定有个牛人看懂了random.nextInt();然后又找到了一个很简单的表达式,直接把值一个个赋给原数组了。
[解决办法]
声明:我那个基于n个人的改进算法不参赛,纯属为了精益求精。见 sort_sagezk2。希望还有更快的出现,期待。
另外我所知的改进顺序是:
... -> talent_marquis -> john_sheeping -> SageZk -> scf37 -> SageZk -> ...
如果有遗漏的请楼下回复。
[解决办法]
mark一下
[解决办法]
跟帖。。。。
[解决办法]
小弟不才,没写代码,只测试了代码
(只测试时间是1字头的最快的几个)
经测试,
sort_sagezk2
sort_scf37
sort_roofalison
sort_john_sheep
sort_lwouyang
中,只有sort_john_sheep是正确的,其它的都有数组越界
测试数组:
int[] nums = new int[]{45,1,97,25,10,37,5,68};
初步分析原因, 在LZ给出的数组中, nums.length 为:
static int MAX = 1000000;


而数数组中的最大元素为:
Random r = new Random(seed); 
for (int i = 0; i < MAX; i++) { 
nums[i] = r.nextInt(MAX); 
}
只能为:999999

当数组中最大元素大于数组长度时,
上述不正确的算法就会数组越界
[解决办法]
C# code 
using System; 

namespace ConsoleApplication1 

class Program 

static int MaxRange = 20080623; 
static void Main(string[] args) 

Test(10*10000); 
Console.Read(); 
Test(100*10000); 
Console.Read(); 
Test(1000*10000); 
Console.Read(); 

public static void Test(int MAX) 
{
int[] nums = new int[MAX]; 
Random r = new Random(MaxRange); 
for (int i = 0; i < MAX; i++) 

nums[i] = r.Next(MAX); 

long begin = System.DateTime.Now.Ticks; 
Sort(nums); 
long end = System.DateTime.Now.Ticks; 
Console.WriteLine("总共" + MAX/10000 + "万数据,用时" + System.TimeSpan.FromTicks(end - begin).Milliseconds + "豪秒");


public static void Sort(int[] a) 


int[] p = new int[MaxRange + 1]; 
for (int i = 0; i <= MaxRange; i++) 

p[i] = 0; 

for (int i = 0; i <a.Length; i++) 

p[a[i]]++; 

for (int i = 0, j = 0; i <= MaxRange; i++) 

while (p[i] > 0) 

a[j++] = i; 
p[i]--; 










10万需要187毫秒 
100万需要250毫秒 
1000万需要984毫秒 

[解决办法]
好贴留名,下班再好好学习。。。
[解决办法]
mark................
[解决办法]
C# code 
using System; 

namespace ConsoleApplication1 

class Program 

static int MaxRange = 20080623; 
static void Main(string[] args) 

Test(10*10000); 
Console.Read(); 
Test(100*10000); 
Console.Read(); 
Test(1000*10000); 
Console.Read(); 

public static void Test(int MAX) 
{
int[] nums = new int[MAX]; 
Random r = new Random(MaxRange); 
for (int i = 0; i < MAX; i++) 

nums[i] = r.Next(MAX); 

long begin = System.DateTime.Now.Ticks; 
Sort(nums); 
long end = System.DateTime.Now.Ticks; 
Console.WriteLine("总共" + MAX/10000 + "万数据,用时" + System.TimeSpan.FromTicks(end - begin).Milliseconds + "豪秒");


public static void Sort(int[] a) 



int[] p = new int[MaxRange + 1]; 

//多余代码,删除后性能大幅提高。
for (int i = 0; i <= MaxRange; i++)
{
p[i] = 0;
}

for (int i = 0; i <a.Length; i++) 

p[a[i]]++; 

for (int i = 0, j = 0; i <= MaxRange; i++) 

while (p[i] > 0) 

a[j++] = i; 
p[i]--; 







[解决办法]
算法局限性太大了!
也就是说针对性太强了!


从数组的生成方式来看,数组中的元素都是非负数且最大元素要小于数组长度
所以有算法要根据数据特征来定了,因此所谓的快速、归并、二分 ...都不在是
最优的了

比赛的这个排序数据规律性,局限性都太强了
之所以那几位排序的速度快,就是因为利用了数据的高度规律性,其实程序利用了这个规律,
根本就不需要机器太多的动作吗,时间当然少了

分析一个算法的思想吧:

public static int[] sort_sagezk2(int[] nums) {
final int LEN = nums.length;
int i, j, t, p;
//声明一个同样大小的数组,来记录要排序数组元素的规律
int[] temp = new int[LEN];
//把要排序的数组的规律性统统记录下来
//是这样记录的:我就假设要排序的数组nums是{2,0,0,0,1}

for (i = 0; i < LEN;) {
temp[nums[i++]]++;
}
//那么记录nums数组元素规律性的数组temp经过for循环以后就是{3, 1, 1, 0, 0}
//首先说一下temp的数组元素以及下标的含义:
//temp数组 的第0个元素是3 含义是:0这个元素在nums中出现了3次
//同理 1这个元素在nums中出现了1次 2这个元素在nums中出现了1次 3,4这两个元素在nums中出现了0次
//好友一个就是nums元素在temp中是以数组下标的形式存在的,天生已经排序


//所以,只需根据这个规律赋值nums数组就OK了,根本没有涉及到什么交换呀,排序呀
//说白了 整个排序的时间就是两次数组赋值花费的时间,靠,怎么会用那么长时间啊
for (i = 0, p = 0; i < LEN; ++i) {
if ((t = temp[i]) == 0)
continue;
for (j = 0; j < t; ++j) {
nums[p++] = i;
}
}

return nums;
}
[解决办法]
MARK 有时间研究一下
[解决办法]
耍点小花招,应该可以更快的.
请楼主再试试.

Java code
  public static int[] sort_john_sheep(int[] nums) {       int max = getMax_john_sheep(nums) + 1;       byte[] temp = new byte[max];       for (int i : nums) {         temp[i]++;       }       int pos = 0;           for (int i = 0; i < max; i++) {             if (temp[i] > 0) {               for (int l = 0; l < temp[i]; l++)                 nums[pos++] = i;             }           }        return nums;     }       private static int getMax_john_sheep(int[] data) {       int max = 0;       for (int i : data) {         if (i > max) {           max = i;         }       }       return max;     }
[解决办法]
我把桶排序写好了,一般情况下,桶排序应该比计数排序要快,但是我写的桶排序太慢了,
桶排序的思想是把元素按照区间【0,1)划分,然后再每一个区间上进行排序
[解决办法]
这种测试实际意义不大。
如果在实际应用中,首先应充分研究业务数据特点,根据研究结果确定算法。
[解决办法]
非常支持。
只是都在写代码,麻烦你给注释一些,更好的就写个简短的说明。

[解决办法]
数组排序算法已经研究几十年了,公认最快的是时间复杂度为 n*log n,空间复杂度为0的算法,
你们有可能讨论出比这快的吗?
[解决办法]
版主,我的这个代码,试了一下,感觉存在明显的问题,就是显示结果不唯一,或者不准确.能否讨论一下原因?(而且还存在,第一个方法已经排序完成,第二个方法排序已经排好的数组,的问题.)
只给出一个方法,其他代码不变.
Java code
public static void test() {        long begin;        long end;        //        // 测试代码框架开始        init();        begin = System.nanoTime();        sort_JDK(nums);        end = System.nanoTime();        map.put((end - begin), String.format("%20s%15d %s\r\n", "sort_JDK=", (end - begin), showResult()));        // 测试代码框架结束        begin = System.nanoTime();        sort_JDK(nums);        end = System.nanoTime();        map.put((end - begin), String.format("%20s%15d %s\r\n", "sort_JDK=", (end - begin), showResult()));               begin = System.nanoTime();        sort_JDK(nums);        end = System.nanoTime();        map.put((end - begin), String.format("%20s%15d %s\r\n", "sort_JDK=", (end - begin), showResult()));                // 其它的测试代码将按照顺序逐个放到后面进行测试。        // 某些方法没有使用我提供的标准调用,造成我手工修改,引起不必要的问题。        // 请大家查看我测试的完整代码,并根据你的需求进行完善与修改。       } 


[解决办法]
学习
[解决办法]
关于写算法这方面。印度程序员就不错,用最基本的算法 写每个人都能看懂的Code
而不会这么刻意去写高深的代码段,仅仅去完成一个很简单的算法
[解决办法]
靠,我找了半天不知道在哪点收藏。111只好回贴,留做纪念!!
[解决办法]

探讨
耍点小花招,应该可以更快的. 
请楼主再试试. 

Java code public static int[] sort_john_sheep(int[] nums) {
int max = getMax_john_sheep(nums) + 1;
byte[] temp = new byte[max];
for (int i : nums) {
temp[i]++;
}
int pos = 0;
for (int i = 0; i < max; i++) {
if (temp[i] > 0) {
for (int l = 0; l < temp[i]; l++…

[解决办法]
学习,牛人真多啊,佩服
[解决办法]
不错不错,顶下
[解决办法]
竟然又是好东西,太好了,谢谢,大家这么多的思想。
[解决办法]
发现这个东西已经是在讨论java语法的优化,算法还是john_sheep的,参考sagezk2我又小改了下,完全是小动作。

Java code
    public static int[] sort_scf37_2(int[] nums) {        final int max = nums.length;        int i=0,j=0,k=0,p=0;        int[] temp = new int[max];        for (; i < max; i++) {            temp[nums[i]]++;        }        for (; k < max; ++k) {            for (; j < temp[k]; ++j) {                nums[p++] = k;            }        }        return nums;    }
[解决办法]
关注一下 ...............
[解决办法]
不错,顶下,又是好东西
[解决办法]
探讨
看来大家想法都是一样的,都是利用整数与平均分布这两个特性。
俺也想到了,就是动作慢了点。

我稍稍测试了一下:
cpu 的 / * + -      最耗时,
其次是 内存的变量赋值  耗时,
其次是 比较两个整数
然后是  ++  --
再然后是 分配内存

楼上前5名的算法都是一样的,有一个共同的特性:计算非常少,赋值次数很少(2n,无法避免的赋值次数)……

俺是想不到更快的方法了,关注中,说不定有个牛人看懂了random.nex…

[解决办法]
排序方法,只要你敢想,就一定有好的创新思维的!呵呵
[解决办法]
玩算法了
o(∩_∩)o...
[解决办法]
mark
[解决办法]
留个记号。都太强了。呵呵。
[解决办法]
做个记号。。顺便学习
[解决办法]
Java code
public static int[] sort_sweetbai(int[] nums) {        // 您的排序代码放在这里啦        int[] copys = new int[nums.length];        for (int i : nums) {            copys[i]=i;        }        return copys;    }
[解决办法]
mark
[解决办法]
学习了
[解决办法]
好久没搞了,真是忘了。看到你们算法,我也有兴趣想想。
------解决方案--------------------


昏 原帖结了啊~
[解决办法]
不知这个帖子是什么意思
难道还有比快速排序和归并排序更快的排序算法么?
[解决办法]

探讨
学习了

[解决办法]
学习

热点排行