1、介绍:
分治是一种算法设计的思想,将大问题分解成多个小问题,例如归并排序将大问题:「排序整个数组」,分解为小问题:「排序左半和右半」;绝大部分情况下「分治算法」通过「递归」实现。即:子问题的求解通过递归方法实现。
算法和数据结构并不是凭空想象出来的,「递归」函数也不例外。「递归」函数基于 「自顶向下」拆分问题,再「自底向上」逐层解决问题的思想设计而成,这是所熟知的「分而治之」的算法思想。
2、分治与递归的解题思路:
分治算法一般通过递归实现
(1)分而治之(Divide-and-Conquer)的思想分为如下三步:
拆分:将原问题拆分成若干个子问题;
解决:解决这些子问题;
合并:合并子问题的解得到原问题的解。
(2)这样的三步恰好与递归的程序写法相吻合:
拆分:即对当前的大问题进行分析,写出相应代码,分解为子问题。
解决:即通过递归调用解决子问题;
合并:即在回溯的过程中,根据递归返回的结果,对子问题进行合并,得到大问题的解。
3、对分治思想的理解
更加形象的一种说法是:一开始我们只有一个问题,我们通过分治,将其分解成多个问题,发散开来,“自顶向下”走出去。在解决完子问题之后,在回溯的过程中合并子问题的解,将发散开来的问题合并成一个,“自底向上”走回来。
典型的分治思想的应用是:归并排序、快速排序、绝大多数「树」中的问题(先把原问题拆分成子树的问题,当子树中的问题解决以后,结合子树求解的结果处理当前结点)(通过修改后的子树来对当前节点进行修改的过程)、链表中的问题。
4、分治与减治思想:
分治思想是将大问题转换为几个小问题,然后将他们的结果合并。而减治思想就是将一个大问题变成一个小问题,小问题的结果就是整个结果,不用合并。
「分治思想」的特例是「减治思想(Decrease-and-Conquer)」:每一步将问题转换成为规模更小的子问题。「减治思想」思想的典型应用是「二分查找」「选择排序」「插入排序」「快速排序」算法。
「分治」与「减治思想」的区别如下:
分治思想:将一个问题拆分成若干个子问题,然后再逐个求解,根据各个子问题得到的结果得到原问题的结果;
减治思想:在拆分子问题的时候,只将原问题转化成 一个 规模更小的子问题,因此子问题的结果就是上一层原问题的结果,每一步只需要解决一个规模更小的子问题,相比较于「分治思想」而言,它没有「合并」的过程。
5、归并排序:
思路:
先对将长序列拆分成短序列,对每个短序列内部排序以后,合并其他短序列,还原成排序好的长序列。
步骤:
1、把长度为n的输入序列分成两个长度为n/2的子序列;
2、对这两个子序列分别采用归并排序;
3、将两个排序好的子序列合并成一个最终的排序序列。
而将两个的有序数列合并成一个有序数列,我们称之为"归并",这就是归并排序名字的由来。
代码实现:
#include <iostream>
using namespace std;
int nums[7] = { 7,3,5,2,9,8 };//待排序数组
int temp[7];//临时存储数组
void merge(int low,int mid,int high) {
int left = low; //左边部分数组指针
int right = mid + 1; //右边部分指针
int k = low; //对temp数组进行操作的指针
while (left < mid + 1 && right < high + 1) {
if (nums[left] > nums[right]) {
temp[k++] = nums[right++];
}
else {
temp[k] = nums[left];
k++;
left++;
}
}
//查看左边序列是否为空
while (left < mid + 1) {
temp[k++] = nums[left++];
}
//查看右边序列是否为空
while (right < high + 1) {
temp[k++] = nums[right++];
}
//移动回原数组
for (int i = low; i <= high; i++) { //这里要i=low阿,不可以等于0
nums[i] = temp[i];
}
}
void mergeSort(int low,int high) {
if(low >= high) {
return;
}
//防止low和high太大导致越界,>>1和除以2一样,不过比/2效率快
int mid = low + ((high - low) >> 1);
//分
mergeSort(low, mid);
mergeSort(mid + 1, high);
//治
merge(low, mid, high);
}
int main() {
mergeSort(0, 5);
for (int i = 0; i <=5; i++) {
cout << nums[i] << " ";
}
cout << endl;
return 0;
}