严蔚敏C++讲稿.docx
- 文档编号:6813103
- 上传时间:2023-01-10
- 格式:DOCX
- 页数:36
- 大小:29.01KB
严蔚敏C++讲稿.docx
《严蔚敏C++讲稿.docx》由会员分享,可在线阅读,更多相关《严蔚敏C++讲稿.docx(36页珍藏版)》请在冰豆网上搜索。
严蔚敏C++讲稿
第二章线性表
线性结构是一个数据元素的有序(次序)集
线性结构的基本特征:
1.集合中必存在唯一的一个“第一元素”;
2.集合中必存在唯一的一个“最后元素”;
3.除最后元素在外,均有唯一的后继;
4.除第一元素之外,均有唯一的前驱。
2.1线性表的类型定义
抽象数据类型线性表的定义如下:
ADTList{
数据对象:
D={ai|ai∈ElemSet,i=1,2,...,n,
n≥0}
数据关系:
R1={
i=2,...,n}
基本操作:
{初始化}
InitList(&L)
操作结果:
构造一个空的线性表L。
{结构销毁}
DestroyList(&L)
初始条件:
线性表L已存在。
操作结果:
销毁线性表L。
{引用型操作}
ListEmpty(L)
初始条件:
线性表L已存在。
操作结果:
若L为空表,则返回TRUE,
否则FALSE。
ListLength(L)
初始条件:
线性表L已存在。
操作结果:
返回L中元素个数。
GetElem(L,i,&e)
初始条件:
线性表L已存在,
1≤i≤LengthList(L)
操作结果:
用e返回L中第i个元素的值。
LocateElem(L,e,compare())
初始条件:
线性表L已存在,compare()
是元素判定函数。
操作结果:
返回L中第1个与e满足关系
compare()的元素的位序。
若这样的元
素不存在,则返回值为0。
PriorElem(L,cur_e,&pre_e)
初始条件:
线性表L已存在。
操作结果:
若cur_e是L的元素,但不是
第一个,则用pre_e返回它的前驱,
否则操作失败,pre_e无定义。
NextElem(L,cur_e,&next_e)
初始条件:
线性表L已存在。
操作结果:
若cur_e是L的元素,但不是
最后一个,则用next_e返回它的后继,
否则操作失败,next_e无定义。
ListTraverse(L,visit())
初始条件:
线性表L已存在。
操作结果:
依次对L的每个元素调用函数
visit()。
一旦visit()失败,则操作失败。
{加工型操作}
ClearList(&L)
初始条件:
线性表L已存在。
操作结果:
将L重置为空表。
PutElem(L,i,&e)
初始条件:
线性表L已存在,
1≤i≤LengthList(L)
操作结果:
L中第i个元素赋值同e的值。
ListInsert(&L,i,e)
初始条件:
线性表L已存在,
1≤i≤LengthList(L)+1
操作结果:
在L的第i个元素之前插入新
的元素e,L的长度增1。
ListDelete(&L,i,&e)
初始条件:
线性表L已存在且非空,
1≤i≤LengthList(L)
操作结果:
删除L的第i个元素,并用e
返回其值,L的长度减1。
}ADTList
例2-1假设利用两个线性表LA和LB分别表示两个集合A和B(即:
线性表中的数据元素即为集合中的成员),现要求一个新的集合A=A∪B。
上述问题等价于:
要求对线性表作如下操作:
扩大线性表LA,将存在于线性表LB中而不存在于线性表LA中的数据元素插入到线性表LA中去。
分下列三步进行:
1.从线性表LB中依次取得每个数据元素;
2.依值在线性表LA中进行查访;
3.若不存在,则插入之。
用C语言描述得如下算法:
voidunion(List&La,ListLb){
//将所有在线性表Lb中但不在La中的
//数据元素插入到La中
La_len=ListLength(La);
Lb_len=ListLength(Lb);//求线性表的长度
for(i=1;i<=Lb_len;i++){
GetElem(Lb,i,e);
//取Lb中第i个数据元素赋给e
if(!
LocateElem(La,e,equal))
ListInsert(La,++La_len,e);
//La中不存在和e相同的数据元素,
//则插入之
}
}//union
算法2.1
例2-2已知一个非纯集合B,试构造集合A,要求集合A中只包含集合B中所有值不相同的数据元素。
解法一:
同上例,分别以线性表LA和LB表示集合A和B,则首先初始化线性表LA为空表,之后的操作和例2-1完全相同。
解法二:
仍以线性表表示集合。
只是求解之前先对线性表LB中的数据元素进行排序,即线性表LB中的数据元素依其值从小到大有序排列,则值相同的数据元素必相邻。
则上述操作中的第二步就不需要进行从头至尾的查询。
用C语言描述得如下算法:
voidpurge(List&La,ListLb){
//已知线性表Lb中的数据元素依值非递减有序排列,现构造线性表La,
//使La中只包含Lb中所有值不相同的数据元素
InitList(La);//初始化La为空表
La_len=ListLength(La);
Lb_len=ListLength(Lb);//求线性表的长度
for(i=1;i<=Lb_len;i++){
GetElem(Lb,i,e);
//取Lb中第i个数据元素赋给e
if(ListEmpty(La)||!
equal(en,e))
ListInsert(La,++La_len,e);
//La中不存在和e相同的数据元素,
//则插入之
en=e;
}//for
}//purge
算法2.2
例2-3归并两个“其数据元素按值非递减有序排列的”线性表LA和LB,求得线性表LC也具有同样特性
voidMergeList(ListLa,ListLb,List&Lc){
//已知线性表La和Lb中的元素按值非递
//减排列。
归并La和Lb得到新的线性表
//Lc,Lc的元素也按值非递减排列。
InitList(Lc);
i=j=1;k=0;
La_len=ListLength(La);
Lb_len=ListLength(Lb);
while((i<=La_len)&&(j<=Lb_len)){
//La和Lb均非空
GetElem(La,i,ai);GetElem(Lb,j,bj);
if(ai<=bj){
ListInsert(Lc,++k,ai);++i;}
else{ListInsert(Lc,++k,bj);++j;}
}
while(i<=La_len){
GetElem(La,i++,ai);
ListInsert(Lc,++k,ai);
}
while(j<=Lb_len){
GetElem(Lb,j++,bj);
ListInsert(Lc,++k,bj);
}
}//merge_list
算法2.3
假设:
GetElem和ListInsert这两个操作的执行时间和表长无关,
LocateElem的执行时间和表长成正比,
则
算法2.1的时间复杂度为
O(ListLength(LA)×ListLength(LB));
例2-2(解法一)的时间复杂度为
O(ListLength2(LB));
算法2.2的时间复杂度为
O(ListLength(LB));
可见,不同的算法策略所得不同算法的时间复杂度不同。
算法2.3的时间复杂度为
O(ListLength(LA)+ListLength(LB))
2.2线性表类型的实现顺序映象
用一组地址连续的存储单元依次存放线性表中的数据元素,即以地址相邻表示数据元素之间的次序关系。
LOC(ai)=LOC(ai-1)+l(l为一个数据元素所占存储量)
线性表中任意一个数据元素的存储位置都可以线性表中第一个数据元素a1的存储地址来表示,
LOC(ai)=LOC(a1)+(i-1)l
称第一个数据元素的存储地址为线性表的起始地址,称作线性表的基地址
在C++语言中,可借用一维数组类型来描述这种结构
classSqList
{
private
constMAXLISTSIZE=100
protected
ElemType*elemPtr;
intcursize;
public
//constructor
SqList(intsize=MAXLISTSIZE);
//destructor
~SqList()
{delete[]elemPtr;}
//accessmethod
intEmpty(void)const;
{return(cursize==0)}
intLength(void)const;
{returncursize}
ElemType*getElem(intpos);
//若1<=pos<=cursize,则返回指示第pos个元素的位置;否则返回NULL
intLocation(ElemType&e);
//返回其值和e所指元素值相同的数据元素在线性表中的序号,
//若不存在这样的数据元素,则返回0
//modification
voidclearList(void);
StatusputElem(intpos,constElemType&e);
//若1<=pos<=cursize,则修改线性表中第pos个数据元素的值,
//并且返回OK;否则不进行修改并返回ERROR
StatusInsert(intpos,constElemType&e);
//若1<=pos<=cursize+1,则插入元素e在线性表中第pos个数据元素之前,
//并且返回OK;否则不进行插入并返回ERROR
Status*Delete(intpos,ElemType&e);
//若1<=pos<=cursize,则删除并返回指示第pos个数据元素的位置,
//否则返回NULL
}
SqList:
:
SqList(intsize){
//构造一个空的顺序表
size=(size>MAXLISTSIZE)?
MAXLISTSIZE:
size;
elemPtr=newElemType[size];
cursize=0;
}
ElemType*SqList:
:
getElem(intpos){
//返回顺序表中第pos个数据元素,
//pos的合法值为1≤pos≤cursize
if((pos<1)||(pos>cursize))return(NULL);
elsereturn&(elemPtr[pos-1])
}
intSqList:
:
Location(constElemType&e){
//返回顺序表中其值和e相等的元素的位序,
//若不存在这样的数据元素,则返回0
ElemType*p;
intk=1;
p=elemPtr;
while(k<=cursize&&(compare(*p++,e)))k++;
if(k<=cursize)returnk;
elsereturn0;
}//Location
StatusSqList:
:
Insert(intpos,ElemTypee){
//在顺序线性表SqList的第pos个元素之前插入新的元素e,
//pos的合法值为1≤pos≤cursize
if(pos<1||pos>cursize+1)
returnERROR;//插入位置pos值不合法
if(cursize>=MAXLISTSIZE)
exit(OVERFLOW);//表已满
q=&(elemPtr[pos-1]);//q为插入位置
for(p=&(elemPtr[L.length-1]);p>=q;--p)
*(p+1)=*p;
//插入位置及之后的元素右移
*q=e;//插入e
++cursize;//表长增1
returnOK;
}//Insert
ElemType*SqList:
:
Delete(intpos,ElemType&e){
//在顺序线性表L中删除第pos个元素,并用e返回其值。
//pos的合法值为1≤pos≤Length
if((pos<1)||(pos>cursize))
returnNULL;//删除位置pos值不合法
p=&(L.elem[pos-1]);
//p指示被删除元素的位置
e=*p;
//被删除元素的值赋给e
q=elem+cursize-1;
//q指示表尾元素的位置
for(++p;p<=q;++p)*(p-1)=*p;
//被删元素之后的元素左移
--cursize;
//表长减1
return&e;
}//Delete
利用顺序表类实现线性表的其它操作
#include
#includeSqList.h
SqListmerge(Sqlist&a,SqList&b){
ElemType*ai,*bj;
intm=a.Length();
intn=b.Length();
SqListc(m+n);
inti=1;
intj=1;
intk=c.Length();//k=0
while((i<=m)&&(j<=n)){
ai=a.getElem(i);
bj=b.getElem(j);
switch(compare(*ai,*bj)){
case–1:
case0:
c.Insert(++k,ai);
i++;
break;
case1:
c.Insert(++k,bj);
j++;
break;
default:
;
}//switch
}//while
while(i<=m){
ai=a.getElem(i++);
c.Insert(++k,ai);
}
while(j<=n){
bj=b.getElem(j++);
c.Insert(++k,bj);
}
returnc;
}//merge
2.3线性表类型的实现链式映象
一、单链表
用一组地址任意的存储单元存放线性表中的数据元素
以元素(数据元素的映象)+(指示后继元素存储位置的)指针=结点(表示数据元素)
线性表~结点的序列称作链表
以线性表中第一个数据元素a1的存储地址作为线性表的地址,为线性表的头指针
二、结点类的定义
classNode{
protected:
ElemTypedata;//数据域
Node*next;//指针域
public:
//constructor
Node(constElemTypeitem,
Node*ptr=NULL);
//destructor
~Node(void){}
//accessmethod
Node*nextNode(void)const;
{returnnext}//返回结点的后继
ElemType*info(void)const;
{returndata}//返回结点数据域的值
//modificationmethod
voidinsertAfter(Node*p);
//插入后继结点
Node*deleteAfter(void);
//删除并返回后继结点
};
//Node类的实现
Node:
:
Node(constElemTypeitem,
Node*ptr=NULL){
data=item;
next=ptr;
}
voidNode:
:
insertAfter(Node*p){
//插入后继结点
p>next=next;
next=p;
}
Node*Node:
:
deleteAfter(void){
//删除并返回后继结点
Node*s=next;
next=s>next;
returns;
}
三、单链表操作的实现
Node*getElem(Node*head,intpos){
//返回指向以head为头指针的链表中第pos个
//数据元素的指针,若不存在,则返回NULL
if(!
head||pos<1)returnNULL;
j=1;p=head;
while(p&&j p=p->nextNode;j++; } returnp; } StatusListInsert(Nodehead,intpos,ElemTypee){ //在以head为头指针的链表中第pos //个数据元素之前插入数据元素e pre=getElem(head,pos-1);//求得插入位置的前驱 if(! pre&&pos<>1)returnERROR; else{ if(pos=1) {head=newNode(e,head);}//插入在第一个元素之前 else{ p=pre>nextNode(); s=newNode(e,p); pre>insertAfter(s);//插入在前驱结点之后 } returnOK; } } Node*ListDelete(Node*head,intpos){ //返回并删除以head为头指针的链表中 //第pos个数据元素的指针 if(! head)returnNULL; elseif(pos=1) {s=head; head=head>nextNode();//删除第一个结点 returns; } else{ pre=getElem(head,pos-1); return(pre>deleteAfter());//删除并返回第pos个结点 } } 四、链表类的定义 1.应该如何设计数据成员? *指针的设置 *其它数据成员 2.成员函数的定义 在结点类中添加两个成员函数: voidsetNext(Node*p); {next=p}//设置结点的后继 voidsetInfo(ElemTypee); {data=e}//更新结点的数据域 classList{//链表类的声明 pravite: Node*head,*tail;//分别指向链表中的第一个和之后一个结点 Node*curPtr,*prePtr;//分别指向“当前位置结点”和它的前驱结点 intlistSize,curPos;//分别表示表长和当前位置的“位序” public: //constructor List(void);//构造一个空表 List(constList&L);//复制构造函数 //destructor ~List(void); //accessmethod BOOLlistEmpty(void) //若表空则返回TRUE否则返回FALSE {return(listSize==0);} intlistLength(void)//返回表的长度 {returnlistSize;} Node*first(void)//返回头指针 {returnhead;} Node*last(void)//返回尾指针 {returntail;} Node*prior(void); //改变当前结点为它的前驱,并返回新的当前结点的指针 Node*succ(void); //改变当前结点为它的后继,并返回新的当前结点的指针 Node*getElem(intpos); //若1≤pos≤表长,则返回指向第pos个元素所在的结点,并设它为 //当前位置 intlocation(constElemType&e); //若存在和e相等元素,则返回它在表中的位序并移动当前指针指向该 //结点,前驱指针指向它的前驱;否则返回0并指针不移动 //modificationmethod voidreSet(void);//恢复当前指针指向第一个结点 voidclearList(void);//将表清空 voidinsFirst(constElemType&e); //在第一个元素之前插入元素e,不改变当前指针 voidinsAfter(constElemType&e); //在当前结点之后插入元素e,并改变当前指针指向新插入的结点 voidinsFront(constElemType&e); //在当前结点之前插入元素e,并改变当前指针指向新插入的结点 voidappend(Node*s); //在最后一个结点之后插入指针s所指一串结点,不改变当前指针 Node*delFirst(void); //删除第一个结点并返回指向它的指针,若当前指针指向被删除的 //结点,则移动当前指针指向它的后继 Node*delNext(void); //删除当前指针所指的后继结点并返回指向它的指针,若当前指针指向 //被删除的结点,则移动当前指针指向它的后继 Node*delPrior(void); //删除当前指针所指的前驱结点并返回指向它的指针,若当前指针指向 //被删除的结点,则移
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 严蔚敏 C+ 讲稿