本人开辟一个专栏,把严蔚敏 数据结构 这本书上的算法和数据结构用C++实现,网上和她书本光盘也带了C的实现方法,但是其实对于初学者来说真不是那么好自己运行看结构,和自己去修改“玩”的。
本人觉得写程序的能力应该是“玩”出来的,不然会觉得学计算机编程很枯燥的。
所以这里都是给出了完整的C++数据结构或算法程序。
而在C++里面和C其实没有根本的区别,但是我们可以很好的利用C++的一些容器,就可以不用自己求定义一些基本的数据结构了,比如与线性表可以直接用vector。
本专栏也会特意用到了C++11的新特性,用VS2012编译环境。其实这些特性非常好的,建议赶紧学起来。我也尽量解析好这些新特性和一些C++基础吧。
先讲一下本文主要要用到的稍微高级一点而重要的一些C++基础:
1. C++模板:
模板简单的来说就是可以让你定义一个通用的类型,模板的关键字为typename和class,这两个关键字用在模板中基本上是一样的作用。class是旧的关键字,现在都建议用typename,这样是为了避免和类关键字class混淆。
如
template<typename T>
void mergeList(vector<T> &t, vector<T> &t1, vector<T> &t2);
这样你就可以定义你的函数的时候把T当做比如int,double,vector,甚至是你自己定义的类来使用了。模板很多书都把它放到书本的后面介绍了,好像很高级似的,其实用多几次就一点都不神秘。
2.Function Objects 函数对象
(下面内容翻译引用 The C++ Programming Language 这本书的部分内容,部分自己写)
又叫functor;其实就是一个类,不过这种类可以当做函数一样来调用。 也可以说表面上是一个类,不过用法确实像函数一样来使用。
如:
[cpp]
template<typename T>
class Less_than {
const T val; // value to compare against
public:
Less_than(const T& v) :val(v) { }
bool operator()(const T& x) const { return x<val; } // call operator
};
函数调用operator()执行函数调用,调用操作符();
初始化:
[cpp]
Less_than<int> lti {42}; // lti(i) will compare i to 42 using < (i<42)
Less_than<string> lts {"Backus"}; // lts(s) will compare s to "Backus" using < (s<"Backus")
然后我们就可以调用这样的对象,就好像我们调用函数一样:
[cpp]
void fct(int n, const string & s)
{
bool b1 = lti(n); // true if n<42
bool b2 = lts(s); // true if s<"Backus"
// ...
}
如果用好STL就知道其实这样的函数对象是很常用的。
而且大家不要以为这样定义一个类,执行效率会下降,其实恰恰相反,这样的函数对象可以内置(inline),函数对象调用实际上比直接调用函数更加快。而且函数对象可以自带数据,把数据和操作结合起来(正是类的优点),我们不用再去定义更多的变量,这也是它的美丽之处。函数对象自带数据和高效性使得函数对象在作为算法参数的时候特别有用。
下面是合并两序列的算法程序:
[cpp]
/*****
已知两线性表中的数据元素按值非递减排列,归并两线性表到新的线性表,是的数据元素也按值非递减排列
*****/
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
void mergeList(vector<T> &t, vector<T> &t1, vector<T> &t2)
{
auto iter1=t1.begin(), iter2=t2.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++;
}
}
template<class C, class Oper>
void for_all(C &c, Oper op)
{
for(auto x:c) //C++新特性,记住其实就是一种方便循环遍历数据的写法
op(x);
}/*写一个通用的函数,增加其可重用性,配合下面的Print函数就可以打印各种不同的数据到屏幕,非常方便。*/
template<typename T>
class Print
{
public:
Print(){}
void operator()(const T& x) const{cout<<x<<" ";}
};//这就是函数对象,这里并没有带数据,只是一个简单的输出操作。
int main()
{
int a[4]={1,2,5,8};
vector<int> vecI1(a,a+4);
//vecI1={1,2,5,8};这个写法是C++11的新标准,可惜的是VS2012还不支持,只能用就的初始化了
int b[7]={2,4,5,7,9,10,30};
vector<int> vecI2(b,b+7);
vector<int> vecI;
mergeList(vecI, vecI1, vecI2);//不局限是vector<int>类型
for_all(vecI,Print<int>());
cout<<endl;
return 0;
}
总结:
主要的算法函数就是mergeList,本算法并不难,拿本程序,左改改,右改改,就很快可以掌握这个算法了,也可以同时学学C++一举两得。也可以换一换排序的数据类型,其实本程序还支持一般的数组排序。