网站的规划 建设与分析论文,潍坊高端模板建站,《网站开发实训》实验报告,好的seo公司目录
前言
递归实现
代码实现 非递归实现
代码实现
总结 前言
归并排序#xff08;Merge sort#xff09;是建立在归并操作上的一种有效的排序算法。该算法是采用分治法#xff08;Divide and Conquer#xff09;的一个非常典型的应用。
作为一种典型的分而治之思想…目录
前言
递归实现
代码实现 非递归实现
代码实现
总结 前言
归并排序Merge sort是建立在归并操作上的一种有效的排序算法。该算法是采用分治法Divide and Conquer的一个非常典型的应用。
作为一种典型的分而治之思想的算法应用归并排序的实现由两种方法
自上而下的递归所有递归的方法都可以用迭代重写所以就有了第 2 种方法自下而上的迭代
和选择排序一样归并排序的性能不受输入数据的影响但表现比选择排序好的多因为始终都是 O(nlogn) 的时间复杂度。代价是需要额外的内存空间。
递归实现
在我们前边的学习过程中例如合并两个有序数组等问题我们就使用过归并的思想本质上来说归并排序还是分治的思想将大问题化为小问题然后解决小问题最终是实现大问题的解决。 动图演示 归并排序的递归实现并不复杂有以下几个步骤
1.首先申请一段空间tmp用来保存以及排好序的部分数据当所有数据都排序完后重新拷贝回原数组。
2.对数组数据进行分割例如二叉树分为左右子树一样也将数组分割为左右数组知道左指针left大于等于右指针right时返回。
3.对以及递归好的数据进行排序两个区域内的数据进行比较小的数据插入到tmp数组中直至到数组的最后一个数据如果当一个数组提前结束直接将另外一个数组数据直接拷贝即可。
4.将排序好的tmp数组拷贝回原数组。 代码实现
由于原函数不适合递归所以我们定义子函数并且求出left和right进行递归将数组分为[left,mid]和[mid1,right]两个部分切记free我们申请的空间其余按照思路实现即可。
void _MergeSort(int* a, int left, int right, int* tmp)
{if (left right)return;int mid left (right - left) / 2;_MergeSort(a, left, mid, tmp);_MergeSort(a, mid 1, right, tmp);int i left;int begin1 left, end1 mid;int begin2 mid 1, end2 right;while (begin1 end1 begin2 end2){if (a[begin1] a[begin2]){tmp[i] a[begin1];}else{tmp[i] a[begin2];}}while (begin1 end1){tmp[i] a[begin1];}while (begin2 end2){tmp[i] a[begin2];}for (int i left; i right; i){a[i] tmp[i];}
}
void MergeSort(int* a, int n)
{int left 0;int right n - 1;int* tmp (int*)malloc(sizeof(int)*n);if (tmp NULL){perror(malloc fail);exit(-1);}_MergeSort(a, left, right, tmp);free(tmp);tmp NULL;
} 非递归实现 归并的非递归实现起来比递归实现较难一点但是还是分治的思想只不过非递归有点类似于二叉树的后序遍历我们使用gap来控制每次归并时数组内数据个数例如第一次就是一个一个数据归并成两个数据的有序数组第二次使用两个数据的有序数组归并成四个数据的有序数组所以gap是由1开始并且每次乘2。 非递归实现就是在gap等于1时将整个数组元素排序成两个两个有序这个递归实现是不同的。 但是当我们每次将gap乘2时我们发现数组元素个数不一定是2的次方倍所以不进行处理时我们的数组一定会造成越界访问。
我们对每次要归并的数组第一个数组起始为begin1结束为end1第二个数组起始为begin2结束为end2所以就会有以下三种情况越界
1.end1越界即end1n。
2.begin2越界即begin2n。
3.end2越界即end2n。
所以我们要对边界进行修正当边界n时我们将其赋值为n-1修正如下 if (end1 n){end1 n - 1;}if (begin2 n){begin2 n;end2 n - 1;}if (end2 n){end2 n - 1;}
我们注意到当begin1n时我们将begin2 赋值为nend2赋值为n-1我们发现这样的话这段区间就不存在了这是为什么呢我们来探究一下。 我们对程序进行以上的处理发现程序崩溃了通过调试发现是tmp数组越界了那么tmp数组为什么会越界呢 通过测试发现本来只有十个数据所以下标最多到9但是tmp数组的下标10的位置插入元素导致越界这是因为当[begin2,end2]原本不存在但是我们修正让其存在[9,9]多插入一个数据所以导致越界所以我们做一下修改。 处理过后就没有下标的越界了。
代码实现
当我们解决这个问题之后其余代码按照思路实现就好了。
void MergeSortNonR(int* a, int n)
{int* tmp (int*)malloc(sizeof(int) * n);if (tmp NULL){perror(maolloc fail);exit(-1);}int gap 1;while (gap n){for (int i 0; i n; i 2 * gap){int begin1 i, end1 i gap - 1;int begin2 i gap, end2 i 2*gap - 1;int InDex i;if (end1 n){end1 n - 1;}if (begin2 n){begin2 n;end2 n - 1;}if (end2 n){end2 n - 1;}/*printf([%d,%d] , begin1, end1);printf([%d,%d] , begin2, end2);*/while (begin1 end1 begin2 end2){//printf(%d , InDex);if (a[begin1] a[begin2]){tmp[InDex] a[begin1];}else{tmp[InDex] a[begin2];}}while (begin1 end1){//printf(%d , InDex);tmp[InDex] a[begin1];}while (begin2 end2){//printf(%d , InDex);tmp[InDex] a[begin2];}}for (int j 0; j n; j){a[j] tmp[j];}gap * 2;}free(tmp);tmp NULL;
}
总结
我们今天讲解了归并排序的递归和非递归的实现方法码文不易希望可以对大家有所帮助。