• 【左程云算法全讲3】归并排序与随机快排


    系列综述:
    💞目的:本系列是个人整理为了秋招面试的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
    🥰来源:材料主要源于左程云算法课程进行的,每个知识点的修正和深入主要参考各平台大佬的文章,其中也可能含有少量的个人实验自证。
    🤭结语:如果有帮到你的地方,就点个赞关注一下呗,谢谢🎈🎄🌷!!!
    🌈【C++】秋招&实习面经汇总篇



    😊点此到文末惊喜↩︎

    归并排序

    1. 是否可递归:大问题能否通过范围缩小但是同等定义的子问题搞定
    2. 归并排序
    // 将两个数组从小到大合并成为一个
    void Merge(vector<int> &vec, int L, int mid, int R) {
        const int n = R-L+1;
        vector<int> tmp(n, 0);  // 注意长度
    
        int i = 0;      // 工作指针
        int p1 = L;     // 左半部分的工作指针
        int p2 = mid+1; // 右半部分的工作指针
        // 两者较小的赋值给tmp数组
        while (p1 <= mid && p2 <= R) {
            tmp[i++] = (vec[p1] <= vec[p2] ? vec[p1++] : vec[p2++]); 
        }
        // 收尾
        while (p1 <= mid) {
            tmp[i++] = vec[p1++];
        }
        while (p2 <= R) {
            tmp[i++] = vec[p2++];
        }
        // 赋值
        for (int i = 0; i < n; ++i) {
            vec[L+i] = tmp[i];  // key:注意递归中赋值的起始位置
        }
    
    }
    // 递归形式
    void Process(vector<int> &vec, int L, int R) {
        // 递归出口
        if (L == R) return ;
        // 划分
        int mid = L + ((R-L)>>1);
        Process(vec, L, mid);
        Process(vec, mid+1, R);
        // 合并
        Merge(vec, L, mid, R);
    }
    // 非递归形式
    void Process(vector<int> &vec) {
        if (vec.size() < 2) return ;
        const int n = vec.size();
        int merge_size = 1;		// 每次合并单位
        while (merge_size < N) {
    		int L = 0; 		// 每次从0开始
    		while (L < N) {	// 合并相邻merge_size的区间
    			int mid = L+merge_size-1;
    			if (mid >= N) break;	// 避免右边界溢出
    			int R = min(mid+merge_size(), N-1);
    			merge(vec, L, mid, R);
    			L = R+1;
    		}
    		if (merge_size > N / 2) break;	// 避免溢出,提前停止
    		merge_size <<= 1;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    1. 求数组小和,表示第i个数左侧小于等于该数的个数,然后整个数组的每个数的小和相加
      • 逆反:相当于求第i个数右侧比i值大的个数
      • 归并排序可以解决两个范围比较的问题
    // 将两个数组从小到大合并成为一个
    int Merge(vector<int> &vec, int L, int mid, int R) {
        const int n = R-L+1;
        vector<int> tmp(n, 0);  // 注意长度
    
        int i = 0;      // 工作指针
        int p1 = L;     // 左半部分的工作指针
        int p2 = mid+1; // 右半部分的工作指针
        // 两者较小的赋值给tmp数组
        int res = 0;
        while (p1 <= mid && p2 <= R) {
        	// 在右组中找到比左组大的数,右组是有序的,所以可以直接通过下标计算出右组更大的有几个
            res += vec[p1] < vec[p2] ? (R-p2+1)*vec[p1] : 0;
            tmp[i++] = (vec[p1] < vec[p2] ? vec[p1++] : vec[p2++]); 
        }
        // 收尾
        while (p1 <= mid) {
            tmp[i++] = vec[p1++];
        }
        while (p2 <= R) {
            tmp[i++] = vec[p2++];
        }
        // 赋值
        for (int i = 0; i < n; ++i) {
            vec[L+i] = tmp[i];  // key:注意递归中赋值的起始位置
        }
        return res;
    
    }
    
    int Process(vector<int> &vec, int L, int R) {
        // 递归出口
        if (L == R) return 0;
        // 划分
        int mid = L + ((R-L)>>1);
        return Process(vec, L, mid) 
            + Process(vec, mid+1, R);
            + Merge(vec, L, mid, R);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    快速排序

    1. partition过程:进行划分但不严格要求两部分内部有序,将小于等于num的数放在左边,将大于等于num的数放在右边
    2. 代码
    // 划分
    int parititon(vector<int> &vec, int left, int right) {
    	// 随机化处理:避免完全有序的情况
        int idx = left + rand() % (right - left + 1);
        swap(vec[left], vec[idx]);
        // 算法部分
        int pos = left;
        int pivot = vec[left];
        while (left < right) {
            while (vec[right] >= pivot && left < right) right--;
            while (vec[left] <= pivot && left < right) left++;
            swap(vec[left], vec[right]);
        }
        swap(vec[left], vec[pos]);
        return left;
    }
    
    void QuickSort(vector<int> &vec, int left, int right) {
        if (left > right) return ;
        int mid = parititon(vec, left, right);
        QuickSort(vec, left, mid-1);
        QuickSort(vec, mid+1, right);
    
    }
    // main中需要 srand((int)time(NULL));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25


    少年,我观你骨骼清奇,颖悟绝伦,必成人中龙凤。
    不如点赞·收藏·关注一波

    🚩点此跳转到首行↩︎

    参考博客

    1. 对数器
    2. 单调队列
    3. 快速链表quicklist
    4. 《深入理解计算机系统》
    5. 侯捷C++全系列视频
    6. 待定引用
    7. 待定引用
    8. 待定引用
  • 相关阅读:
    代码随想录算法训练营第四十八天| LeetCode198. 打家劫舍、LeetCode213. 打家劫舍 II、LeetCode337. 打家劫舍 III
    C# 解决从其他地方迁移项目,引用中大多数包是感叹号的问题
    react native 使用夜神模拟器开发调试 windows+android
    java实现 图片转ico
    Java之线程详解(一)——线程概念知识、创建线程的几种方式
    BIM+GIS工程管理系统——BIM与GIS的跨界合作
    现代 CSS 解决方案:CSS 数学函数
    【代码执行以及调试】
    Bash编程语法
    Vue/Vuex入门、Vuex安装 和 Vuex创建导入仓库、Vuex (state )方法、state 辅助函数mapState 方法说明
  • 原文地址:https://blog.csdn.net/qq_43840665/article/details/134255545