【问题标题】:(Java) Heapsort - Implementation not sorting half elements?(Java) Heapsort - 实现不对半个元素进行排序?
【发布时间】:2012-11-04 00:28:08
【问题描述】:

我今天写了两个不同的堆排序实现,都给了我相同的结果:

Object i: 18
Object i: 11
Object i: 10
Object i: 9
Object i: 8
Object i: 3
Object i: 7
Object i: 1
Object i: 4

现在我用这个页面检查了我的代码here;并相信我的一个实现与伪代码所建议的完全相同,而另一个与 Java 实现之一非常相似。

我想强调一个事实,我实际上已经编写了两个不同的版本,并根据我能找到的实现检查了它们!所以我现在真的很难过!我已经用调试器逐步完成了几次 - 但可能在此过程中必须有一些东西?我什至做了一个调试函数,它只是循环遍历列表并使用System.out.println() 输出内容 - 但这仍然没有太大帮助!

算法正在处理一个列表 - 在这个阶段我没有做任何事情来优化它;目前这只是一个实验。我有 QuickSort、BubbleSort 和插入排序的工作实现 - 但这个让我很难过!

我的第一个实现如下:

public static List<Integer> execSort(List<Integer> s) {

    int n = (s.size()-1);
    Integer t;

    for(int i = n/2; i>0; i--){
        s = downheap(s, i, n);
    }

    while(n >= 1){
        t= s.remove(0);
        s.add(0, s.remove(n-1));
        s.add(n-1, t);

        n--;
        s = downheap(s, 1, n);
    } 

    return s;
}


public static List<Integer> downheap(List<Integer> s, int i, int n){
    Integer t = s.get(i-1);
    int j;

    while( i <= n/2 ){  
        j = i*2;

        if( (j<n) && (s.get(j-1) < s.get(j)))
            j++;

        if( t >= s.get(j-1)){
            break;
        } else {
            /* Swap them, without using a third variable 
                        - although with all the get()/set() methods
                        it would be better to have a third one, doh! */ 
            s.set(i-1, (s.get(i-1) + s.get(j-1)));
            s.set(j-1, (s.get(i-1) - s.get(j-1)));
            s.set(i-1, (s.get(i-1) - s.get(j-1)));

            i=j;
        }
    }

    s.set(i-1, t);
    return s;
}

您还可以在 Github 上将它们视为 Gists: - Implementation 1 - Implementation 2

关于为什么某些元素不想排序的任何想法?!我知道这个实现将是次优的,在 List 上工作是'不会是最好的数据结构,我可能应该考虑使用原始数据类型而不是(ab)使用自动装箱......但这是另一篇文章!我只想要一个工作版本,然后再尝试改进它;)

【问题讨论】:

    标签: java algorithm list sorting heapsort


    【解决方案1】:

    在要点中(您不小心将两者链接到同一个),您有一些拼写错误

    public static List<Integer> execSort(List<Integer> s) {
    
        int start = (s.size()/2)-1;
        int end = s.size()-1;
    
        while( start >= 0){
            s = sift(s, start, end);
    

    sift 将计数作为最后一个参数,而不是最后一个索引,因此参数应该是s.size()(或end+1)而不是end

    public static List<Integer> sift(List<Integer> s, int start, int count){
    
        int root = start;
    
        while( ((root*2)+1) < 2 ){
    

    那必须是while(root*2+1 &lt; count),而不是&lt; 2

    在您这里的代码中,您有部分相同的问题(我怀疑是由奇怪的索引策略引起的):

        for(int i = n/2; i>0; i--){
            s = downheap(s, i, n);
    

    因为你总是get(i-1) resp。 j-1downheap 中,在构建初始堆时需要s.size()n+1 的上限。

        }
    
        while(n >= 1){
    

    这个循环应该只在 n &gt; 1 时运行,否则你会交换最小的元素。

            t= s.remove(0);
            s.add(0, s.remove(n-1));
            s.add(n-1, t);
    

    旧根必须放在最后一个位置,即n,而不是n-1s.add(n,t)

            n--;
            s = downheap(s, 1, n);
        } 
    

    downheap,决赛

        s.set(i-1, t);
    

    是多余的,你总是交换t,所以当到达那行时,i-1处的元素已经是t

    【讨论】:

    • 不敢相信这是我在 github 上的原始实现中的一个错字(while 循环)。具有讽刺意味的是,我在那里做得比我检查其他代码以重写它时做得更好......!这是一个绝妙的答案,我非常感谢。尽管最后两个元素仍然是错误的方法,但毫无疑问我可以解决这个问题!再次感谢。
    猜你喜欢
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 2020-06-24
    • 2015-08-23
    • 1970-01-01
    • 2016-04-11
    • 2015-07-18
    • 1970-01-01
    相关资源
    最近更新 更多