zoukankan      html  css  js  c++  java
  • 冒泡排序

    冒泡排序

    算法简介

      冒泡排序(BubbleSort)算法:比较相邻元素的大小,如果第一个元素大于第二个元素,则交换它们的位置,然后第二个元素与第三个元素比较,直到所有的元素比较完,冒泡出最小的元素。假设我们有n各元素,那么我们就要进行 n-1 次冒泡,n-1 个最小的元素已经冒泡出来,因此,最后剩下的一个元素也就处于它应当处于的位置。

      本篇文章主要是对冒泡排序进行优化,使其避免不必要的比较,以及泛型的实现,共分四个版本。

    先来看一张直观的图:

    第一版

      

    static int FirstVersionBubbleSort(int[] array)
    {
        int count = array.Length - 1;
        int number = 0;
        for (int i = 0; i < count; i++)
        {
            for (int j = 0; j < count - i; j++)
            {
                if (array[j] > array[j + 1])
                {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
                number++;
            }
        }
        return number;
    }

    外层循环用来控制冒泡的次数,内层循环用来比较相邻元素的大小。number 用来记录总共进行了几次比较,为后面的优化版本做对比。

    执行 Main():

    int[] firstArray = { 2, 1, 3, 4 };
    
    Console.WriteLine("总共比较的次数:{0}", FirstVersionBubbleSort(firstArray));
    foreach (var item in firstArray)
    {
        Console.Write(item.ToString().PadRight(2));
    }
    总共比较的次数:6
    1 2 3 4

    总共比较了6次,分别是:

    第一次冒泡出 4:

    2-1:1 2 3 4

    2-3:1 2 3 4

    3-4 : 1 2 3 4

    第二次冒泡 3:

    1-2 : 1 2 3 4

    2-3 : 1 2 3 4

    第三次冒泡 2:

    1-2 : 1 2 3 4

    看一下上面的过程,就很容想到,当整个数列已经排好序后我们就没有必要再做多余的比较。用一个标志量来表示上次是否内层循环是否有元素交换,如果有则进行下一次循环,否则退出,因为所有元素已经有序。

    第二版

      

    static int SecondVersionBubbleSort(int[] array)
    {
        int count = array.Length;
        bool change;
        int number = 0;
        do
        {
            count--;
            change = false;
            for(int i = 0; i < count; i++)
            {
                if(array[i] > array[i + 1])
                {
                    int temp = array[i];
                    array[i] = array[i + 1];
                    array[i + 1] = temp;
                    change = true;
                }
                number++;
            }
        }while(change);
        return number;
    }

    执行Main():

    int[] secondArray= { 2, 1, 3, 4 };
    
    Console.WriteLine("
    总共比较的次数:{0}", SecondVersionBubbleSort(secondArray));
    foreach (var item in secondArray)
    {
        Console.Write(item.ToString().PadRight(2));
    }
    总共比较的次数:5
    1 2 3 4

    总共比较了5次,分别是:

    第一次冒泡出 4:

    2-1:1 2 3 4

    2-3:1 2 3 4

    3-4 : 1 2 3 4

    此时 change 为 true

    第二次冒泡 3:

    1-2 : 1 2 3 4

    2-3 : 1 2 3 4

    发现已经有序,change 为 false, 结束冒泡。再继续思考,事实上,第一次冒泡后,2、3、4 已经有序,因此下次循环完全没有必要再继续对其比较;现在我们增加一个位置变量来记录每次冒泡的最后交换的位置,下次比较的此处就可以了,避免对后面已经有序的元素重复进行比较。

    static int ThirdVersionBubbleSort(int[] array)
    {
        int count = array.Length - 1, index = 0;
        bool change;
        int number = 0;
    
        do
        {
            change = false;
            for (int i = 0; i < count; i++)
            {
                if (array[i] > array[i + 1])
                {
                    int temp = array[i];
                    array[i] = array[i + 1];
                    array[i + 1] = temp;
                    change = true;
                    index = i;  // 记录最后一次交换的位置
                }
                number++;
            }
            count = index;
        } while (change);
        return number;
    }

    执行 Main():

    int[] thirdArray = { 2, 1, 3, 4 };
    
    Console.WriteLine("
    总共比较的次数:{0}", ThirdVersionBubbleSort(thirdArray));
    foreach (var item in thirdArray)
    {
        Console.Write(item.ToString().PadRight(2));
    }
    总共比较的次数:3
    1 2 3 4

    有上面的结果,可以看到,这次只进行了 3 次比较,分别如下:

    总共比较了3次,分别是:

    第一次冒泡出 4:

    2-1:1 2 3 4

    2-3:1 2 3 4

    3-4 : 1 2 3 4

    此时 index 为 0, count 为 0,结束冒泡。可见,这种方式,可以大大降低比较的次数。

    第四版

    如果说继承是为我们提供了代码重用,那么泛型则为我们提供了算法的重用。下面我们将实现一个泛型版本的冒泡排序。

    public static int FourthVersionBubbleSort<T>(List<T> list) where T:IComparable<T>
    {
        int count = list.Count - 1, index = 0;
        bool change;
        int number = 0;
    
        do
        {
            change = false;
            for (int i = 0; i < count; i++)
            {
                if (list[i].CompareTo(list[i + 1]) > 0)
                {
                    T temp = list[i];
                    list[i] = list[i + 1];
                    list[i + 1] = temp;
                    change = true;
                    index = i;  // 记录最后一次交换的位置
                }
                number++;
            }
            count = index;
        } while (change);
        return number;
    }

    执行 Main():

    List<string> stringList = new List<string> { "Banana", "Apple", "Orange" };
    Console.WriteLine("总共比较的次数:{0}", FourthVersionBubbleSort(stringList));
    foreach (var item in stringList)
    {
        Console.Write(item.ToString().PadRight(10));
    }
    总共比较的次数:2
    Apple     Banana    Orange

     结束语

      冒泡排序最优时间复杂度为(即所有元素有序,只需遍历一次即可) O(n),最差时间复杂度为 O(n^2), 即当所有元素为逆序时。 

  • 相关阅读:
    关于在MAC上进行 LARAVEL 环境 Homestead 安装过程记录
    js 贷款计算器
    js 实现阶乘
    js 两点间距离函数
    composer Your requirements could not be resolved to an installable set of packages
    vue 项目优化记录 持续更新...
    vue 项目打包
    vue 真机调试页面出现空白
    vue 真机调试
    谈谈-Android状态栏的编辑
  • 原文地址:https://www.cnblogs.com/kanlei/p/3442384.html
Copyright © 2011-2022 走看看