赞
踩
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
1.分解:将要排序的序列每次分解为2个序列,直到不能再分解
2.合并:将分解的序列排序并两两归并

过程:我们需要创建一个临时数组tmp,将每次归并后的结果存入tmp,最后用memcpy将排好后的tmp的数据拷贝到原数组中。
void _MergeSort(int* a, int begin, int end, int* tmp) { if (begin >= end) return;//序列只有一个数的时候,不用也不能再分解 int mid = (begin + end) / 2; _MergeSort(a, begin, mid, tmp); _MergeSort(a, mid+1, end, tmp);//将原序列分解为2段序列 int i = begin; int begin1 = i, end1 = mid; int begin2 = mid + 1, end2 = end;//确定两段序列的首位下标 while (begin1 <= end1 && begin2 <= end2) { if (a[begin1] < a[begin2]) { tmp[i++] = a[begin1++]; } else { tmp[i++] = a[begin2++]; } }//将2段序列中的数按顺序存入tmp while (begin1 <= end1) { tmp[i++] = a[begin1++]; } while (begin2 <= end2) { tmp[i++] = a[begin2++]; }//将没存完的那个序列剩下的值(有序)存入tmp memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));//将tmp拷贝给原数组,加上begin定位排序好的值,因为begin是我们操作2个序列的前一个序列的首下标。不加begin的话就是拷贝整个序列的第一个值,可能不是我们正在归并的序列,还没有被排序。 } void MergeSort(int* a, int n) { int* tmp = (int*)malloc(sizeof(int) * n); if (tmp == NULL) { perror("malloc fail"); return; } _MergeSort(a, 0, n - 1, tmp); free(tmp); }
递归版本时,我们通过将要排序的序列分解、合并,在合并的过程中完成排序。在非递归的版本中,合并的思路和代码实现是一样,主要是如何将序列分解,递归版本可以利用子问题分治实现,非递归就要用循环模拟递归,我们这里引入一个gap
,代表序列的数据个数,首先让gap等于1,这样就将序列分解为好了,然后开始两两归并,之后让gap不断2倍化,直到gap等于原数组的数据个数。这里分解后的序列首位下标之差就是gap-1(因为是双闭区间,序列的数据个数就是gap)。这里还要注意分解的序列的首尾下标不能超过原序列的数据个数。

void MergeSortnonR(int* a, int n) { int* tmp = (int*)malloc(sizeof(int) * n); if (tmp == NULL) { perror("malloc fail"); return; }//临时数组,存归并好的数据 int gap = 1;//分解好的序列的数据个数为gap 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;//要归并的2个序列的首尾下标 int j = begin1; if (end1 >= n || begin2 >= n) { break; } if (end2 >= n) { end2 = n - 1; }//保证首尾下标不越界 while (begin1 <= end1 && begin2 <= end2) { if (a[begin1] < a[begin2]) { tmp[j++] = a[begin1++]; } else { tmp[j++] = a[begin2++]; } } while (begin1 <= end1) { tmp[j++] = a[begin1++]; } while (begin2 <= end2) { tmp[j++] = a[begin2++]; }//排序并合并数据 memcpy(a +i, tmp +i, sizeof(int) * (end2 - i + 1));//将归并好的数据拷贝给原数组 } gap *= 2;//放大排序序列的区间,begin1到end1和begin2到end2这两个区间的数据个数是2倍的gap,所以gap *= 2后新序列还是有序的,只需继续将新序列两两归并即可。 } }
int main() { int a[] = { 2,5,9,1,6,11,3,4 }; int n1 = sizeof(a) / sizeof(a[0]); MergeSort(a, n1); printf("MergeSort:"); for (int i = 0; i < n1; i++) { printf("%d ", a[i]); } printf("\n"); int b[] = { 2,7,3,4,1,2,6,5,11,8 }; int n2 = sizeof(b) / sizeof(b[0]); MergeSortnonR(b, n2); printf("MergeSortnonR:"); for (int i = 0; i < n2; i++) { printf("%d ", b[i]); } return 0; }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。