【算法】学习笔记(4):分治思想 归并排序

分治思想,分治策略,自古有之,与人类生活息息相关,其本质是将大问题拆解为小问题,小问题转换为已知解的问题,进而求解。

军队管理,国家分级治理……

在这里插入图片描述

大规模数据排序,例如10000000000万个数,规模大的时候,分治思想就很重要了。

基本思想

分!如果问题还大,就再分!直到其变成容易求解的基本问题,这个过程其实与递归的类似的。

在这里插入图片描述
总而言之,递归思想与分治策略,有着密不可分的联系。

对于分解之后的基本问题,我们就可以使用一些基本的策略求解,因为容易,比如枚举。

在这里插入图片描述

核心策略

  1. 分:大问题–> 小问题 --> 基本问题
  2. 治:解决基本问题
  3. 合:将基本问题的解合并,得到原问题的解
    在这里插入图片描述在这里插入图片描述
    抽象的理论内容,很重要,我们把握其核心思想和本质,但是,想要理解抽象,我们更应该解决实际问题,在实际问题中理解抽象概念,达到融会贯通。

基本框架程序

在这里插入图片描述
在这里插入图片描述

  1. 理解问题
  2. 分解问题,找到自己认识的部分;或者,从最简单情况出发,递推地分析一下
  3. 获得简单问题的求解办法
  4. 将大问题递归地分解为简单问题去处理
  5. 将每个小问题的解合并

如此抽象,说了也白说,直接上例子。

归并排序

最难点:【合】的策略,合无定法!

在这里插入图片描述
分治策略与递归的对应关系

分:进行递归操作
治:递归终止条件和处理办法
合:递归处理办法

对于归并排序

  1. 分:将数组不断进行二分,直到其剩余1个元素
  2. 治:对于1个元素,一定是有序的,就可以将其作为基本问题的解返回
  3. 合:对于基本问题的解,需要让其合并后有序,因此合并需要专门的一些策略,针对归并排序特点进行设计。

合是最难的,因为合无定法,每种问题的每种解法,可能都不一样。

看代码:

#include <ctime>
#include <iostream>
using namespace std;// 给你一个规模很小的数组,并且告诉你分两半,每一半都是有序的,让你给合起来依然有序
// 合
void merge(int data[], int buffer[], int min, int mid, int max) {int first_mid_pointer = min;		// data[min, mid]int second_mid_pointer = mid + 1;	// data[mid+1, max]int buffer_pointer = min;			// buffer[min, max]while (first_mid_pointer <= mid && second_mid_pointer <= max) {if (data[first_mid_pointer] <= data[second_mid_pointer]) {buffer[buffer_pointer] = data[first_mid_pointer];buffer_pointer++;first_mid_pointer++;}else{buffer[buffer_pointer++] = data[second_mid_pointer++];}}// 传递剩余部分if (first_mid_pointer <= mid) {while (first_mid_pointer <= mid && buffer_pointer <= max) {buffer[buffer_pointer++] = data[first_mid_pointer++];}} else {while (second_mid_pointer <= max && buffer_pointer <= max) {buffer[buffer_pointer++] = data[second_mid_pointer++];}}}// 归并排序
void merge_sort(int data[], int buffer[], int min, int max) {// 治if (min >= max)return;if (min < max){// 分int mid = (max + min) / 2;	// + ;not -merge_sort(data, buffer, min, mid);merge_sort(data, buffer, mid + 1, max);// 合(“治”之后才会执行)merge(data, buffer, min, mid, max);// buffer result --> datafor (int i = min; i <= max; i++) {	// 注意起点和终点,注意“=”data[i] = buffer[i];}}
}int main()
{clock_t start, end;for (int n = 64; ; n *= 2) {// initializationint *a = new int[n];for (int i = 0; i < n; i++) {a[i] = rand() % 10000 + 1;}// merge sortstart = clock();int length = n; //sizeof(a) / sizeof(a[0]);int *buffer = new int[length];merge_sort(a, buffer, 0, length - 1);end = clock();cout << "N = " << n << "   time = " << end - start << endl;if ((end - start)*2 > 180000)	// predict: more than 3 minutes,stop!break;}return 0;}

类似版本的代码

#include <iostream>
using namespace std;// combine function
// data sequence: min to max
void combine(int data[], int buffer[], int min, int mid, int max) {// NOTE: max = length of array - 1int before_mid_pointer = min;		// data[min,mid]int after_mid_pointer = mid + 1;	// data[mid+1,max]int buffer_pointer = min;			// buffer[min,max]while (before_mid_pointer <= mid && after_mid_pointer <= max){if (data[before_mid_pointer] <= data[after_mid_pointer])buffer[buffer_pointer++] = data[before_mid_pointer++];elsebuffer[buffer_pointer++] = data[after_mid_pointer++];}// process the rest of data that is not be compared// add them to buffer directlywhile (before_mid_pointer <= mid && buffer_pointer <= max){buffer[buffer_pointer++] = data[before_mid_pointer++];}while (after_mid_pointer <= max && buffer_pointer <= max){buffer[buffer_pointer++] = data[after_mid_pointer++];}// add buffer to datafor (int i = min; i <= max; i++) {data[i] = buffer[i];}}// 自始至终,我们都是使用一个data和一个buffer,通过指针值“虚拟地”分割和排序。
// merge sort
void merge_sort(int data[], int buffer[], int min, int max) {if (max > min) {// divideint mid = (max + min) / 2;merge_sort(data, buffer, min, mid);merge_sort(data, buffer, mid + 1, max);// combine: sort two sorted arrays using specified methodcombine(data, buffer, min, mid, max);} else {// conquer: only 1 elementreturn;}
}int main() {int data[8] = { 1,3,5,0,100,4,33,7 };int buffer[8] = { 0 };merge_sort(data, buffer, 0, 7);for (int i = 0; i < 8; i++) {cout << buffer[i] << "  ";}return 0;
}

小结

分治思想,用一个成语就是庖丁解牛,完整的牛我们搞不懂,就将其合理地拆解,分成小部分,然后就可以搞定了。

还需要大量实例去体会分、治、合的思想策略。

我们知道了分治策略与递归思想的结合。

治理的是基本问题,也就是递归的结束条件和结束时候的处理办法。

而分则是递归调用过程,它指明了我们应该如何调用递归函数去分割问题,使其更简化。

最后,,则是在某个递归函数返回之后的处理办法,它也在递归处理过程内,只有递归返回后,才会执行,用于合并返回的基本问题的解,从而得到最终的复杂问题的解。

对于归并排序,我们有一个比较神奇的点,那就是,自始至终,data和buffer都使用的是一个,而所谓的分割,都是通过虚拟的指针来实现的,我们并没有真地将其分割!

算法学习策略

  1. 原理与思想本质
  2. 实例与图解
  3. 实际问题分析
    1. 抽象
    2. 实现

需要这几个过程,才能真正体会算法思想的精髓,通过大量实例和图解,能够更好地理解算法,理解思想本质。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html css 学习笔记(1)背景相关

背景颜色 图片 插入图片img背景图片 背景图片 3. logo 4. 大图 5. 装饰性小图 便于控制位置&#xff01; 插入后会执行自动平铺&#xff0c;这与插入图片是不同的&#xff01; div{width: 600px;height: 300px;background-image: url(img/登录用户头像.png); }小结 盒子的第…

2020-12-15 CPU设计复盘

SOC修改 将之前完成的31条指令单周期CPU进行了重构&#xff0c;将其分开&#xff0c;实现了内外有别&#xff0c;将CPU、指令ROM和数据RAM。 这样&#xff0c;以后为其增加接口外设&#xff0c;总线控制&#xff0c;才更加清晰&#xff0c;这是进一步封装和抽象。 MARS大坑 …

Tomcat 学习笔记(0)

JavaWeb 用Java写的程序&#xff0c;可以在浏览器运行。 Request & Responce Web资源 Web服务器 我们在自己的主机启动Tomcat服务器&#xff0c;然后运行它&#xff0c;就能够通过主机访问这个服务器&#xff0c;这个服务器能够运行我们的程序。 部署Web工程 法1 将web…

计算机系统 学习笔记(0)南京大学(一)第一周

课程&#xff1a;计算机系统基础 核心理念&#xff1a;人类世界与计算机世界的异同 人类世界 直观感受数学 计算机世界 与数学不同&#xff0c;存储首先&#xff0c;各层次与现实世界不同 我们关注点是差异点&#xff01; 一样的你就不用关心了&#xff0c;关心差异&#…

x86架构下 CF与OF标志位 带符号和无符号运算 详解

针对能够影响OF和CF标志位的指令&#xff0c;一般来说是涉及到数据运算的指令&#xff0c;这里使用add举例&#xff0c;即不区分有无符号的加法指令&#xff0c;参与运算的数据&#xff0c;从二进制层级去考虑。 CF标志位 对于CF&#xff0c;它是carry flag&#xff0c;进位标…

tmux学习笔记

参考学习链接 我们需要理解几个重要的概念 session 回话window 窗口pane 窗格 window 我们打开的一个terminal就是一个window. 而打开的这个window&#xff0c;也就是打开了一个session&#xff0c;打开window&#xff0c;session开始&#xff1b;关闭window&#xff0c;se…

Linux的ext4文件系统学习笔记

补充&#xff1a;设备独立性 Linux中&#xff0c;设备驱动以文件形式表示&#xff0c;用户操作逻辑设备就是操作文件&#xff0c;而不是具体的物理设备&#xff0c;也就是说&#xff0c;用户操作的是功能&#xff0c;是黑箱&#xff0c;而不是真正的实体。 APP操作的都是逻辑…

html基础元素案例笔记(1)

这是代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>CSS FlexBox test</title><link rel"stylesheet" type"text/css" href"./css/index.css"></head><body>…

C语言中的struct和union区别

参考&#xff1a;Difference between Structure and Union in C 二者区别 struct 这里不做详细说明&#xff0c;因为参考链接中都写明了。只做一些重点强调。 struct中声明的变量&#xff0c;在分配空间的时候&#xff0c;struct结构空间大小&#xff0c;大于等于其内部所有…

Leetcode1512. 好数对的数目 抽出本质原型 利用范围条件

解法1&#xff1a;暴力枚举 class Solution {public int numIdenticalPairs(int[] nums) {int count 0;for(int i 0;i < nums.length; i){for(int j i 1; j < nums.length; j){if(nums[i] nums[j])count;}}return count;} }没啥可说的&#xff0c;就是小学数学问题…

leetcode面试题 10.01. 合并排序的数组

直接排序 直接使用Java已有的方法进行排序&#xff0c;这一招…大意了&#xff01; 这题简单&#xff0c;就是个基本的排序&#xff0c;后面难题&#xff0c;可能这只是一小步&#xff0c;内个时候直接用排序算法比较合适&#xff0c;这个不合适。。 class Solution {public…

IA-32 Architecture: the function of segment regitster(CS DS SS ES)

对于IA-32架构&#xff0c;与8086不同&#xff0c;段寄存器不再是像以前一样&#xff0c;直接作为段基址&#xff0c;因为32位的寄存器直接就可以表示4GB大小&#xff0c;不需要再偏移&#xff0c;因此段寄存器的含义也发生了相应的变化。 在IA-32架构里&#xff0c;段寄存器是…

x86异常处理与中断机制(1)概述中断的来源和处理方式

参考《计算机组成》&#xff08;北京大学 MOOC&#xff09; 1 异常与中断的来源&#xff08;为什么需要中断&#xff09; 首先&#xff0c;说明一下异常和中断这两个概念。 它们两个唯一的区别&#xff0c;就是&#xff0c;没有什么区别。只是不同的地方不同的时间不同的人的…

【C language】动态数组的创建和使用

在C语言中&#xff0c;使用malloc函数创建动态数组&#xff0c;使用一个指针指向它&#xff0c;使用下标进行访问。 unsigned long *a (unsigned long *)malloc(2 * sizeof(int)); a[0] 1000; a[1] 2000; printf("%d %d\n", a[0], a[1]); free(a);上述例子&…

x86异常处理与中断机制(2)中断向量表

补充&#xff1a;事件不仅包含中断和异常&#xff0c;还包含系统调用&#xff0c;这个属于用户主动请求的事件。 上一节&#xff0c;只有一个溢出异常&#xff0c;那么&#xff0c;如果很多异常、中断呢&#xff1f;&#xff08;中断向量表&#xff09; 另外&#xff0c;之前0…

x86异常处理与中断机制(3)中断处理过程

上一节讲完了根据中断类型号找中断服务程序的过程&#xff0c;现在着重说明一下更加完整的中断处理过程吧。 本节以8086时代的中断处理过程为例进行说明&#xff0c;主要分两大部分 硬件处理软件处理 需要注意&#xff0c;这不是绝对的&#xff0c;得看实际情况&#xff0c;…

Linux 0.11 内核解析:中断相关(1)asm.s文件中断处理分析

0 源代码 有两个版本的&#xff0c;一个是带中文注释&#xff0c;Intel格式的&#xff1b;一个是不带注释是AT&T格式的。 Linux 0.11 中文注释版 Linux 0.11 源码&#xff0c;基于《Linux内核完全注释》赵炯 1 asm.s 文件 我们先假设该文件处理的中断是无特权过渡的情况…

【精华文】C语言结构体特殊情况分析:结构体指针 / 基本数据类型指针,指向其他结构体

参考链接&#xff1a;Structure pointer pointing to different structure instance 注&#xff1a;可以查看此篇的问题和唯一的回复&#xff0c;那是相对正确的&#xff0c;不要看comment&#xff0c;有很多错误。 我是拒绝分析这种问题的&#xff0c;因为似乎没有人会这么乱用…

enum in c language

今天说说C语言中的枚举。 参考&#xff1a;Enumeration (or enum) in C 1 定义 定义一个枚举类型很容易&#xff1a; enum aa { a1, a2, a3 };这里 enum是关键字aa是枚举变量&#xff0c;也就是我们自定义类型a1,a2,a3是枚举成员 然后怎么使用呢&#xff1f; 首先&#…

信号量SIGCHLD的使用,如何让父进程得知子进程执行结束,如何让父进程区分多个子进程的结束

本教程基于 Ubuntu 20.10 gcc 10.2.0. 示例程序如果不能正常编译和执行&#xff0c;说明您系统和工具版本与我的不匹配&#xff0c;请自行查阅资料。 0 概述 先给出该信号的描述&#xff1a; SignalValueDescriptionSIGCHLD17Child status has changed (POSIX). Signal sent …