44
Unit 8— 第第第 第第 6.1 第第第第第第第 6.4 第第第第第第 6.3 第第第第第第第第第 6.5 第第第第第第第第第 第第第 () 6.2 第第第第第第第第

Unit 8— 第 六 章 模板

  • Upload
    cecil

  • View
    104

  • Download
    0

Embed Size (px)

DESCRIPTION

Unit 8— 第 六 章 模板. 6.1 模板与数据结构. 6.4 模板与类参数. 6.5 函数指针与指针识别(选读). 6.2 类模板与排序查找. 6.3 索引查找与指针数组. 例 6.3 顺序表类模板设计. template < typename T, int size> class seqlist { T slist [size]; // 存放顺序表的数 组 int Maxsize ; // 最大可容纳项数 int last; // 已存表项的最后位置 public : - PowerPoint PPT Presentation

Citation preview

Page 1: Unit 8— 第 六 章 模板

Unit 8— 第六章 模板6.1 模板与数据结构 6.4 模板与类参数

6.3 索引查找与指针数组

6.5 函数指针与指针识别(选读) 6.2 类模板与排序查找

Page 2: Unit 8— 第 六 章 模板

class seqlist { int slist[size]; // 存放顺序表的数组, size 需定义为常量 int Maxsize; // 最大可容纳项数 int last; // 已存表项的最后位置public: seqlist(){last=-1;Maxsize=size;} // 初始化为空表 int Length() const{return last+1;} // 计算表长度 int Find(int & x)const; // 寻找 x 在表中位置(下标) bool IsIn(int & x); // 判断 x 是否在表中 bool Insert(int & x,int i); //x 插入到列表中第 i个位置处(下标) bool Remove(int & x); // 删除 X int Next(int & x); // 寻找 X 的后续位置 int Prior(int & x); // 寻找 x 的前驱位置 bool IsEmpty(){return last==-1;} // 判断表是否空 bool IsFull(){return last==Maxsize -1;} // 判断表是否满 int Get(int i){return i<0||i>last?NULL:slist[i];} // 取第 i 个元素之值 int& operator[](int i); }; // 重载下标运算符 []

例 6.3 顺序表类模板设计 template <typename T,int size>class seqlist { T slist[size]; // 存放顺序表的数组 int Maxsize; // 最大可容纳项数 int last; // 已存表项的最后位置public: seqlist(){last=-1;Maxsize=size;} // 初始化为空表 int Length() const{return last+1;} // 计算表长度 int Find(T & x)const; // 寻找 x 在表中位置(下标) bool IsIn(T & x); // 判断 x 是否在表中 bool Insert(T & x,int i); //x 插入到列表中第 i 个位置处(下标) bool Remove(T & x); // 删除 X int Next(T & x); // 寻找 X 的后续位置 int Prior(T & x); // 寻找 x 的前驱位置 bool IsEmpty(){return last==-1;} // 判断表是否空 bool IsFull(){return last==Maxsize -1;} // 判断表是否满 T Get(int i){return i<0||i>last?NULL:slist[i];} // 取第 i 个元素之值 T& operator[](int i); }; // 重载下标运算符 []

Page 3: Unit 8— 第 六 章 模板

template <typename T,int size> int seqlist<T,size>::Find(T & x)const {//const 成员函数,表明对象的数据只能读不能写。 int i=0; while(i<=last && slist[i]!=x) i++; // 顺序查找是否有 x if (i>last) return -1; // 未找到,返回 -1 else return i; // 找到,返回下标}

例 6.3 顺序表类模板设计

template <typename T,int size> bool seqlist<T,size>::IsIn(T & x){ int i=0; bool found=0; while(i<=last && !found) // 换了一种方法来查找 if (slist[i]!=x) i++; else found=1; // 找到 return found;}

Page 4: Unit 8— 第 六 章 模板

template <typename T,int size> T& seqlist<T,size>::operator[](int i){ if(i<0||i>=Maxsize){ cout<<" 下标出界! "<<endl; exit(1); } while(i>last) last++; // 数组最大下标增长到 i return slist[i];}

例 6.3 顺序表类模板设计

assert(!(i<0||i>=Maxsize));

有没有其他方式?

对 P194 作了调整 !

对 P194 作了调整 !

Page 5: Unit 8— 第 六 章 模板

template <typename T,int size> bool seqlist<T,size>:: Insert(T & x, int i) { int j; if (i<0||i>last+1||last==Maxsize -1) return false; // 插入位置不合理,不能插入(健壮性) else{ last++; for(j=last;j>i;j--) slist[j]=slist[j-1]; // 从表最后位置向前依次后移,空出指定位置来 slist[i]=x; return true; }}

例 6.3 顺序表类模板设计

Page 6: Unit 8— 第 六 章 模板

template <typename T,int size>bool seqlist<T,size>::Remove(T & x){ int i=Find(x),j; // 先去找 x 在哪个位置 if(i>=0){ last--; // 预先将 last 前移一位 for(j=i;j<=last;j++) slist[j]=slist[j+1]; // 依次前移,保证表连续 return true; } return false; // 表中不存在 x}

例 6.3 顺序表类模板设计

Page 7: Unit 8— 第 六 章 模板

template <typename T,int size> int seqlist<T,size>::Next(T & x){ int i=Find(x); if(i>=0 && i<last) return i+1; //x 后继位置 else return -1; //x 不在表中,或在表末尾}

template <typename T,int size> int seqlist<T,size>::Prior(T & x){ int i=Find(x); if(i>0 && i<=last) return i-1; //x 前驱的位置 else return -1; }

例 6.3 顺序表类模板设计

Page 8: Unit 8— 第 六 章 模板

int main(){ seqlist <int,100> seqlisti; //seqlisti 的元素为整型 int i,j,k,a[10]={2,3,5,7,11,13,17,19,23,29}; for(j=0;j<10;j++) // 把素数写入 if (!seqlisti.Insert(a[j],j)){ cout<<“ 表太小放不下了 !"<<endl; break; } j=seqlisti.Length(); for(i=0;i<j;i++) cout<<seqlisti.Get(i)<<' '; cout << endl ; // 打印出 seqlisti.slist[]- 素数表 for(j=0;j<10;j++) seqlisti[j]=0; // 采用下标运算符运算 for(j=0;j<10;j++) cout<<seqlisti[j]<<' '; cout<<endl; for(j=0;j<10;j++) seqlisti[j]=a[j];

例 6.3 顺序表类模板设计

Page 9: Unit 8— 第 六 章 模板

seqlisti[10]=31; // 检验能否增加元素,正确!! for(j=0;j<11;j++) cout<<seqlisti[j]<<' '; cout<<endl; k=7; if (seqlisti.IsIn(k)) cout<<"7 在表中 "<< endl; // 因形参为引用,所以实参不可用整数常量 7 else cout <<"7 不在表中 "<<endl; k=17; if (seqlisti.Remove (k)) cout<<" 删除17"<<endl; // 删除 17 else cout<<" 找不到 17 ,无法删除 "; j=seqlisti.Length( ) ; for (i=0;i<j;i++) cout<<seqlisti.Get(i) <<' '; // 打印剩下的素数 cout<<endl;

例 6.3 顺序表类模板设计

Page 10: Unit 8— 第 六 章 模板

if (seqlisti.Insert(k,j-1)){ // 把素数 17 装回去 ,成功则打印 j=seqlisti.Length ( ); for (i=0;i<j;i++) cout<<seqlisti.Get(i) <<' '; cout<<endl; } cout<<" 打印 17 后一个素数 : “

<<seqlisti.Get(seqlisti.Next(k))<<endl; cout<<" 打印 17 前一个素数 :"

<<seqlisti.Get(seqlisti.Prior(k))<<endl; cout<<" 素数 17 在表中位置(下标)为 :"

<<seqlisti.Find(k)<<endl; if(seqlisti.IsEmpty( )) cout<<" 表是空的 "<<endl; else cout<<" 表不空 "<<endl; if (seqlisti.IsFull()) cout<<" 表是满的 "<<endl; else cout<<" 表也不满 "<<endl; if (seqlisti.IsIn(k)) cout<<" 素数 17 在表中 "<<endl; return 0; }

例 6.3 顺序表类模板设计

Page 11: Unit 8— 第 六 章 模板

单链表类模板设计回忆结点类:typedef int DataType;class Node{ DataType info; // 数据域 Node *link; // 指针域public: Node(); // 生成空结点的构造函数 Node(const Datatype &); // 生成一般结点的构造函数 void PrintNode(); // 打印当前结点的信息域 friend class SLList; // 以 SLList 为 Node 友元类,SLList 可直接访问 Node 私有数据,比结构安全};

6.1.2 类模板与数据结构—单链表结点类模板:template <typename DataType> class SLList;template <typename DataType> class Node{ DataType info; // 数据域 Node <DataType> *link; // 指针域public: Node(); // 生成空结点的构造函数 Node(const Datatype &); // 生成一般结点的构造函数 void PrintNode(); // 打印当前结点的信息域 friend class SLList <DataType>; // 以 SLList 为Node 友元类, SLList 可直接访问 Node 私有数据,比结构安全};

infon-1 ^

info1 info0 ……head

tail

Page 12: Unit 8— 第 六 章 模板

Node::Node(){

link=NULL;}

Node::Node(const DataType & data){info=data;link=NULL;

}

void Node::PrintNode(){cout<<info<<endl;

}

6.1.2 类模板与数据结构—单链表template <typename DataType> Node<DataType>::Node(){ link=NULL;}

template <typename DataType> Node<DataType>::Node(const DataType & data){

info=data;link=NULL;

}

template <typename DataType> void Node<DataType>:: PrintNode(){

cout<<info<<endl;}

Page 13: Unit 8— 第 六 章 模板

链表类模板设计 class SLList{ Node *head,*tail; // 链表头指针和尾指针public: SLList (); // 构造函数,生成头结点 ( 空链表 ) ~SLList(); // 析构函数 void MakeEmpty(); // 清空链表,只余表头结点 Node* TravFind(DataType); // 搜索数据域与 data 相同的结点,返回该结点的地址 void PrintSLL(); // 打印链表的数据域 void GrowUP(const DataType &); // 链表向前生长 void GrowDN(const DataType &); // 链表向后生长 void RemoveAft(Node*); // 删除结点后的结点 void RemoveCur(Node*); // 删除指定结点};

6.1.2 类模板与数据结构—单链表template <typename DataType> class SLList{ Node <DataType> *head,*tail; // 链表头指针和尾指针public: SLList (); // 构造函数,生成头结点 ( 空链表 ) ~SLList(); // 析构函数 void MakeEmpty(); // 清空链表,只余表头结点 Node <DataType> * TravFind(DataType); // 搜索数据域与 data 相同的结点,返回该结点的地址 void PrintSLL(); // 打印链表的数据域 void GrowUP(const DataType &); // 链表向前生长 void GrowDN(const DataType &); // 链表向后生长 void RemoveAft(Node <DataType> *); // 删除结点后的结点 void RemoveCur(Node <DataType> *); // 删除指定结点};

Page 14: Unit 8— 第 六 章 模板

链表类模板成员函数:template <typename DataType> SLList<DataType>::SLList(){ head=tail=new Node<DataType> ();}template <typename DataType> SLList<DataType>:: ~SLList(){ MakeEmpty(); delete head; head=NULL;}template <typename DataType> void SLList<DataType>:: MakeEmpty(){ Node<DataType> *p; while(head->link!=NULL) { // 将链表结点从链中脱离 p=head->link; head->link=p->link; delete p; p=NULL; // 删除 ( 释放 ) 脱离下来的结点 } tail=head; // 表头指针与表尾指针均指向表头结点,表示空链}

6.1.2 类模板与数据结构—单链表

Page 15: Unit 8— 第 六 章 模板

template <typename DataType> Node <DataType>* SLList<DataType>:: TravFind(DataType key){ Node<DataType>*p=head->link; while(p!=NULL&&p->info!=key)p=p->link; return p;// 搜索成功返回该结点地址,不成功返回NULL }template <typename DataType> void SLList<DataType>:: PrintSLL() { // 显示链表 Node<DataType>* p=head->link; while(p!=NULL) { cout<<p->info<<'\t'; p=p->link; } cout<<endl;}

6.1.2 类模板与数据结构—单链表

Page 16: Unit 8— 第 六 章 模板

template <typename DataType> void SLList<DataType>:: GrowUP(const DataType& data){

Node<DataType>*p=new Node<DataType> (data);

p->link=head->link;head->link=p; // 新结点始终在头结点之后

}

template <typename DataType> void SLList<DataType>:: GrowDN(const DataType& data){

Node<DataType>* p=new Node<DataType>(data);

tail->link=p;tail=p;tail->link=NULL;

}

6.1.2 类模板与数据结构—单链表

Page 17: Unit 8— 第 六 章 模板

template <typename DataType> void SLList<DataType>:: RemoveAfter(Node<DataType>*p){ Node<DataType>*q; q=p->link; if(q!=NULL){ p->link=q->link; delete q; q=NULL;}}template <typename DataType> void SLList<DataType>:: RemoveCur(Node<DataType>*p){ Node<DataType>*q=head; while(q->link!=NULL && q->link!=p) q=q->link;// 遍历查找 if(q->link==tail) tail=q;// 已经找到末尾 RemoveAfter(q);// 删除 q 后面的结点 p}

6.1.2 类模板与数据结构—单链表

Page 18: Unit 8— 第 六 章 模板

测试:void int main(){

SLList <int>L1; Node<int> n, *tmp;for(int j=0;j<10;j++)

L1.GrowDN(j); // 向后生成链表cout<<" 初始链表 :"; L1.PrintSLL(); // 打印表L1.GrowUP(20);// 向前插入到头结点后cout<<" 插入结点后的链表 :";

L1.PrintSLL(); // 打印tmp=L1.TravFind(20); // 查找插入的结点n=*tmp;cout<<" 找到结点的信息域 :";

n.PrintNode();L1.RemoveCur(tmp);// 删除插入的结点cout<<" 删除结点后的链表 :";

L1.PrintSLL();// 打印return 0;

}

6.1.2 类模板与数据结构—单链表

类到类模板的设计要点:( 1 )将类中潜在可变的数据类型或者常量,替换为模板参数,设计模板头;( 2 )查找类中包含的其他类模板,将类名后加 < 模板参数名表 > ,便于随后的实例化。

Page 19: Unit 8— 第 六 章 模板

a0

an-2

……a1

an-1

bottom

压栈

toptop

toptop

top

退栈

顺序栈类模板设计:6.1.2 类模板与数据结构—栈class Stack{ int top; // 栈顶(下标) DataType *elements; // 指向动态建立的栈 int maxSize; // 栈最大容纳的元素个数public: Stack(const int&size=20); // 构造函数, top= -1 ~Stack(){delete[ ] elements; elements=NULL;} void Push(const DataType &); // 压栈, top++ DataType Pop(); // 弹出, top-- DataType GetElem(int); // 随机取数据, top 不变 void MakeEmpty(){top= -1;} // 清空栈 bool IsEmpty() const{return top== -1;}

// 判栈空 bool IsFull() const{return top==maxSize-1;}

// 判栈满 void PrintStack(); // 输出栈内所有数据};

template <typename DataType, int size> class Stack{ int top; // 栈顶(下标) DataType *elements; // 指向动态建立的栈 int maxSize; // 栈最大容纳的元素个数public: Stack(); // 构造函数 ~Stack(){delete[ ] elements; elements=NULL;} void Push(const DataType &); // 压栈, top++ DataType Pop(); // 弹出, top-- DataType GetElem(int); // 随机取数据, top 不变 void MakeEmpty(){top= -1;} // 清空栈 bool IsEmpty() const{return top== -1;}

// 判栈空 bool IsFull() const{return top==maxSize-1;}

// 判栈满 void PrintStack(); // 输出栈内所有数据};

Page 20: Unit 8— 第 六 章 模板

template <typename DataType , int size > Stack<DataType, size > ::Stack () { maxSize=size; top=-1; elements=new DataType [maxSize]; // 建立栈空间 assert(elements!=NULL); // 假定未悬空,否则分配失败,结束}template <typename DataType , int size > void Stack<DataType,size> :: PrintStack(){ for(int i=0;i<=top;i++) cout<<elements[i]<<'\t'; cout<<endl;}template <typename DataType , int size > void Stack<DataType,size> :: Push(const DataType &data){ assert(!IsFull()); // 栈满则退出程序 elements[++top]=data; // 栈顶下标先加 1 ,元素再进栈}

6.1.2 类模板与数据结构—栈

Page 21: Unit 8— 第 六 章 模板

template <typename DataType , int size > DataType Stack <DataType,size> :: Pop(){ assert(!IsEmpty()); // 栈已空则不能退栈,退出程序 return elements[top--]; // 返回栈顶元素,同时栈顶下标 -1 }

template <typename DataType , int size > DataType Stack <DataType,size> :: GetElem(int i){ assert(i<=top&&i>=0); // 超出栈有效数据区,则退出程序 return elements[i]; // 返回指定元素, top 不变}

6.1.2 类模板与数据结构—栈

Page 22: Unit 8— 第 六 章 模板

测试:int main(){

int i,a[10]={0,1,2,3,4,5,6,7,8,9},b[10];Stack <int, 10>istack();for(i=0;i<10;i++) istack.Push(a[i]); // 压栈if(istack.IsFull()) cout<<" 栈满 "<<endl;istack.PrintStack();for(i=0;i<10;i++) b[i]=istack.Pop();if(istack.IsEmpty()) cout<<" 栈空 "<<endl;for(i=0;i<10;i++) cout<<b[i]<<'\t'; //注意先进后出cout<<endl;istack.Pop(); // 弹出报错return 0;

}

6.1.2 类模板与数据结构—栈

Page 23: Unit 8— 第 六 章 模板

链队类模板设计:Node 和 SLList 类模板设置:template <typename DataType> class SLListQueue; template <typename DataType> class Node { (略)

friend class SLListQueue <DataType>;};

template <typename DataType> class SLList{(略) friend class SLListQueue<DataType>;

};

6.1.2 类模板与数据结构—队列

a0 a1 a2 … an-1…

front rear

head …… ^

……

front

a0 a1 an

reartail

链队实现方式

Page 24: Unit 8— 第 六 章 模板

template <typename DataType> class SLListQueue{ SLList <DataType> LstQue; Node <DataType> *front,*rear;public: SLListQueue(){front=rear=LstQue.head->link;} // 空链队 ~SLListQueue(){} // 析构函数 bool IsEmpty(){ return Length()==0;} //队空否? void EnQue(const DataType &); // 进队 DataType DeQue(); // 出队 DataType GetFront(); // 查看队头数据 void MakeEmpty(); // 置空队列};

6.1.2 类模板与数据结构—队列

Page 25: Unit 8— 第 六 章 模板

template <typename DataType> DataType SLListQueue <DataType> :: DeQue(){ ……}template <typename DataType> DataType SLListQueue <DataType> :: GetFront(){ ……}template <typename DataType> void SLListQueue <DataType> :: MakeEmpty(){ ……}

6.1.2 类模板与数据结构—队列

链队类模板可以继承链表类模板吗?继承的思想不适应类模板设计;各模板独立设计,但可以使用聚合概念!

Page 26: Unit 8— 第 六 章 模板

查找( search ):按关键字( key word ),在有序的数据集合(顺序表,升序或降序)中,寻找满足条件的数据。算法:对半查找(迭代、递归)

6.2 类模板与排序查找

Page 27: Unit 8— 第 六 章 模板

low

8 9 17

13

11

20

7 19

21

23

31

26

29

2 5 37

39

23查找

low mid

high

20

21

29

26

23

31

37

39

mid

highlow20

21

23

mid

high23

low mid high

成功图 6.3 查找成功例

以变量 low 和 high 为数据序列的首尾元素的下标,取mid= (low+ high)/2 ,如mid 位置的元素是所查找的,则结束。如果该元素大了,则取 low=mid +1 , high 不变,继续查找;如果该元素小了,则取 high=mid-1 , low 不变,继续查找。如果查到low>=high仍未找到,则失败,停止。

对半查找 :6.2.1 类模板与查找方法

Page 28: Unit 8— 第 六 章 模板

2 5 7 8 11

13

17

9 19

20

23

21

26

29

31

37

10查找 low

39

mid

high2 5 7 8 1

113

17

9

low mid

high11

13

17

9

low mid

high9

low mid high

图 6.4 查找失败例注意:( 1 )区间收缩过程中, low=mid+1 和high=mid-1非常重要,没有“+1”和“ -1” 时,可能数据存在却找不到。( 2 )对半查找递归算法与迭代算法。

6.2.1 类模板与查找方法

Page 29: Unit 8— 第 六 章 模板

【例 6.4】对半查找递归算法 作为有序表类模板成员函数:template <typename T,int size> int Orderedlist<T,size> :: Binarysearch (const T & x, const int low, const int high){ int mid=-1; if (low<=high) { mid=(low+high)/2; if (slist[mid]<x) mid = Binarysearch(x,mid+1,high);

// 中间点小于 X ,查找右区间,注意mid+1 else if(x<slist[mid]) mid=Binarysearch(x,low,mid-1);

// 中间点大于 X ,查找左区间,注意 mid-1 } return mid;// 找到返回下标 ; 未找到但结束了,返回 -1}

Page 30: Unit 8— 第 六 章 模板

有序表基本元素为类 Element 对象 :class Element{

int key; // 其他域省略public:

bool operator<(Element ele){return key<ele.key;}

void setkey(int k){key=k;}void show(){cout<<key<<'\t';}

}; // 重载了比较运算符 , 元素的比较实际是元素关键字的比较 template <typename T,int size>class Orderedlist{

int maxsize;int last;T slist[size];

public:Orderedlist(){last=-1;maxsize=size;}int Binarysearch(T & x,const int low,const

int high);bool Insert(T & elem,int i);void print(); // 无关成员函数省略

};

Page 31: Unit 8— 第 六 章 模板

【例 6.4】对半查找递归算法template <typename T,int size>bool Orderedlist<T,size>:: Insert(T & elem ,int i){ int j ; if (i<0||i>last+1||last==maxsize-1) return false; //” 前驱后继”

else{ last++;for (j=last;j>i;j--) slist[j]=slist[j-1];slist[i]=elem;return true;}

}template <typename T,int size> void Orderedlist<T,size>:: print(){ int i; for(i=0;i<=last;i++){

slist[i].show();if(i%5==4) cout<<endl;}

cout<<endl;}

Page 32: Unit 8— 第 六 章 模板

【例 6.4】对半查找递归算法int main(){

const int h=19;int i,k=37;Orderedlist<Element,100> ordlist;int

a[h]={67,61,59,53,47,43,41,37,31,29,23, 19,17,13,11,7,5,3,2}; //降序

Element n[h],elem;for(i=0;i<h;i++)

n[i].setkey(a[i]); // 初始化关键字for(i=0;i<h;i++)

ordlist.Insert(n[i],0); // 始终在 0 下标位置插入,建立升序顺序表ordlist.print();elem.setkey(k);

i=ordlist.Binarysearch(elem,0,h-1);cout<<" 整数 "<<k<<" 在表中位置: "<<i<<endl;return 0;}

Page 33: Unit 8— 第 六 章 模板

【例 6.5】对半查找迭代算法template <typename T,int size > int Orderedlist<T,size>:: BinarySearch(const T & x) const{ int high=last, low=0, mid; // last 当前有序表最大下标 if ( last ==- 1 ) return -1; //避免空表出错 while (low<=high ) { mid = (low+high)/2; if ( x<slist[mid] ) high = mid-1; //左缩查找区间 else if ( slist[mid]<x ) low = mid+1; // 右缩查找区间 else return mid; } if ( slist[mid] != x ) mid = -1; // 未找到 return mid;}

Page 34: Unit 8— 第 六 章 模板

6.2.2 常用的排序法排序( sorting ):按照数据元素的可排序数据项(关键字)的大小,排列成升序或降序的数据序列的过程。排序是查找的前提。算法:插入排序(直接、对半);交换排序(冒泡排序);选择排序(直接选择排序)

Page 35: Unit 8— 第 六 章 模板

6.2.2 常用的排序法——直接插入排序 直接插入排序(升序)的思想 :当取得元素 s[i] ( i>0 )时 , 前面的元素s[0],s[1],…, s[i-1] 已经排好序 ,我们将 s[i] 的关键字与 s[i-1], s[i-2],…, 的关键字顺序进行比较 , 找到第一个比它小的 , 则 s[i] 插到该元素之后。i 0 1 2 3 4 5 6 temp初始序列 [8] 6 7 9 4 5 2 61 [6 8] 7 9 4 5 2 72 [6 7 8] 9 4 5 2 93 [6 7 8 9] 4 5 2 44 [4 6 7 8 9] 5 2 55 [4 5 6 7 8 9] 2 26 [2 4 5 6 7 8 9]

Page 36: Unit 8— 第 六 章 模板

【例 6.6】升序直接插入排序算法 作 Orderedlist<T,size> 类成员函数, T 为数组元素类型template<typename T,int size>void Orderedlist<T,size>:: InsertSort(){

T temp;int i,j;for (i=1;i<=last;i++){

temp=slist[i];j=i;while (j>0&&temp<slist[j-1]){

slist[j]=slist[j-1];j--; // 查找与移动同时做

}slist[j]=temp;

}}

Page 37: Unit 8— 第 六 章 模板

有序表类 Orderedlist<T,size> 的基本元素为 Element 类对象, Element 类定义类似( key类型改为 string ),略。void main(){

const int h=10; Element n[h];int i;Orderedlist<Element,100> ordlist;string

mslist[h]={"cat","book","car","zoo","fish","cab","dog","cap","fox","can"};for(i=0;i<h;i++) n[i].setkey(mslist[i]);for(i=0;i<h;i++)

ordlist.Insert(n[i],i); // 建立顺序表cout<<" 未排序表: "<<endl;ordlist.print();ordlist.InsertSort();cout<<" 已排序表: "<<endl;ordlist.print();

}

【例 6.6】升序直接插入排序算法

Page 38: Unit 8— 第 六 章 模板

6.2.2 常用的排序法——交换排序

图 6.6 从下往上冒泡排序

交换排序基本思想: 按关键字两两排序,如果发生逆序则交换之,直到所有的数据都排好为止。49 13 13 13 13 1338 49 27 27 27 2765 38 49 38 38 3897 65 38 49 49 4976 97 65 49’ 49’ 49’13 76 97 65 65 6527 27 76 97 76 7649’ 49’ 49’ 76 97 97

冒泡排序:( 1 )首先从一列数据底部(下标 last )开始,相邻两数据进行比较,小的放上面,一趟下来,最小的数据冒到最上面;( 2 )缩小区域,按同样方法继续下一趟交换;( 3 )如果有一趟比较中没有发生交换,则已排好序。

Page 39: Unit 8— 第 六 章 模板

【例 6.8】冒泡排序算法template <typename T, int size> void Orderedlist<T,size>:: BubbleSort(){ bool noswap; int i, j; T temp; for ( i=0; i<last; i++ ) { // 最多做last趟 noswap=true; //“ 未交换”标志为真

for ( j=last; j>i; j--) { // 从下往上冒泡if ( slist[ j ] < slist[ j-1 ] ) {

temp = slist[ j ];slist[ j ] = slist[ j-1 ];slist[ j-1 ] = temp;noswap = false;

}}if ( noswap ) break; //本趟无交换,则终止算法。

}}

Page 40: Unit 8— 第 六 章 模板

【例 6.8】冒泡排序算法student 类对象为数组的元素

class student{int id; //学号 (主关键字 )int age; //年龄string name; // 姓名char sex; // 性别string address; //家庭地址float eng, phy, math, electron; //英语 ,物理 ,数学和电子成绩

public:student(){}

student(int,string,char,int,string,float,float,float,float);bool operator<(student ele){return id<ele.id;} // 比较符重载void show(){ cout<<id<<'\t'<<name<<'\t'<<sex<<'\t' <<age <<'\t' <<address<<'\t'<<eng<<'\t'<<phy<<'\t'<<math<<'\t'<<electron<<endl;}

};

Page 41: Unit 8— 第 六 章 模板

【例 6.8】冒泡排序算法int main(){

const int h=4; int i;Orderedlist<student,100> ordlist;student n[h]={ student(6004327,"张菲 ",'m',19,"北京路 58号 ",80,85,90,78), student(6004121,"关雨 ",'w',19,"天津路 64号 ",88,75,91,68), student(6004118,"刘蓓 ",'w',18,"上海路 37号 ",78,95,81,88), student(6004219,"赵昀 ",'m',18," 重庆路 95号 ",78,95,81,88)};for(i=0;i<h;i++) ordlist.Insert(n[i],i); // 建立顺序表cout<<" 未排序表: "<<endl;ordlist.print();ordlist.BubbleSort();cout<<" 已排序表: "<<endl;ordlist.print();return 0;

}

Page 42: Unit 8— 第 六 章 模板

6.2.2 常用的排序法——直接选择排序 选择排序( Selection Sort ):每一趟从记录中选出关键字最小的元素,顺序放在已排好序的子序列前面,直到全部记录排序完成。直接选择排序( Straight Selection Sort )是最简单方法。[49 38 65 97 76 13 27 49’] 13 [38 65 97 76 49 27 49’] 13 27 [65 97 76 49 38 49’] 13 27 38 [97 76 49 65 49’] 13 27 38 49 [76 97 65 49’] 13 27 38 49 49’ [97 65 76] 13 27 38 49 49’ 65 [97 76] 13 27 38 49 49’ 65 76 97 图 6.7 直接选择排序的过程

Page 43: Unit 8— 第 六 章 模板

【例 6.9】直接选择排序template<typename T,int size>void Orderedlist<T,size>:: SelectSort(){ int i, j, k; T temp; for(i=0;i<last;i++){

k=i; temp=slist[i];for(j=i+1;j<=last;j++) //课本 j=i 有误 ,多了趟自己比

if(slist[j]<temp) { k=j; temp=slist[j]; }if ( k != i ){ temp=slist[i]; slist[i]=slist[k]; slist[k]=temp;}

}}

Page 44: Unit 8— 第 六 章 模板

Unit 8— 第六章 模板6.1 模板与数据结构 6.4 模板与类参数

6.3 索引查找与指针数组

6.5 函数指针与指针识别(选读) 6.2 类模板与排序查找