最近面试的时候被问到了归并排序,之前学数据结构的时候了解过,但是并没有手动实现过它的原理,今天实现一下。
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
其实也就是利用了递归的思想,把我们的整个序列不断的划分,直到划分到元素为1的N个子序列,然后开始合并。
首先我们得将我们的序列转化成一个个子队列,直到分离到最小的单位,然后开始合并,分离很简单,那么如何合并呢?先上一张经典图:
红色的代表左右指针当前指向的元素,左指针是左边序列的开始,右指针是右边序列的开始,也是mid指针(他俩的中间位置)右边的元素,对比他们的大小,决定插入的顺序,如果左边的元素小于右边的元素,那么就往新空间插入这个元素,然后把左 指针往后移动一位,继续比较,如果小于则同上,直到我们的左指针大于等于我们的mid指针,或者右指针大于等于最右的位置,说明其中的一个序列已经对比完毕了,上图演示的是一种理想情况,其实我们有可能遇见一方序列全部小于一方序列的情况,那么这种情况我们需要手动将剩余序列填入合并序列的后面,然后我们重复这个过程,就可以完成一次归并排序了。
但是上面又个问题,我们合并的序列放在哪里?如果放在原队列的话可能会改变一些值,所以我们需要再开辟一片空间去记录中间状态的序列,下次合并还需要用到它,加上这个,代码思路就完整了。
下面看看代码:
// 归并排序
// 分离函数,参数x 和 y分别代表要分离数列的开头和结尾
int n;
int a[10], b[10];
void Merge(int low, int mid, int high);
void mergeSort(int x, int y) {
if (x >= y) {
return;
}
int mid = (x + y) / 2;
// 递归继续合并
mergeSort(x, mid);
mergeSort(mid + 1, y);
Merge(x, mid, y);
}
void Merge(int low, int mid, int high) {
int i = low, j = mid + 1, k = low;
while (i <= mid && j <= high) {
if (a[i] < a[j]) {
b[k++] = a[i++];
} else {
b[k++] = a[j++];
}
}
while (i <= mid) {
b[k++] = a[i++];
}
while (j <= high) {
b[k++] = a[j++];
}
for (int i = low; i <= high; i++) {
a[i] = b[i];
}
}
int main(int argc, const char * argv[]) {
// insert code here...
cout << "请输入数组个数n:";
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
mergeSort(0, n - 1);
for (int i = 0; i < n; i++) {
cout << a[i] << endl;
}
return 0;
}