归并排序
一.算法描述:
我们一般采用的是二路归并——折半归并,每次将数字的量缩小一倍;最后再将有序的数组两两合并。
二.实现——合并两个有序数组
1.意义:在这里,无论是递归还是非递归都是要进行有序数组合并这一步的;
2.步骤:
1)将部分有序的数组分割成两个完全有序的数组——需要用到额外的空间来保存数组的值。
2)合并
template <class T>
void merge(vector<T>& v, int left, int mid, int right) {
vector<T> l(v.begin() + left, v.begin() + mid + 1);
vector<T> r(v.begin() + mid + 1, v.begin() + right + 1);
int i = 0, j = 0, k = left;
while (i < l.size() && j < r.size()) {
if (l[i] < r[j]) {
v[k++] = l[i++];
}
else {
v[k++] = r[j++];
}
}
if (i >= l.size()) {
while (j < r.size()) {
v[k++] = r[j++];
}
}
if (j >= r.size()) {
while (i < l.size()) {
v[k++] = l[i++];
}
}
}
三.递归版本:
1.利用函数调用栈的性质来实现归并
//递归
template <class T>
void _merge_sort(vector<T>& v, int left, int right) {
if (left >= right) {
return;
}
else {
int mid = (left + right) / 2;
_merge_sort(v, left, mid);
_merge_sort(v, mid + 1, right);
merge(v, left, mid, right);
}
}
四.非递归版本
1.描述:
需要解决的在于:如何将数组每次减半
方法:在这里我们设置一个变量sz用来控制每次归并的数据的量,该变量每次更新时翻倍更新即可
//非递归版本
template <class T>
void mergeSort(vector<T>& v, int size) {
if (size < 2) {
return;
}
int sz = 1; //每次归并的组内的数字步幅
while (sz <= size) {
int begin = 0, mid = 0, end = 0;
while (end < size - 1) {
mid = begin + sz - 1;
end = mid + sz;
if (end >= size) {
end = size - 1;
}
if (mid >= size) {
mid = (begin + end) / 2;
}
merge(v, begin, mid, end);
begin = end + 1;
}
sz *= 2;
}
}
五.总结
注意:
1.无论是递归还是非递归,我们需要注意的就是区间,在这里合并数组和递归版本的分割区间采用的都是闭区间。