算法导论-分治法和合并(Merge)排序

算法合集

https://github.com/SYRollingStone/SiYangUnityAlgorithmsSamples

一、分治法

分:大问题分解物小问题。

治:递归解决小问题。

并:将小问题的结果合并成为结果。

二、合并排序

4, 8, 1, 6, 0, 5, 3, 9

4, 8, 1, 6, 0, 5, 3, 9

↓ 切一刀

4, 8, 1, 6\] \[0, 5, 3, 9

↓ ↓

4, 8\] \[1, 6\] \[0, 5\] \[3, 9

↓ ↓ ↓ ↓

4\] \[8\] \[1\] \[6\] \[0\] \[5\] \[3\] \[9

治+合:

合并第 1 层:把两个"长度1的有序段"合成"长度2的有序段"

merge([4], [8]) => [4, 8]

merge([1], [6]) => [1, 6]

merge([0], [5]) => [0, 5]

merge([3], [9]) => [3, 9]

合并第 2 层:把两个"长度2的有序段"合成"长度4的有序段"

复制代码
merge([4,8], [1,6]) => [1,4,6,8] 
merge([0,5], [3,9]) => [0,3,5,9] 

合并第 3 层:合成最终结果

merge([1,4,6,8], [0,3,5,9]) => [0,1,3,4,5,6,8,9]

merge中的双指针排序

以这一步为例:

merge([4,8], [1,6])

用两个指针 i、j 分别指向左右数组的"当前最小元素":

Left : [4, 8]

i^

Right: [1, 6]

j^

结果 result: []

先4和1比较,1更小,1放入result,j指针移动到6

Left : [4, 8]

i^

Right: [1, 6]

j^

结果 result: [1]

4和6比较,4放入result,i指针移动到8

Left : [4, 8]

i^

Right: [1, 6]

j^

结果 result: [1,4]

6和8比较,6放入result

Left : [4, 8]

i^

Right: [1, 6]

j^

结果 result: [1,4,6]

将最后一个8放入result

结果 result: [1,4,6,8]

三、代码

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 分治法
// 合并排序
public class MergeSort : MonoBehaviour
{
    private int[] _data = {2,1,5,3,4,7,8,9,0,15,67,45 ,100,134,121,111,11};
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("Before: " + string.Join(", ", _data));
        int[] temp = new int[_data.Length];
        Sort(_data, temp, 0, temp.Length - 1);
        Debug.Log("After: " + string.Join(", ", _data));
    }

    private void Sort(int[] array,int[] temp,int left,int right)
    {
        // 分,每次分一半,直到不可以再分 即 数组长度为1
        if (left >= right) return;
        
        int mid = left + (right - left) / 2;
        Sort(array,temp,left,mid);
        Sort(array,temp,mid+1,right);

        Merge(array, temp, left, mid, right);
    }

    private void Merge(int [] array,int [] temp,int left,int mid, int right)
    {
        for (int i = left; i <= right; i++)
        {
            temp[i] = array[i];
        }

        int iLeft = left;   // 左边数组的下指针
        int iRight = mid + 1;// 右边数组的指针,从mid+1开始
        int cur = left;

        while (iLeft <= mid && iRight <= right)
        {
            // <= 保持稳定性(相等时先取左边)
            if (temp[iLeft] <= temp[iRight]) // 改成 >= 就是降序
                array[cur++] = temp[iLeft++];
            else
                array[cur++] = temp[iRight++];
        }
        
        // 左边剩余拷贝回去(右边剩余不需要:已经在 a 的正确位置)
        while (iLeft <= mid)
            array[cur++] = temp[iLeft++];
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

四、分治法和动态规划的区别

我们发现分治法和动态规划都是划分子问题。

如果子问题重复度极高,用动态规划。子问题重复度不高用分治法。

严谨的说法:

  • 分治法 :把问题拆成相互独立(或基本不重叠)的子问题,分别求解后合并;通常不需要缓存子结果。

  • 动态规划 :子问题存在重叠(Overlapping Subproblems) ,并且满足最优子结构(Optimal Substructure),所以要用记忆化/填表复用子问题结果,避免重复计算。

相关推荐
你撅嘴真丑9 小时前
第九章-数字三角形
算法
uesowys9 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
ValhallaCoder9 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
董董灿是个攻城狮10 小时前
AI 视觉连载1:像素
算法
智驱力人工智能10 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
孞㐑¥11 小时前
算法——BFS
开发语言·c++·经验分享·笔记·算法
月挽清风11 小时前
代码随想录第十五天
数据结构·算法·leetcode
XX風11 小时前
8.1 PFH&&FPFH
图像处理·算法
NEXT0611 小时前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法
代码游侠12 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法