算法竞赛 入门经典---刘汝佳 第八章 我就打一遍博客,再次熟悉原理。。。。。。。
归并排序
第一种高效的排序算法是归并排序。按照分治 三部法,对归并排序的介绍如下。
1.划分问题: 把序列分成元素个数尽量相等的两半。
2.递归求解: 把两半元素分别排序。
3.合并问题: 把两个有序表合并成一个。
书上的介绍就是这样,但如果是新手肯定不会懂于是我特意找了一张图帮助理解,
百闻不如一见,排序的思路一看没有问题就会懂。
接下来是代码:
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> ve;
int n;
ve nums;
void merge_sort(ve& nums, int start, int end) {
if(end - start > 1) { //左闭 右开 **********例如:1 2 3 [1,2) [2,3)
int mid = start + (end-start)/2; //向下取整
merge_sort(nums, start, mid); //拆分
merge_sort(nums, mid, end); // 拆分
ve temp(n); //创建临时的数组储存值
int i = start, j = mid, k = start; //后面要变化这些变量 所以 创建新的变量存储
while(i < mid || j < end ) {
if(j >= end || (i < mid && nums[i] < nums[j])) temp[k++] = nums[i++];
else temp[k++] = nums[j++];
}
for(int u = start; u < k; ++u) nums[u] = temp[u]; //注意是从 哪里开始赋值的 这里 很重要
}
}
int main() {
cin >> n; //输入你需要排序的个数
int temp;
for(int i = 0; i < n; ++i) cin >> temp,nums.push_back(temp); //getin n
merge_sort(nums, 0, n); //左闭 右开
for(int i = 0; i < n; ++i) cout << nums[i] << " ";
return 0;
}
时间复杂度是 O(nlogn),证明我也不会,脑子理想一遍过程 就知道 它是小于 O(n^2)的。。。。
值得注意的是,边界条件要一直注意,利用左闭右开 , 还有就是 || 的用法, 但左式子成立时就不会考虑右边的式子。
利用这一点可以简化代码,while循环的赋值等价于下面代码:
while (i < mid &&j < end) { //挑选两部分中最小的元素放入辅助数组中
if (nums[i] < nums[j])
temp[k++] = nums[i++];
else
temp[k++] = nums[j++];
}
while (i < mid)//如果还有剩余,直接放入到辅助数组中
temp[k++] = nums[i++];
while (j < end)
temp[k++] = nums[j++];
巧用 || 确实可以 简化代码但是, 思维的理解却是在原来代码上基础的上改进的。。。各有各的好处。
以下是用迭代写的:(迭代难理解,但是写出来就很简单找错,下面是在第一个的代码上强行加上去的)
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> ve;
int n;
ve nums, nums1;
void merge_sort(ve& nums, int start, int end) {
if(end - start > 1) { //左闭 右开 **********例如:1 2 3 [1,2) [2,3)
int mid = start + (end-start)/2; //向下取整
merge_sort(nums, start, mid); //拆分
merge_sort(nums, mid, end); // 拆分
ve temp(n); //创建临时的数组储存值
int i = start, j = mid, k = start; //后面要变化这些变量 所以 创建新的变量存储
while(i < mid || j < end ) {
if(j >= end || (i < mid && nums[i] < nums[j])) temp[k++] = nums[i++];
else temp[k++] = nums[j++];
}
// while (i < mid &&j < end) { //挑选两部分中最小的元素放入辅助数组中
// if (nums[i] < nums[j])
// temp[k++] = nums[i++];
// else
// temp[k++] = nums[j++];
// }
// while (i < mid)//如果还有剩余,直接放入到辅助数组中
// temp[k++] = nums[i++];
// while (j < end)
// temp[k++] = nums[j++];
for(int u = start; u < k; ++u) nums[u] = temp[u]; //注意是从 哪里开始赋值的 这里 很重要
}
}
void merge_sort1(ve& nums1) { //利用迭代实现代码。
for(int step = 2; step < n*2; step*=2 ) {
for(int i = 0; i <= n; i += step) {
int mid = i + step/2,start = i, end = min(i + step, n);//这个end的边界条件要注意
if(mid < n) { //如果中点在范围内,才执行下面的处理
int s = start, e = mid, k = start;
ve temp(n);
while(s < mid || e < end ) {
if(e >= end || (s < mid && nums1[s] < nums1[e])) temp[k++] = nums1[s++];
else temp[k++] = nums1[e++];
}
for(int u = start; u < k; ++u) nums1[u] = temp[u]; //注意是从 哪里开始赋值的 这里 很重要
// cout << step << " " << start << ' ' <<mid << ' ' << end << endl; for(int i = 0; i < n; ++i) cout << nums1[i] << " ";
// cout <<endl;
}
}
}
}
int main() {
cin >> n; //输入你需要排序的个数
int temp;
for(int i = 0; i < n; ++i) cin >> temp,nums.push_back(temp); //getin n
nums1 = nums;
merge_sort(nums, 0, n); //左闭 右开
for(int i = 0; i < n; ++i) cout << nums[i] << " ";
cout << endl ;
merge_sort1(nums1);
for(int i = 0; i < n; ++i) cout << nums1[i] << " ";
return 0;
}