【问题标题】:Why bubble sort is taking more time then selection sort为什么冒泡排序比选择排序花费更多时间
【发布时间】:2015-09-13 05:20:42
【问题描述】:

我正在尝试使用冒泡排序和选择排序的各种场景。 我知道如果我们使用 break 语句,冒泡排序的最佳情况是 O(n)。 但是可以说,即使我没有使用任何 break 语句,也不会有任何交换(因为我们有 if 条件),并且它应该花费与选择排序相同或更少的时间。

但奇怪的是它花费了我更多的时间。

注意:我采用了已经排序的相同数据集(1 到 900000)。 由于我使用的是已经排序的数据集,因此没有任何算法会有任何交换。

请在下面找到程序:

 package sorting;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class Sorting<Item extends Comparable>//this Item is a var/field which can only be find while creatng a object and hence it is non static
{

    List<Item> list=new ArrayList<Item>();

    public static void main(String args[])
    {

        Sorting<Integer> ss=new Sorting<Integer>();

        System.out.println("adding item logic started : "+Calendar.getInstance().getTime());
        for(int i=0;i<90000;i++)
        {
            ss.list.add(i);

        }
        System.out.println("adding item logic ended : "+Calendar.getInstance().getTime());
        //selection sort started
        Calendar c1=Calendar.getInstance();
        System.out.println(c1.getTime());
        ss.selectionSort(ss.list);

        Calendar c2=Calendar.getInstance();
        System.out.println(c2.getTime());
        System.out.println("selection sort time taken in seconds : "+(c2.getTimeInMillis()-c1.getTimeInMillis())/1000);
    //  System.out.println(ss.list);


        //bubble sort started
        ss.list=new ArrayList<Integer>();
        for(int i=0;i<90000;i++)
        {
            ss.list.add(i);

        }
        Calendar c3=Calendar.getInstance();
        System.out.println(c3.getTime());
        ss.bubbleSort(ss.list);

        Calendar c4=Calendar.getInstance();
        System.out.println(c4.getTime());
        System.out.println("bubble sort time taken in seconds : "+(c4.getTimeInMillis()-c3.getTimeInMillis())/1000);
    //  System.out.println(ss.list);
    }

    void selectionSort(List<Integer> list)
    {
        for(int i=0;i<list.size();i++)
        {
            int target=(Integer)list.get(i);
            int pos=0;

            for(int j=i+1;j<list.size();j++)
            {//System.out.println(i+"  "+j);
                if(target>(Integer)list.get(j))
                {
                    pos=j;
                    target=(Integer)list.get(j);
                }
            }
            if(pos!=0)
            {
                Integer temp=(Integer)list.get(i);
                list.set(i, (Integer)list.get(pos));
                list.set(pos, temp);


            }



        }
    }

    void bubbleSort(List<Integer> list)
    {

        for(int i=list.size()-1;i>0;i--)
        {
            int status=0;
            for(int j=0;j<=i-1;j++)
            {
                //System.out.println(i+"  "+j);
                if((Integer)list.get(j)>(Integer)list.get(j+1))
                {
                    int temp=(Integer)list.get(j+1);
                    list.set(j+1, (Integer)list.get(j));
                    list.set(j, temp);
                    status++;
                }
            }
            //if(status==0)break;
        }
    }
}

这个程序为冒泡排序提供了 85% 的更多时间,有时它是插入排序的两倍。

adding item logic started : Fri Jun 26 02:47:13 PDT 2015
adding item logic ended : Fri Jun 26 02:47:13 PDT 2015
Fri Jun 26 02:47:13 PDT 2015
Fri Jun 26 02:47:58 PDT 2015
selection sort time taken in seconds : 44
Fri Jun 26 02:47:58 PDT 2015
Fri Jun 26 02:48:46 PDT 2015
bubble sort time taken in seconds : 56

【问题讨论】:

  • 请查看此链接,其中提供了有关为什么冒泡排序比选择排序花费更长时间的详细信息cs.stackexchange.com/questions/13106/…
  • @Mudassar 我浏览了这个链接,但我仍然很困惑。我在这里描述的情况是最好的情况,不需要时间交换。仍然需要更多时间。在这种情况下,选择排序除了一些赋值函数外还有两个循环,因为冒泡排序只是通过循环,理想情况下应该花费更少的时间。
  • 链接中的答案还指出“......时间复杂度取决于实现和运行机器......”(可能还有更多因素。
  • @ceekay 我在同一台机器和同一程序中执行这两种算法。但是,如果在实施中存在一些问题,那么这就是我想知道的。但我找不到任何错误。
  • 如前所述,冒泡排序平均每个条目需要 n/4 次交换(每个条目按元素从其初始位置移动到其最终位置,每次交换涉及两个条目),而选择sort 只需要 1(一旦找到最小值/最大值,它就会被交换一次到数组的末尾)。

标签: java algorithm bubble-sort selection-sort


【解决方案1】:

你说:

“但是让我们说,即使我没有使用任何 break 语句,也不会有任何交换(就像我们有 if 条件一样),它应该花费与选择排序相同或更少的时间。”

在您的代码中,您注释掉外循环中的 break 语句:

//if(status==0)break;

如果没有 break 语句,算法/代码是 O(n^2),并且您不会从排序中获得任何好处。

【讨论】:

    【解决方案2】:

    嗯,正如我在您的代码中看到的,两种算法的迭代次数是相同的

    for(int i=0;i<list.size();i++)
        for(int j=i+1;j<list.size();j++)
    

    将与

    相同
    for(int i=list.size()-1;i>0;i--)
        for(int j=0;j<=i-1;j++)
    

    所以差异应该取决于每次迭代中发生的事情(我将只取循环的内部部分,其他部分我们将省略)。

    冒泡排序:

    if((Integer)list.get(j)>(Integer)list.get(j+1))
    {
        int temp=(Integer)list.get(j+1);
        list.set(j+1, (Integer)list.get(j));
        list.set(j, temp);
        status++;
    }
    

    由于列表已排序,您不会进入 if,因此您有两个 list.get(something)。

    在选择排序中:

    if(target>(Integer)list.get(j))
    {
        pos=j;
        target=(Integer)list.get(j);
    }
    

    但你不会进入 if,所以你只会得到一个 list.get(something)。

    简而言之,使用选择排序,您在每次迭代中执行的操作更少,这可能是让您的程序运行得更快的原因。

    【讨论】:

    • 顺便说一句,这与@Jan 所说的相同:复杂性与运行时间不同
    【解决方案3】:

    这里举一个简单的例子,有两种情况 在冒泡排序中

    First Pass:
    ( 5 1 4 2 8 ) \to ( 1 5 4 2 8 ), Here, algorithm compares the first two elements, and swaps since 5 > 1.
    ( 1 5 4 2 8 ) \to ( 1 4 5 2 8 ), Swap since 5 > 4
    ( 1 4 5 2 8 ) \to ( 1 4 2 5 8 ), Swap since 5 > 2
    ( 1 4 2 5 8 ) \to ( 1 4 2 5 8 ), Now, since these elements are already in order (8 > 5), algorithm does not swap them.
    Second Pass:
    ( 1 4 2 5 8 ) \to ( 1 4 2 5 8 )
    ( 1 4 2 5 8 ) \to ( 1 2 4 5 8 ), Swap since 4 > 2
    ( 1 2 4 5 8 ) \to ( 1 2 4 5 8 )
    ( 1 2 4 5 8 ) \to ( 1 2 4 5 8 )
    Now, the array is already sorted, but the algorithm does not know if it is completed. The algorithm needs one whole pass without any swap to know it is sorted.
    Third Pass:
    ( 1 2 4 5 8 ) \to ( 1 2 4 5 8 )
    ( 1 2 4 5 8 ) \to ( 1 2 4 5 8 )
    ( 1 2 4 5 8 ) \to ( 1 2 4 5 8 )
    ( 1 2 4 5 8 ) \to ( 1 2 4 5 8 )
    

    在选择排序中的位置

    64 25 12 22 11 // this is the initial, starting state of the array
    
    11 25 12 22 64 // sorted sublist = {11}
    
    11 12 25 22 64 // sorted sublist = {11, 12}
    
    11 12 22 25 64 // sorted sublist = {11, 12, 22}
    
    11 12 22 25 64 // sorted sublist = {11, 12, 22, 25}
    
    11 12 22 25 64 // sorted sublist = {11, 12, 22, 25, 64}
    

    在冒泡排序中可以看到三遍,而在选择排序中只有一次通过

    【讨论】:

    • 请检查我已经为两种算法提供排序数据集的条件,这不会导致两种算法的任何交换。
    • 即使交换没有发生,但这并不意味着它不会进行必要的比较来识别交换
    【解决方案4】:

    您混淆了复杂性运行时间

    例如,如果您有一种算法,总是需要一小时,那么该算法的复杂度为 O(1)。第二个算法需要 1 分钟处理 1 个元素,2 分钟处理 2 个元素,3 分钟处理 3 个元素,......这个算法的复杂度为 O(n)。在复杂性方面,第一种算法更好,但对于 1 到 59 个元素,第二种算法更快。

    【讨论】:

    • 我理解你提到的概念。但是如果你说选择排序在复杂性上更好,而第二种算法在运行时间上更好,你就完全错了。请您再次阅读该问题。我采用了相同排序的 1 到 90000 个整数数据集。并在同一数据集上测试这两种算法。冒泡排序需要更多时间。而且我相信我们也可以用大大的 oh 表达式来表达运行时间,
    • 复杂性是关于算法的渐近行为,并且具有相同渐近行为的类使用大的哦表达式进行标记。运行时间以秒为单位,取决于很多因素(例如输入、cpu 等)。在您的场景中,为什么您认为冒泡排序应该比选择排序更快(即花费更少的秒数)?
    猜你喜欢
    • 2019-02-26
    • 2021-11-24
    • 2017-05-01
    • 2015-09-12
    • 2017-03-18
    • 2018-03-28
    • 2021-05-13
    • 2020-07-30
    • 2015-02-14
    相关资源
    最近更新 更多