函数模版:
v 函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计。
v 定义方法:
n template <模板参数表>
函数定义
v 模板参数表的内容
n 类型参数:class(或typename) 标识符
n 常量参数:类型说明符 标识符
求绝对值函数的模板:
template<typename T>
T abs(T x) {
return x < 0? -x : x;
}
求绝对值函数的模板分析:
v 编译器从调用abs()时实参的类型,推导出函数模板的类型参数。例如,对于调用表达式abs(n),若实参n为int型,所以推导出模板中类型参数T为int。
v 当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数:
int abs(int x) {
return x < 0 ? –x : x;
}
类模板的作用:
使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值,能取任意类型(包括基本类型的和用户自定义类型)。
类模板的声明:
v 类模板:
template <模板参数表>
class 类名
{类成员声明}
v 如果需要在类模板以外定义其成员函数,则要采用以下的形式:
n template <模板参数表>
n 类型名 类名<模板参数标识符列表>::函数名(参数表)
Ø 群体数据:
v 线性群体
n 线性群体的概念
n 直接访问群体--数组类
n 顺序访问群体--链表类
n 栈类
n 队列类
群体的概念:
v 群体是指由多个数据元素组成的集合体。群体可以分为两个大类:线性群体和非线性群体。
v 线性群体中的元素按位置排列有序,可以区分为第一个元素、第二个元素等。
v 非线性群体不用位置顺序来标识元素。
v 线性群体中的元素次序与其位置关系是对应的。在线性群体中,又可按照访问元素的不同方法分为直接访问、顺序访问和索引访问。
数组:
v 静态数组是具有固定元素个数的群体,其中的元素可以通过下标直接访问。
n 缺点:大小在编译时就已经确定,在运行时无法修改。
v 动态数组由一系列位置连续的,任意数量相同类型的元素组成。
n 优点:其元素个数可在程序运行时改变。
v vector就是用类模板实现的动态数组。
数组类模板的构造函数:
// 构造函数
template <class T>
Array<T>::Array(int sz) {
//sz为数组大小(元素个数),应当非负,其作用是如果它的条件返回错误,则终止程序执行
assert(sz >= 0);
// 将元素个数赋值给变量size
size = sz;
//动态分配size个T类型的元素空间
list = new T [size];
}
数组类模板的拷贝构造函数:
//拷贝构造函数
template <class T>
Array<T>::Array(const Array<T> &a) {
//从对象x取得数组大小,并赋值给当前对象的成员
size = a.size;
//为对象申请内存并进行出错检查
list = new T[size];// 动态分配n个T类型的元素空间
//从对象X复制数组元素到本对象
for (int i = 0; i < size; i++)
list[i] = a.list[i];
}
数组类模板的重载"="运算符函数
//重载“=”运算符
template <class T>
Array<T> &Array<T>::operator = (const Array<T>& rhs) {
if (&rhs != this) {
if (size != rhs.size) {
delete [] list; //删除数组原有内存
size = rhs.size; //设置本对象的数组大小
list = new T[size]; //重新分配n个元素的内存
}
//从对象X复制数组元素到本对象
for (int i = 0; i < size; i++)
list[i] = rhs.list[i];
}
return *this; //返回当前对象的引用
}
数组类模板的重载下标操作符函数
template <class T>
T &Array<T>::operator[] (int n) {
assert(n >= 0 && n < size);//越界检查
return list[n]; //返回下标为n的数组元素
}
template <class T>
const T &Array<T>::operator[] (int n) const {
assert(n >= 0 && n < size); //越界检查
return list[n]; //返回下标为n的数组元素
}
为什么有的函数返回引用:
v 如果一个函数的返回值是一个对象的值,就不应成为左值。(+ -的重载)
v 如果返回值为引用。由于引。([]的重载,前置++和后置++用是对象的别名,通过引用当然可以改变对象的值)
v
链表:
v 链表是一种动态数据结构,可以用来表示顺序访问的线性群体。
v 链表是由系列结点组成的,结点可以在运行时动态生成。
v 每一个结点包括数据域和指向链表中下一个结点的指针(即下一个结点的地址)。如果链表每个结点中只有一个指向后继结点的指针,则该链表称为单链表。
单链表的结点类模板:
template<class T>
class Node {
private:
Node *next;
public:
T data;
Node(const T& item,Node* next = 0);
void insertAfter(Node *p);
Node *deleteAfter();
Node *nextNode() const;
};
链表的基本操作:
v 生成结点
v 插入结点
v 查找结点
v 删除结点
v 遍历链表
v 清空链表
特殊的线性群体——栈:
栈是只能从一端访问的线性群体,可以访问的这一端称栈顶,另一端称栈底。(先进后出)
特殊的线性群体——队列:
队列是只能向一端添加元素,从另一端删除元素的线性群体(先进先出)
会在后面的STL中详细介绍。
循环队列:
在想象中将数组弯曲成环形,元素出队时,后继元素不移动,每当队尾达到数组最后一个元素时,便 再回到数组开头。
Ø 群体数据的组织:
v 插入排序
v 选择排序
v 交换排序
v 顺序查找
v 折半查找
排序(sorting)
v 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列。
n 数据元素:数据的基本单位。在计算机中通常作为一个整体进行考虑。一个数据元素可由若干数据项组成。
n 关键字:数据元素中某个数据项的值,用它可以标识(识别)一个数据元素。
v 在排序过程中需要完成两种基本操作:
n 比较两个数的大小
n 调整元素在序列中的位置
内部排序与外部排序:
v 内部排序:待排序的数据元素存放在计算机内存中进行的排序过程。
v 外部排序:待排序的数据元素数量很大,以致内存存中一次不能容纳全部数据,在排序过程中尚需对外存进行访问的排序过程。
内部排序方法:
v 插入排序
每一步将一个待排序元素按其关键字值的大小插入到已排序序列的适当位置上,直到待排序元素插入 完为止。
v 选择排序
每次从待排序序列中选择一个关键字最小的元素,(当需要按关键字升序排列时),顺序排在已排序序 列的最后,直至全部排完。
v 交换排序
两两比较待排序序列中的元素,并交换不满足顺序要求的各对元素,直到全部满足顺序要求为止。
最简单的交换排序方法
——起泡排序
v 对具有n个元素的序列按升序进行起泡排序的步骤:
n 首先将第一个元素与第二个元素进行比较,若为逆序,则将两元素交换。然后比较第二、第三个元素,依次类推,直到第n-1和第n个元素进行了比较和交换。此过程称为第一趟起泡排序。经过第一趟,最大的元素便被交换到第n个位置。
n 对前n-1个元素进行第二趟起泡排序,将其中最大元素交换到第n-1个位置。
n 如此继续,直到某一趟排序未发生任何交换时,排序完毕。对n个元素的序列,起泡排序最多需要进行n-1趟。
起泡排序函数模板:
template <class T>
void mySwap(T &x, T &y) {
T temp = x;
x = y;
y = temp;
}
template <class T>
void bubbleSort(T a[], int n) {
int i = n – 1;
while (i > 0) {
int lastExchangeIndex = 0;
for (int j = 0; j < i; j++)
if (a[j + 1] < a[j]) {
mySwap(a[j], a[j + 1]);
lastExchangeIndex = j;
}
i = lastExchangeIndex;
}
}
v 顺序查找:
n 其基本思想
n 从序列的首元素开始,逐个元素与待查找的关键字进行比较,直到找到相等的。若整个序列中没有与待查找关键字相等的元素,就是查找不成功。
v 顺序查找函数模板:
template <class T>
int seqSearch(const T list[], int n, const T &key) {
for(int i = 0; i < n; i++)
if (list[i] == key)
return i;
return -1;
}
折半查找的基本思想:
对于已按关键字排序的序列,经过一次比较,可将序列分割成两部分,然后只在有可能包含待查元素的一部分中继续查找,并根据试探结果继续分割,逐步缩小查找范围,直至找到或找不到为止。
折半查找函数模板:
template <class T>
int binSearch(const T list[], int n, const T &key) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (key == list[mid])
return mid;
else if (key < list[mid])
high = mid – 1;
else
low = mid + 1;
}
return -1;
}