《数据结构与算法描述:c++实现》第一章
1.3 递归的简单介绍
编写递归例程的时候,牢记四条基本法则
- 基准情形:必须总有某些基准情形不用递归就能求解
- 不断推进:对于那些需要递归求解的,递归调用必须总能够朝着基准情形的方向推进。
- 设计法则:所有的递归调用都能运行
- 合成效益法则:在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性的工作。
1.4 c++类
1.4.2 特别的构造函数语法与访问函数
先举一个例子
图1.6
/* A class for simulating an integer memory cell*/
class IntCell
{
public:
explicit IntCell( int initialValue = 0 ): storedValue(initialValue){ }
int read() const { return storedValue;}
void write(int x){ storedValue = x;}
private:
int storedValue;
};
explicit函数
所有单参数的构造函数必须是explicit的,避免后台的类型转换,否则c++一些宽松的规则允许在没有显示转换操作的情况写进行类型转换。
常量成员参数
访问函数:进行检测但不改变其对象状态的成员函数
修改函数:改变其对象状态的成员函数。
在默认情况下,所有的成员函数都是修改函数,成员函数称为访问函数必须在参数类型列表结尾的圆括号后加上关键字const。
在上面的代码中,read函数明显是一个访问函数。
1.4.3 接口与实现的分离
下面给出类IntCell的接口与实现
类的接口,不具体写实现方法,只进行类的声明和定义
图1.7
/* 类的接口*/
#ifndef IntCell_H
#define IntCell_H
class IntCell
{
public:
explicit IntCell( int initialValue = 0 );
int read() const ;
void write(int x);
private:
int storedValue;
};
#endif
类的实现,具体方法如何操作
图1.8
/* 类的实现 */
#include "IntCell.h"
IntCell::IneCell(int initialValue):storedValue(initialValue )
{
}
int IneCell::read() const
{
return storedValue;
}
void IneCell::write(int x)
{
storedValue = x;
}
1.4.4 vector和string
c++标准定义了两个类,vector替代带来无穷麻烦的c++内置数组,例如,内置数组不能使用=复制,也不能记忆其本身能存储多少项,并且索引操作不能检查索引是否有效。
vector和string都可以用=进行复制,并且容易使用,以下代码创建了一个存储100个平方值并且将这些数据输出的vector。
图1.10
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> squares(100);
for(int i = 0; i< squares.size();i++)
squares[i]=i * i;
for(int i = 0; i< squares.size();i++)
cout<< i << " "<<squares[i]<<endl;
//其实这两个可以合并,书上例子没有合并
return 0;
}
1.5 c++细节
1.5.2 参数传递
下面的函数声明阐述了三种参数传递的机制,该函数返回arr中前n个整数的平均值,并且如果n大于arr.size()或者小于1,就设定errorFlag为true
double avg(const vector<int> & arr, int n, bool & errorFlag);
这里,arr是vector类型,使用按常量引用调用(call by constant reference),n是按值调用,errorFlag是引址调用。参数传递机制可以通过以下两步判断决定
- 形参必须能够改变实参的值,使用引址调用
- 实参的值不能被形参改变,如果参数类型简单,使用按值调用,否则,就按常量引用调用。
1.6 模板
1.6.1 函数模板
不是真正的函数,而是一个用来产生函数的公式。例如图1.17代码
template <typename Comparable>
const Comparable & findMax (const vector<Comparable> & a)
{
int maxIndex = 0;
for(int i = 1;i < a.size(); i++)
{
if(a[maxIndex] < a[i])
maxIndex = i;
}
return a[maxIndex];
}
使用模板代码图1.18
图1.18
#include <string.h>
int main()
{
vector<int> v1(37);
vector<double> v2(40);
vector<string> v3(80);
vector<IntCell> v4(75);
//添加元素在vector数组中,这里省略
cout<< findMax(v1)<<endl; //OK: Comparable = int
cout<< findMax(v2)<<endl; //OK: Comparable = double
cout<< findMax(v3)<<endl; //OK: Comparable = string
cout<< findMax(v4)<<endl; //error! operator< undefined
return 0;
}
1.6.2 类模板
图1.19代码展示了MemoryCell类模板
图1.19
template <typename Object>
class MemoryCell
{
public:
explicit MemoryCell( const Object & initialValue = Object() ): storedValue(initialValue){ }
const Object & read() const { return storedValue;}
void write(const Object & x){ storedValue = x;}
private:
Object storedValue;
};
要注意的是,Object是通过常量引用来传递的,默认参数不是0,因为0有可能不是有效的Object。图1.20给出了MemoryCell怎么存储基本类型和类类型的例子,注意,MemoryCell不是类,仅仅是类模板。
图1.20
int main()
{
MemoryCell<int> m1;
MemoryCell<string> m2("hello");
m1.write(37);
m2.write(m2.read() + "world");
cout<< m1.read()<<endl<<m2.read() <<endl;
return 0 ;
}
1.7 使用矩阵
c++没有提供matrix类,可以通过使用向量的向量的思想实现,附加操作符重载的知识,对matrix定义operator[],即数组索引操作符。图1.24例举了matrix类。
图1.24
#ifndef MATRIX_H_
#define MATRIX_H_
#include <vector>
using namespace std;
template<typename Object>
class matrix
{
public:
matrix( int rows, int coles): array(rows)
{
for(int i = 0 ; i < rows; i++)
array[i].resize(cols);
}
const vector<Object> & operator[](int row) const
{ return array[ row]; }
vector<Object> & operator[]( int row )
{ return array[ row]; }
int numrows() const
{ return array.size(); }
int numcols() const
{ return numrows() ? array[0].size(): 0 ; }
private:
vector<vector<Object>> array;
};
#endif