这次是按照 Introduction to Algorithm 的归并排序来写的C++实现算法,其中复用了前面用过的合并两个数组的算法。
STL函数:for_each(vecI1.begin(), vecI1.end(), Print<int>());
这次用了for_each这个STL中的标准函数,代替了前面自己写的for_all函数,用法也很简单,前面两个参数是数组的范围,第三个参数可以是函数也可以是函数对象,就是实现用这个函数操作每一个数组的元素。
我发现Introduction to Algorithm这本书虽然经典,但是它也没有很好的处理下标问题,所以我在编程的时候也不能直接抄它的下标,必须要自己认真核对,它处理的下标应该是有错的,下面我也标志处错处了。下面是C++代码,注释出了书本上的伪代码,比较一下吧:
包括了一个头文件,就是这里的一个算法:http://blog.csdn.net/kenden23/article/details/12234567
#pragma once
/*****
Merge.h
已知两线性表中的数据元素按值非递减排列,归并两线性表到新的线性表,是的数据元素也按值非递减排列
*****/
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
void mergeList(vector<T> &t, vector<T> &t1, vector<T> &t2)
{
t.clear();
auto iter1=t1.begin(), iter2=t2.begin(), iter=t.begin();
while(iter1!=t1.end() && iter2!=t2.end())
{
if(*iter1<=*iter2)
{
t.push_back(*iter1);
++iter1;
}
else
{
t.push_back(*iter2);
++iter2;
}
}
while(iter1!=t1.end())
{
t.push_back(*iter1);
iter1++;
}
while(iter2!=t2.end())
{
t.push_back(*iter2);
iter2++;
}
}
下面是主文件代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include"Merge.h"
using namespace std;
template<typename T>
void myMerge(vector<T> &t, int p, int q, int r)
{
int n1 = q-p+1;
int n2 = r-q+1;
int k;
vector<T> leftT(t.begin()+p-1, t.begin()+q);
vector<T> rightT(t.begin()+q, t.begin()+r);
vector<T> tempT;
mergeList(tempT, leftT, rightT);
auto itTemp = tempT.begin();
for(k=p-1; itTemp!=tempT.end(); k++, itTemp++)
{
t.at(k)=*itTemp;
}
}
/* Introduction to Algorithm 中的算法
MERGE(A, p, q, r)
1 n1 = q - p + 1
2 n2 = r - q //这里的下表按照C++的思维习惯的话,应该是不对的,应该是n2=r-q+1
3 letL[1.. n1 + 1] and R[1.. n2 + 1] be new arrays
4 for i = 1 to n1
5 L[i] = A[p + i - 1]//这里是正确的
6 for j = 1 to n2
7 R[j] = A[q + j ] //这里也应该不对,改为:A[q+j-1]
8 L[n1 + 1] = 无穷大//其实下面就是mergeList的算法,不过有点不一样罢了,效果一样
9 R[n2 + 1] = 无穷大
10 i = 1
11 j = 1
12 for k = p to r
13 if L[i] <= R[j]
14 A[k] = L[i]
15 i = i + 1
16 else A[k] = R[j]
17 j = j + 1
*/
template<typename T>
void mergeSort(vector<T>& t, int p, int r)
{
if(p<r)
{
int q = (p+r)/2;
mergeSort(t,p,q);
mergeSort(t,q+1,r);
myMerge(t,p,q,r);
}
}//下标从1开始
template<typename T>
void mergeS(vector<T>& t, int p, int r)
{
p++;
mergeSort(t,p,r);
}//下表从0开始,比较符合C/C++的编程习惯
template<typename T>
void mergeSort(vector<T> &t)
{
mergeSort(t, 1, t.size());
}
template<typename T>
class Print
{
public:
Print(){}
void inline operator()(const T& x) const{cout<<x<<" ";}
};//这就是函数对象,这里并没有带数据,只是一个简单的输出操作。
int main()
{
int a[4]={5,2,90,8};
vector<int> vecI1(a,a+4);
int b[7]={2,10,7,30,9,4,5};
vector<int> vecI2(b,b+7);
mergeSort(vecI2, 1, 7);
for(auto x:vecI2)
{//C++11标准遍历数组,非常方便
cout<<x<<" ";
}
cout<<endl;
mergeS(vecI2, 0, 7);
for(auto x:vecI2)
{
cout<<x<<" ";
}
cout<<endl;
mergeSort(vecI1);
for_each(vecI1.begin(), vecI1.end(), Print<int>());
cout<<endl;
//这里利用stl中的函数实现输出
return 0;
}
总结:
本算法一直都觉得很难理解的,因为递归本来就难理解,而且还拆分那么对次,很难跟踪他的思路的,尤其是严蔚敏等一大批书关于这个算法的程序都按照一个思路来写的,非常糟糕。
Introduction to Algorithm这本书就简化了参数,好理解很多了,传入的数组参数只有一个,非常简明。
还有值得注意的就是下标问题,非常头疼的问题,所以写程序的时候要非常注意。一定要一个一个下标跟踪好,否则很容易下标溢出。
值得思考一下怎么把这个程序的下标进一步规范一下吧。