一.模板:对类或函数的数据类型的抽象,是参数的多态性工具
1.函数模板
定义:
template<模板形参表>
返回值类型 函数名(参数表)
{
函数体
}
模板形参表=引导词+模板参数(类型名)
Ex:
template<template/class T>
T abs(T a)
{
return a<0?-a:a>;
}
使用时需实例化
int main
{
int x=2;
double y=-5:
abs(x);
ans(y);
}
2.类模板
其中的成员函数自动成为函数模板
template<模板形参表>
class 类模板名
{
成员的声明
};
类外函数的定义
template<模板形参表>
返回值类型 类模板名<形参名表>::成员函数名(参数表)
{
成员函数体
}
模板:对类或函数的数据类型的抽象,是参数的多态性工具
1.函数模板
定义:
template<模板形参表>
返回值类型 函数名(参数表)
{
函数体
}
模板形参表=引导词+模板参数(类型名)
Ex:
template<template/class T>
T abs(T a)
{
return a<0?-a:a>;
}
使用时需实例化
int main
{
int x=2;
double y=-5:
abs(x);
ans(y);
}
2.类模板
其中的成员函数自动成为函数模板
template<模板形参表>
class 类模板名
{
成员的声明
};
类外函数的定义
template<模板形参表>
返回值类型 类模板名<形参名表>::成员函数名(参数表)
{
成员函数体
}
二·顺序表的实现
const int Maxsize=100;
template
class SeqList{
private:
T data[MaxSize]; // 存放数据元素的数组
int length; // 线性表的长度
public:
SeqList ( ) ;// 无参构造函数
SeqList ( T a[ ], int n ) ; // 有参构造函数
~SeqList( ) { } // 析构函数为空
int Length ( ) {return length;} // 求线性表的长度
有参构造函数的实现
template
SeqList:: SeqList(T a[], int n)
{
if
(n>MaxSize) throw “参数非法”;
for (int i=0;
i<n; i++)
data[i]=a[i];
length=n;
}
插入算法的实现
template
void SeqList::Insert(int i, T x){
int j;
if
(length>=MaxSize) throw “上溢”;
if (i<1
|| i>length+1) throw “位置”;
for
(j=length; j>=i; j–)
data[j]=data[j-1];
data[i-1]=x;
length++;
}
按值查找
template
int SeqList::Locate(T x){
for (int i=0; i<length; i++)
if (data[i]==x)
return i+1 ; //下标为i的元素等于x,返回其序号i+1
return 0;
//退出循环,说明查找失败
}
顺序表的特点
(1) 可方便地随机存取表中的任一元素。
(2) 插入或删除运算不方便,
除表尾的位置外,在表的其它位置上进行插入或删除操作都必须移动大量的结点,其效率较低;
(3) 由于顺序表要求占用连续的存储空间,存储分配只能预先进行静态分配,因此当表长变化较大时,难以确定合适的存储规模。
三.单链表
1·链表结点数据类型的定义(结点类)
在C++中,可以用结构类型来描述单链表的结点 ,由于结点的元素类型不确定,所以采用C++的模板机制。
template
struct Node
{
T data;
Node
*next; //此处也可以省略
}
2·带头节点的单链表
头结点:如果链表有头节点,则链式结构中的第一个节点称为头结点:其数据域可以存储一些附加信息,如链表长度;其指针域指向链表中的第一个节点。
单链表的实现(重点)
template
class LinkList {
public:
LinkList ( ) {first=new Node; first -> next=
NULL ;}
LinkList ( T a[
], int n ) ;
~LinkList ( ) ;
int Length ( ) ;
T Get ( int i ) ;
int Locate ( T x ) ;
void Insert ( int i, T x ) ;
T Delete ( int i ) ;
void PrintList ( ) ;
private:
Node *first; // 单链表的头指针 , 可以省略
};
单链表的构造-头插法(先修改远端)
template
LinkList:: LinkList(T a[ ], int n) {
first=new
Node; //生成头结点
first->next=NULL;
Node
*s;
for (int i=0;
i<n; i++){
s=new
Node;
s->data=a[i]; //为每个数组元素建立一个结点
s->next=first->next;
first->next=s;
}
}
单链表的构造-尾插法
template
LinkList:: LinkList(T a[ ], int n) {
Node *r,*s; //尾指针
first=new
Node; //生成头结点
r=first;
for (int
i=0; i<n; i++) {
s=new
Node;
s->data=a[i]; //为每个数组元素建立一个结点
r->next=s; r=s; //插入到终端结点之后
}
r->next=NULL; //单链表建立完毕,将终端结点的指针域置空
}
单链表的遍历
template
LinkList:: PrintList()
{
Node *p;
p=first->next;
while§
{
cout<data;
p=p->next;
}
}
单链表中按位置查找
template
T LinkList::Get(int i) {
Node *p; int j;
p=first->next; j=1;
//或p=first; j=0;
while (p && j<i) {
p=p->next; //工作指针p后移
j++;
}
if (!p) throw “位置”;
else return p->data;
}
单链表的插入操作(按位置进行插入)
1 工作指针p初始化,计数器初始化
2 查找第i-1个节点,并使工作指针p指向该节点
3 若查找不成功(P==NULL),说明位置错误,抛出位置异常,否则
3.1 生成一个元素值为x的新节点s
3.2 将s插入到p之后
template
void LinkList::Insert(int i, T x){
Node
*p; int j;
p=first ;
j=0; //工作指针p初始化
while (p
&& j<i-1) {
p=p->next; //工作指针p后移
j++;
}
if (!p) throw
“位置”;
else {
Node *s;
s=new
Node;
s->data=x;
//向内存申请一个结点s,其数据域为x
s->next=p->next; //将结点s插入到结点p之后
p->next=s;
}
}
单链表中节点的删除(删除编号是i的结点)
template
T LinkList::Delete(int i){
Node
*p; int j;
p=first ;
j=0; //工作指针p初始化
while (p
&& j<i-1) { //查找第i-1个结点
p=p->next;
j++;
}
if (!p ||
!p->next) throw “位置”; //结点p不存在或结点p的后继结点不存在
else {
Node *q; T x;
q=p->next; x=q->data; //暂存被删结点
p->next=q->next; //摘链
delete
q;
return x;
}
}
析构函数
template
LinkList:: ~LinkList()
{
Node
*q;
while (first)
{
q=first->next;
delete
first;
first=q;
}
}
三·循环链表
将单链表或者双链表的头尾结点链接起来,就是一个循环链表。
首尾相接的链表。
可以从任一节点出发,访问链表中的所有节点。
判断循环链表中尾结点的特点:
q->next==first
循环链表的定义:
template
class CycleLinkList{
public:
CycleLinkList( );
CycleLinkList(T a[ ], int n);
CycleLinkList(T a[ ], int n,int i);
~CycleLinkList();
int Length();
T Get(int
i);
void
Insert(int i, T x);
T Delete(int
i);
void
PrintList( );
private:
Node
*first;
};
空表的构造
template
CycleLinkList:: CycleLinkList( )
{
first=new Node; first->next=first;
}
尾插法构造循环链表
template
CycleLinkList:: CycleLinkList(T a[ ], int n)
{
first=new
Node; //生成头结点
Node
*r,*s;
r=first; //尾指针初始化
for (int
i=0; i<n; i++) {
s=new Node;
s->data=a[i];
r->next=s;
r=s;
}
r->next=first; //单链表建立完毕,将终端结点的指针域指向头结点
}
头插法构造循环链表
template
CycleLinkList:: CycleLinkList(T a[ ], int
n,int k)
{
first=new
Node; //生成头结点
first->next=first;
Node
*s;
for (int i=1;
i<n; i++)
{
s=new
Node;
s->data=a[i]; //为每个数组元素建立一个结点
s->next=first->next;
first->next=s;
}
}
将非循环的单链表改造成循环的单链表
p=first;
while(p->next)
{
p=p->next;
}
p->next=first
双链表
增加一个指向前驱的指针
template
struct DNode{
T data;
DNode
*llink;
DNode *rlink;
};
双链表的结构特点
由于在双向链表中既有前向链又有后向链,寻找任一个结点的直接前驱结点与直接后继结点变得非常方便。设指针p指向双链表中某一结点,则有下式成立:
p->llink->rlink = p = p->rlink->llink ;
双向链表的实现
template
class DoubleLink {
private:
Node
*head;
public:
DoubleLink() ;
~DoubleLink();
void Append(T
data);
void
Display();
void
Insert(int locate , T data);
T Get(int locate);
T Delete(int locate);
};
双向链表的构造-空表的构造
template
DoubleLink ::DoubleLink(){
head=new
Node;
head->rlink=NULL;
head->llink=NULL;
}
追加(头插):Append(T data)
template
void DoubleLink::Append(T data){
Node *s;
s=new Node;
s->data=data;
s->rlink=head->rlink;
head->rlink=s;
s->llink=head;
if
(s->rlink)
s->rlink->llink=s;
return;
}
遍历
template
void DoubleLink::Display(){
Node
*p;
p=head->rlink;
while§ {
cout<data<<" ";
p=p->rlink;
}
cout<<endl;
return;
}
析构
template
DoubleLink::~DoubleLink(){
Node *p,*q;
p=head;
while§
{
q=p->rlink;
delete
p;
p=q;
}
}