
- 画图,自己整个数组,看代码写步骤,这个对理解归并排序还是很有必要的
- 合并两个有序数组的merge函数写法
- 时间复杂度的分析方法!!!
- 其实我觉得去b站找个动态的步骤分解视频也是不错的复习方法,当然要自己先回想
- 稳定,快速
- 递归调用,分治思想
- 合并两个有序数组的思想
- 时间复杂度O(nlogn),这个时间复杂度的分析方法很重要一定要掌握
恋上数据结构笔记 归并排序与时间复杂度
这个图可能会很有用
图片来自:恋上数据结构结构与算法第二季-李明杰老师
归并排序本体函数
从输出也能大致看出来归并排序的归并顺序,每次merge都会打印一次数组
图片来自:恋上数据结构结构与算法第二季-李明杰老师
void mergeSort(vector&array, int begin, int end) { //有点类似树的递归访问,每次调用都把当前数组一分为二,直到不可再分就return,两个都return后,merge成一个有序数组,再不断往回merge成有序数组 if (end - begin + 1 < 2) { return; } int mid = (begin + end) / 2; mergeSort(array, begin, mid); mergeSort(array, mid+1, end); merge(array, begin, end); vectorPrint(array); }
输入数组: 6 9 3 1 2 0 8 29 15 11 10 归并排序基础版 6 9 3 1 2 0 8 29 15 11 10 3 6 9 1 2 0 8 29 15 11 10 3 6 9 1 2 0 8 29 15 11 10 3 6 9 0 1 2 8 29 15 11 10 0 1 2 3 6 9 8 29 15 11 10 0 1 2 3 6 9 8 29 15 11 10 0 1 2 3 6 9 8 15 29 11 10 0 1 2 3 6 9 8 15 29 10 11 0 1 2 3 6 9 8 10 11 15 29 0 1 2 3 6 8 9 10 11 15 29 算法用时:(微秒) [AlgoTime: 20007 us] 输入数组: 6 9 3 1 2 0 8 29 15 11 10 归并排序归并换个写法 6 9 3 1 2 0 8 29 15 11 10 3 6 9 1 2 0 8 29 15 11 10 3 6 9 1 2 0 8 29 15 11 10 3 6 9 0 1 2 8 29 15 11 10 0 1 2 3 6 9 8 29 15 11 10 0 1 2 3 6 9 8 29 15 11 10 0 1 2 3 6 9 8 15 29 11 10 0 1 2 3 6 9 8 15 29 10 11 0 1 2 3 6 9 8 10 11 15 29 0 1 2 3 6 8 9 10 11 15 29 算法用时:(微秒) [AlgoTime: 22006 us]
merge函数!!重要(两个有序数组合并成一个有序数组)
图片来自:恋上数据结构结构与算法第二季-李明杰老师
- 这个函数比较重要
- 重点理解三个指针的 *** 作和循环终止的条件
- 这个写法不便于理解,后面那个比较好理解
//merge函数就是将两个有序数组合并成一个有序数组,由于归并排序中,这两个数组都在一个数组内,所以这里参数begin是左数组的第一位,end是右数组的最后一位 //这里的begin,mid,end都代表的是数组下标 //merge的整体思想是,两个有序数组,两个指针分别指向首位,指针指向的二者进行比较,小的先放入新数组,同时插入的元素对应数组指针++,另一个不变,接着比 //还是画图比较好理解,但这个也不难 void merge(vectormerge函数写法2&array, int begin, int end) { vector temp = {};//定义临时数组,用于暂时存放合并并排序的有序数组,最后再覆盖给array int mid = (begin + end) / 2; //求mid,mid是左数组的终端,mid+1是右数组的起点,这和mergeSort函数中上面两个递归调用的begin与mid和end是一样的 int tempPointer = 0; int leftBeginPointer = begin;//不要想当然以为左数组起点下标一定是0,这要看你传进来的是从哪开始的数组 int rightBeginPointer = mid + 1; //这里定义了三个指针,分别指向临时数组的下一个插入位置(vector就不需要了,就是个摆设),左数组的下一个插入元素,右数组的下一个插入元素 while (tempPointer != end + 1)//当临时数组长度已经等于右数组末尾长度(左右数组长度和),说明都插入了,结束循环 { if (array[leftBeginPointer] <= array[rightBeginPointer]) { temp.push_back(array[leftBeginPointer]); tempPointer++; leftBeginPointer++; } else if (array[rightBeginPointer] < array[leftBeginPointer]) { temp.push_back(array[rightBeginPointer]); tempPointer++; rightBeginPointer++; } //若检测一个数组已经全部插入,则直接把另一个数组剩余元素全部插入退出即可 if (leftBeginPointer == mid + 1) { while (rightBeginPointer != end + 1) { temp.push_back(array[rightBeginPointer]); tempPointer++; rightBeginPointer++; } break; } else if (rightBeginPointer == end + 1) { while (leftBeginPointer != mid + 1) { temp.push_back(array[leftBeginPointer]); tempPointer++; leftBeginPointer++; } break; } } //用临时数组覆盖array对应位置的数组 for (int i = 0; i < end - begin + 1; i++) { array[begin + i] = temp[i]; } }
这是merge函数的另一种写法,因为写法不是唯一的,多看看以免以后考到不会
这个是先有一个数组全部插入了就截止,然后再把另一个数组剩余的全部插入
void merge2nd(vector&array, int begin, int end) { vector temp = {};//定义临时数组,用于暂时存放合并并排序的有序数组,最后再覆盖给array int mid = (begin + end) / 2; //求mid,mid是左数组的终端,mid+1是右数组的起点,这和mergeSort函数中上面两个递归调用的begin与mid和end是一样的 int tempPointer = 0; int leftBeginPointer = begin;//不要想当然以为左数组起点下标一定是0,这要看你传进来的是从哪开始的数组 int rightBeginPointer = mid + 1; //这里定义了三个指针,分别指向临时数组的下一个插入位置,左数组的下一个插入元素,右数组的下一个插入元素 while(leftBeginPointer 完整代码 #include#include #include "MeasureAlgoTime.hpp" using namespace std; // void vectorPrint(vector &array) { for (int i = 0; i < array.size(); i++) { cout << array[i] << ' '; } cout << endl; } //merge函数就是将两个有序数组合并成一个有序数组,由于归并排序中,这两个数组都在一个数组内,所以这里参数begin是左数组的第一位,end是右数组的最后一位 //这里的begin,mid,end都代表的是数组下标 //merge的整体思想是,两个有序数组,两个指针分别指向首位,指针指向的二者进行比较,小的先放入新数组,同时插入的元素对应数组指针++,另一个不变,接着比 //还是画图比较好理解,但这个也不难 void merge(vector &array, int begin, int end) { vector temp = {};//定义临时数组,用于暂时存放合并并排序的有序数组,最后再覆盖给array int mid = (begin + end) / 2; //求mid,mid是左数组的终端,mid+1是右数组的起点,这和mergeSort函数中上面两个递归调用的begin与mid和end是一样的 int tempPointer = 0; int leftBeginPointer = begin;//不要想当然以为左数组起点下标一定是0,这要看你传进来的是从哪开始的数组 int rightBeginPointer = mid + 1; //这里定义了三个指针,分别指向临时数组的下一个插入位置(vector就不需要了,就是个摆设),左数组的下一个插入元素,右数组的下一个插入元素 while (tempPointer != end + 1)//当临时数组长度已经等于右数组末尾长度(左右数组长度和),说明都插入了,结束循环 { if (array[leftBeginPointer] <= array[rightBeginPointer]) { temp.push_back(array[leftBeginPointer]); tempPointer++; leftBeginPointer++; } else if (array[rightBeginPointer] < array[leftBeginPointer]) { temp.push_back(array[rightBeginPointer]); tempPointer++; rightBeginPointer++; } //若检测一个数组已经全部插入,则直接把另一个数组剩余元素全部插入退出即可 if (leftBeginPointer == mid + 1) { while (rightBeginPointer != end + 1) { temp.push_back(array[rightBeginPointer]); tempPointer++; rightBeginPointer++; } break; } else if (rightBeginPointer == end + 1) { while (leftBeginPointer != mid + 1) { temp.push_back(array[leftBeginPointer]); tempPointer++; leftBeginPointer++; } break; } } //用临时数组覆盖array对应位置的数组 for (int i = 0; i < end - begin + 1; i++) { array[begin + i] = temp[i]; } } void merge2nd(vector &array, int begin, int end) { vector temp = {};//定义临时数组,用于暂时存放合并并排序的有序数组,最后再覆盖给array int mid = (begin + end) / 2; //求mid,mid是左数组的终端,mid+1是右数组的起点,这和mergeSort函数中上面两个递归调用的begin与mid和end是一样的 int tempPointer = 0; int leftBeginPointer = begin;//不要想当然以为左数组起点下标一定是0,这要看你传进来的是从哪开始的数组 int rightBeginPointer = mid + 1; //这里定义了三个指针,分别指向临时数组的下一个插入位置,左数组的下一个插入元素,右数组的下一个插入元素 while(leftBeginPointer &array, int begin, int end) { //有点类似树的递归访问,每次调用都把当前数组一分为二,直到不可再分就return,然后merge成一个有序数组,再不断merge if (end - begin + 1 < 2) { return; } int mid = (begin + end) / 2; mergeSort(array, begin, mid); mergeSort(array, mid+1, end); merge(array, begin, end); vectorPrint(array); } void mergeSort2nd(vector &array, int begin, int end) { if (end - begin + 1 < 2) { return; } int mid = (begin + end) / 2; mergeSort2nd(array, begin, mid); mergeSort2nd(array, mid+1, end); merge2nd(array, begin, end); vectorPrint(array); } int main() { Tools::Time::AlgoTimeUs time1; Tools::Time::AlgoTimeUs time2; Tools::Time::AlgoTimeUs time3; vector array; array = {6, 9, 3, 1, 2, 0, 8, 29, 15, 11, 10}; vector array2 = array; vector array3 = array; cout << "输入数组:" << endl; vectorPrint(array); time1.start(); cout << "归并排序基础版" << endl; mergeSort(array, 0, array.size() - 1); cout << "算法用时:(微秒)"; time1.printElapsed(); cout << "输入数组:" << endl; vectorPrint(array2); time1.start(); cout << "归并排序归并换个写法" << endl; mergeSort(array2, 0, array2.size() - 1); cout << "算法用时:(微秒)"; time1.printElapsed(); return 0; } 欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)