【慢速学数据结构】排序

前言

刚开始学的时候,一般都是几大排序一起看,看着看着就晕了,觉得很难。其实没学会的原因只有一个,那就是自己打击了自己的积极性。

如果你心里对它们还存有畏难情绪的话,不妨先看看这些视频,匈牙利民间舞模拟各种排序,很滑稽;) 地址

快速排序

快速排序

这代码够简洁了吧!

void quickSort(std::vector<int> &a, int left, int right)
{
    if(left < right)
    {
        // 选择左节点为枢纽元
        int pivot = a[left];
        int low = left, high = right;

        // 把数组分成两半,左边的小于pivot,右边的大于pivot
        while(low < high)
        {
            while(high > low && a[high] > pivot)
            {
                high--;
            }
            if(low < high)// 1
                a[low] = a[high];

            while(low < high && a[low] < pivot)
            {
                low++;
            }
            if(low < high)// 2
                a[high] = a[low];

            // 因为你不知道会在哪个while之后结束,所以1,2两处都要加一个判断。
        }

        // 此时pivot的位置就是正确的了。
        a[low] = pivot;

        quickSort(a, left, low-1);
        quickSort(a, low+1, right);
    }
}

归并排序

一句话记忆:”分治与合并“

void merge(std::vector<int> &a, int l, int m, int r)
{
    // 用一个辅助数组
    std::vector<int> tmp;
    int i = l, j = m+1;


    // 按序插入到辅助数组中
    while(i<=m && j<=r)
    {
        if(a[i] <= a[j])
            tmp.push_back(a[i++]);
        else
            tmp.push_back(a[j++]);
    }


    // 拷贝剩下的数据
    while(i<=m)
        tmp.push_back(a[i++]);
    while(j<=r)
        tmp.push_back(a[j++]);


    // 全部复制到原来的数组
    for(int i = 0; i<tmp.size(); i++)
        a[l+i] = tmp[i];

}

void mergeSort(std::vector<int> &a, int l, int r)
{
    if(l<r)
    {
        int m = l + (r-l)/2;


        mergeSort(a, l, m);
        mergeSort(a, m+1, r);
        merge(a, l, m, r);
    }

}

插入排序

一句话记忆:”不断将新节点插入到一个已经排好序的数组中。“

void insertSort(std::vector<int> &a)
{
    for(int i = 1; i<a.size(); i++)
        for(int j = i-1; j>=0 && a[j+1]<a[j]; j--)
            std::swap(a[j+1],a[j]);
}

希尔排序

一句话记忆:”插入排序的兄弟。“

void shellSort(std::vector<int> &a)
{
    int n = a.size();

    // 步长每次减半
    for(int gap = n/2; gap>0; gap/=2)
        // 对应插入排序中 for(int i=1;i<n;i++),gap=1
        for(int i = gap; i < n; i++)
            // 对应插入排序中 for(int j=i-1;j>=0;j--)
            for(int j = i-gap; j>=0 && a[j+gap]<a[j]; j-=gap)
                std::swap(a[j+gap], a[j]);
}

堆排序

一句话理解:”把要排序的数组当作一个最大堆,并想办法使其恢复堆序,最后通过将堆顶元素换到末尾实现排序。“

void maxHeapfix(std::vector<int> &a, int heapSize, int index)
{
    int iMax = index;
    int iLeft = 2*index + 1;// 这里的数组下标从0开始,所以我们要调整一下
    int iRight = 2*index + 2;


    if(iLeft < heapSize && a[iLeft]>a[iMax])
        iMax = iLeft;
    if(iRight < heapSize && a[iRight]>a[iMax])
        iMax = iRight;


    if(iMax != index)
    {
        std::swap(a[iMax], a[index]);
        maxHeapfix(a, heapSize, iMax);
    }
}

void heapSort(std::vector<int> &a)
{
    int n = a.size();

    // 构建最大堆,数组小于3就会直接跳过这里
    for(int i = n/2-1; i>=0; i--)
    {
        maxHeapfix(a, n, i);
    }


    // 排序
    for(int i = n-1; i>0; i--)
    {
        std::swap(a[0], a[i]);
        maxHeapfix(a, i, 0);
    }
}

冒泡排序

一句话记忆:”请认真对待每一件事,哪怕它只是个冒泡排序“

void bubbleSort(std::vector<int> &a)
{
    for(int i = 0; i<a.size(); i++)
        for(int j = 1; j<a.size()-i; j++)
            if(a[j] > a[j-1])    
                std::swap(a[j], a[j-1]);
}

它们的复杂度

complexity

稳定性

选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法

参考文章

http://quiz.geeksforgeeks.org/
里面的代码、注释都很精炼很优雅,读起来简直是享受。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值