数据结构和算法

排序算法中——归并排序和快速排序

2018-10-18  本文已影响74人  seniusen

冒泡排序、插入排序、选择排序这三种算法的时间复杂度都为 O(n^2),只适合小规模的数据。今天,我们来认识两种时间复杂度为 O(nlogn) 的排序算法——归并排序(Merge Sort)和快速排序(Quick Sort),他们都用到了分治思想,非常巧妙。

1. 归并排序(Merge Sort)?

1.1. 归并排序算法实现

归并排序
递推公式:
merge_sort(p…r) = merge(merge_sort(p…q), merge_sort(q+1…r))

终止条件:
p >= r 不用再继续分解
数组合并
// O(n(logn))
void Merge_Sort(float data[], int left, int right, float sorted_data[])
{
    if(left < right)
    {
        int mid = (left + right) / 2;
        Merge_Sort(data, left, mid, sorted_data);
        Merge_Sort(data, mid+1, right, sorted_data);
        Merge_Array(data, left, mid, right, sorted_data);
    }
}

void Merge_Array(float data[], int left, int mid, int right, float temp[])
{
    int i = left, j = mid + 1;
    int k = 0;

    // 从子数组的头开始比较
    while(i <= mid && j <= right)
    {
        if (data[i] <= data[j])
        {
            temp[k++] = data[i++];
        }
        else
        {
            temp[k++] = data[j++];
        }
    }

    // 判断哪个子数组还有元素,并拷贝到 temp 后面
    while(i <= mid)
    {
        temp[k++] = data[i++];
    }
    while(j <= right)
    {
        temp[k++] = data[j++];
    }

    // 将 temp 中的数据拷贝到原数组对应位置
    for(i = 0; i < k; i++)
    {
        data[left+i] = temp[i];
    }
}

1.2. 归并排序算法分析

T(1) = C
T(n) = 2*T(\frac{n}{2}) + n, n>1

T(n) = 2*T(\frac{n}{2}) + n
= 2*[2*T(\frac{n}{4}) + \frac{n}{2}] + n = 4*T(\frac{n}{4}) + 2*n
= 4*[2*T(\frac{n}{8}) + \frac{n}{4}] + 2*n = 8*T(\frac{n}{8}) + 3*n
......
= 2^k * T(\frac{n}{2^k}) + k * n
......
\frac{n}{2^k} = 1时, k = log_2n,代入上式得:
T(n) = n * C + nlog_2n
用大 O 标记法来表示,归并排序的时间复杂度为 O(nlogn)


2. 快速排序(Quick Sort)?

1.1. 快速排序算法实现

递推公式:
quick_sort(p…r) = quick_sort(p…q-1) + quick_sort(q+1, r)

终止条件:
p >= r
归并排序和快速排序
// O(n(logn))
void Quick_Sort(float data[], int left, int right)
{
    if (left < right)
    {
        int i = left, j = left;
        int pivot = data[right];

        for (j = left; j < right; j++)
        {
            if (data[j] < pivot)
            {
                int temp = data[i];
                data[i] = data[j];
                data[j] = temp;
                i++;
            }
        }

        data[j] = data[i];
        data[i] = pivot;
        Quick_Sort(data, left, i-1);
        Quick_Sort(data, i+1, right);
    }
}
快速排序
// O(n(logn))
void Quick_Sort(float data[], int left, int right)
{
    if (left < right)
    {
        int i = left, j = right;
        int pivot = data[i];
        while(i < j)
        {
            while(i < j && data[i] <= pivot) // 从左往右找到第一个比 pivot 大的数
            {
                i++;
            }
            if(i < j)
            {
                data[j--] = data[i];
            }
            while(i < j && data[j] >= pivot) // 从右往左找到第一个比 pivot 小的数
            {
                j--;
            }
            if(i < j)
            {
                data[i++] = data[j];
            }
        }
        data[i] = pivot; // i=j
        Quick_Sort(data, left, i-1);
        Quick_Sort(data, i+1, right);
    }
}

2.2. 快速排序算法分析


3. 小结


参考资料-极客时间专栏《数据结构与算法之美》

获取更多精彩,请关注「seniusen」!


seniusen
上一篇下一篇

猜你喜欢

热点阅读