Algorithms

印象

图2 快速排序过程

思想

通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

分析

  • 稳定: 否
  • 时间复杂度:
    • 最优时间: O(nlog(n))
    • 最坏时间: O(n^2)
    • 平均时间: O(nlog(n))

理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(nlog2n)。
最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n2)。
为改善最坏情况下的时间性能,可采用其他方法选取中间数。通常采用“三者值取中”方法,即比较H->r[low].key、H->r[high].key与H->r[(10w+high)/2].key,取三者中关键字为中值的元素为中间数。

示例代码

C#

static void Main(string[] args)
{
    // 定义待排序数组
    int[] a = { 12, 312, 32, 82, 21 };

    // 显示待排序数组
    Console.WriteLine("待排序数组:");
    foreach (var item in a)
    {
        Console.Write(item);
        Console.Write(" ");
    }
    Console.WriteLine("");

    // 排序
    QSort(a);

    // 显示已排序数组
    Console.WriteLine("已排序数组:");
    foreach (var item in a)
    {
        Console.Write(item);
        Console.Write(" ");
    }

    // 等待
    Console.ReadKey();
}

/// <summary>
/// 快速排序
/// </summary>
/// <param name="a"></param>
static void  QSort(int[] a)
{
    QSort(a, 0, a.Length - 1);
}

/// <summary>
/// 快速排序
/// </summary>
/// <param name="a">排序数组</param>
/// <param name="left">数组左侧索引</param>
/// <param name="right">数组右侧索引</param>
static void QSort(int[] a, int left, int right)
{
    if (left < right)
    {
        int i = left - 1;
        int j = right + 1;
        int key = a[(left + right) / 2];
        while (true)
        {
            // 寻找满足交换条件的两个索引
            while (a[++i] < key) ;
            while (a[--j] > key) ;

            // 结束
            if (i >= j)
            {
                break;
            }

            // 交换
            int temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }

        // 递归
        QSort(a, left, i - 1);
        QSort(a, j + 1, right);
    }
}

参考

Wikipedia - Quicksort

原文地址:https://www.cnblogs.com/zdfffg/p/10432039.html