数据结构——(3)排序

目录

一、插入排序

1.1  简单插入排序

1.2  希尔排序

二、比较排序

2.1  堆排序(这里介绍最大堆排序)

2.2  冒泡排序

三、递归排序

3.1  归并排序

3.2  快速排序(留坑)

四、基数排序

4.1  桶排序(留坑)

4.2  基数排序(卡片排序)(留坑)


一、插入排序

1.1  简单插入排序

  • 插入排序核心思想:将待排序的一组序列分成两组:已排序的组和未排序的组。初始时,选取第一个元素加入已排序的组,其余元素全部放在未排列的组。进行排序时,从未排序的组中取出一个元素,按顺序插入待已排序的组中。循环该过程,直至所有元素均被排序。
  • 代码:
//小值在前
void InsertSort(vector<int>& v){
    if(v.size() <= 1)return;
    int lastIndex;
    //这个循环是遍历序列的每个元素
    for(int i = 1; i < v.size(); i++){
        int tmp = v[i];
        //这个循环是将第i个未排序元素tmp往前对比,直至全部对比完或碰到比这个元素tmp小的
        for(lastIndex = i; lastIndex > 0 && v[lastIndex - 1] > tmp; lastIndex--){
            v[lastIndex] = v[lastIndex-1];
        }
        v[lastIndex] = tmp;
    }
}
  • 复杂度分析:时间复杂度:两层for,最坏情况能到O(n^2), 最好情况就是已经排好序,不用进入第二个for,相当于遍历数组,复杂度为O(n)。空间复杂度:...貌似没怎么额外申请空间,就一两个变量而已,空间复杂度O(1)

1.2  希尔排序

  • 核心思想:插入排序低效的原因是每次比较只能交换相邻两个元素的位置,希尔排序是多做几次插入排序,但每次插入排序的元素是隔着一定距离的,最后一次的插入排序才是间隔为1的正常插入排序。这样虽然多做了几次排序,但经过前面几次的排序后,序列已经大致有序,最后一次插入排序时的,每次插入需要移动元素的个数会大幅度降低。

代码:

  • //小值在前
    void ShellSort(vector<int>& v){
        if(v.size() <= 1)return;
        vector<int>increase_array = {1000, 100, 10, 5, 1};
    
        //获取适合大小的初始增量大小,不能超出数组长度
        int increase_index;
        for(increase_index = 0; increase_array[increase_index] > v.size(); increase_index++);
    
        int lastIndex;
        for(int d = increase_array[increase_index]; increase_index < increase_array.size(); d = increase_array[++increase_index]){
            //这个循环是遍历序列的每个元素
            for(int i = d; i < v.size(); i++){
                int tmp = v[i];
                //这个循环是将第i个未排序元素tmp往前对比,直至全部对比完或碰到比这个元素tmp小的
                for(lastIndex = i; lastIndex > d - 1 && v[lastIndex - d] > tmp; lastIndex--){
                    v[lastIndex] = v[lastIndex-d];
                }
                v[lastIndex] = tmp;
            }
        }
    }
  • 复杂度分析:玄学算法,时间复杂度据说还没定论,空间复杂度为O(1)

二、比较排序

2.1  堆排序(这里介绍最大堆排序)

  • 核心思想:最大堆的根节点一定是整个堆的最大值,利用这一特点,如下处理:(1)将堆的根节点与堆数组的最后一个节点交换;(2)重新对堆进行维护,在维护过程中,将已经被移动的原来堆的根节点视为已不属于这个堆,即维护一个少了一个节点的堆,此时,堆顶节点为次大元素;(3)将当前堆顶节点与倒数第二个节点交换位置。重复上述操作至当前堆只剩一个节点为止。
  • 代码:
void MaxHeapSort(vector<int>& v){
    if(v.empty())return;
    for(int n = 0; n < v.end() - v.begin() - 1; n++){
        make_heap (v.begin(), v.end() - n);
        pop_heap(v.begin(), v.end() - n);//标准库函数,直接帮我们把堆的根节点放到数组的最后一个元素,且剩余节点重排
    }
}
  • 时间复杂度:时间复杂度O(nlogn)、时间复杂度O(1)

2.2  冒泡排序

  • 当年学C的时候写过...不想写了,偷个懒~

三、递归排序

3.1  归并排序

  • 核心思想:假设目标序列由两个已排序的子序列组成,则这两个子序列边排序边合并,就可以对整个序列进行排序了;利用递归思想,可以知道当子序列中只有一个元素时的排序是最简单的,因此整个归并是用递归来实现的。注意,在进行合并的时候,要利用一个辅助数组来暂存合并结果。
  • 代码:
    ///合并两个序列
    void combine(vector<int>& A, vector<int>& tmp, int left, int right, int right_end){
        int left_end = right - 1;
    
        int i = left, j = right;
    
        int index = left;
        //先将一部分合并
        for(;i <= left_end && j <= right_end;){
                if(A[i] < A[j])tmp[index++] = A[i++];
                else tmp[index++] = A[j++];
        }
        //将剩下的部分也放进去
        while(i <= left_end){
            tmp[index++] = A[i++];
        }
        while(j <= right_end){
            tmp[index++] = A[j++];
        }
        //将临时序列中的序列传给原序列
        for(index = left; index <= right_end; index++){
            A[index] = tmp[index];
        }
    }
    
    ///递归程序
    void merge_sort(vector<int>& A, vector<int>& tmp, int left, int right_end){
        if(left < right_end){
           int center = (right_end + left) / 2;
           merge_sort(A, tmp, left, center);
           merge_sort(A, tmp, center + 1, right_end);
           combine(A, tmp, left, center+1, right_end);  //这几个left、right、right_end一定要想清楚传什么,不然程序会出错
        }
    }
    
    ///驱动程序
    void merge_sort(vector<int>& v){
        auto tmp = v;
        tmp.assign(tmp.size(), 0);
        merge_sort(v, tmp, 0, v.size() - 1);
    }

     

3.2  快速排序(留坑)

四、基数排序

4.1  桶排序(留坑)

4.2  基数排序(卡片排序)(留坑)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值