数据结构-用面向对象语言描述-殷人昆-第二章_第1页
数据结构-用面向对象语言描述-殷人昆-第二章_第2页
数据结构-用面向对象语言描述-殷人昆-第二章_第3页
数据结构-用面向对象语言描述-殷人昆-第二章_第4页
数据结构-用面向对象语言描述-殷人昆-第二章_第5页
已阅读5页,还剩68页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第二章线性表数据结构电子教案主讲:杨同峰1第二章线性表线性表顺序表单链表2线性表(LinearList)线性表的定义线性表是n(≥0)个数据元素的有限序列,记作

(a1,a2,…,an)

ai是表中数据元素,n是表长度。原则上讲,线性表中表元素的数据类型可以不相同。但采用的存储表示可能会对其有限制。为简单起见,假定各元素类型相同。

3线性表的特点除第一个元素外,其他每一个元素有一个且仅有一个直接前驱。除最后一个元素外,其他每一个元素有一个且仅有一个直接后继。直接前驱和直接后继描述了结点之间的逻辑关系(即邻接关系)。

a1a2a3a4a5a64线性表的抽象基类

template<classT>classLinearList{public:LinearList(); //构造函数~LinearList(); //析构函数virtualintSize()const=0; //求表最大体积virtualintLength()const=0; //求表长度virtualintSearch(T&x)const=0;//搜索virtualintLocate(inti)const=0;//定位virtualboolgetData(inti,T&x)const=0;//取值virtualvoidsetData(inti,T&x)=0;//赋值

5virtualboolInsert(inti,T&x)=0;//插入virtualboolRemove(inti,T&x)=0; //删除virtualboolIsEmpty()const=0; //判表空

virtualboolIsFull()const=0; //判表满virtualvoidSort()=0; //排序virtualvoidinput()=0; //输入virtualvoidoutput()=0; //输出//复制virtualvoidoperator=(LinearList<T,E>&L)=0;};程序:SequentialList线性表的存储表示有2种:顺序存储方式和链表存储方式。6顺序表(SequentialList)顺序表的定义将线性表中的元素相继存放在一个连续的存储空间中。可利用一维数组描述存储结构顺序表的特点所有元素的逻辑先后顺序与其物理存放顺序一致

253457164809

012345data7顺序表的静态存储和动态存储#definemaxSize100typedefintT;typedefstruct{Tdata[maxSize];//顺序表的静态存储表示intn;}SeqList;typedefintT;typedefstruct{T*data;//顺序表的动态存储表示intmaxSize,n;}SeqList;8顺序表(SeqList)类的定义#include<iostream.h> //定义在“seqList.h”中#include<stdlib.h>#include"LinearList.h"constintdefaultSize=100;template<classT>classSeqList:publicLinearList<T>{protected: T*data; //存放数组 intmaxSize; //最大可容纳表项的项数intlast; //当前已存表项数 voidreSize(intnewSize); //改变数组空间大小9public: SeqList(intsz=defaultSize);//构造函数 SeqList(SeqList<T>&L); //复制构造函数 ~SeqList(){delete[]data;} //析构函数intSize()const{returnmaxSize;} //求表最大容量intLength()const{returnlast+1;}//计算表长度intSearch(T&x)const;

//搜索x在表中位置,函数返回表项序号intLocate(inti)const;

//定位第i个表项,函数返回表项序号boolInsert(inti,T&x); //插入 boolRemove(inti,T&x); //删除};}10顺序表的构造函数//操作“exit”存放在此template<classT>SeqList<T>::SeqList(intsz){ if(sz>0){maxSize=sz;last=-1; data=newT[maxSize]; //创建表存储数组 if(data==NULL) //动态分配失败{cerr<<"存储分配错误!"<<endl;exit(1);} }}11template<classT>SeqList<T>::SeqList(SeqList<T>&L){ maxSize=L.Size();last=L.Length()-1; data=newT[maxSize]; //创建存储数组if(data==NULL) //动态分配失败{cerr<<"存储分配错误!"<<endl;exit(1);} for(inti=1;i<=n;i++)//传送各个表项 data[i-1]=L.getData(i);}复制构造函数12顺序表的搜索算法template<classT>intSeqList<T>::search(T&x)const{//在表中顺序搜索与给定值x匹配的表项,找到则//函数返回该表项是第几个元素,否则函数返回0for(inti=0;i<=last;i++) //顺序搜索if(data[i]==x)returni+1;

//表项序号和表项位置差1 return0; //搜索失败}13顺序搜索图示253457164809

012345data搜索

16i253457164809

i253457164809

i253457164809

i搜索成功142534571648

01234data搜索

50i2534571648

i2534571648

i2534571648

i2534571648

i搜索失败15搜索成功的平均比较次数

pi

是搜索第i项的概率

ci是找到时的比较次数若搜索概率相等,则

搜索不成功,数据比较n次搜索性能分析16表项的插入2534571648096301234567data50插入x253457501648096301234567data50i17表项的插入算法template<classT>boolSeqList<T>::Insert(inti,T&x){//将新元素x插入到表中第i(0≤i≤last+1)个表项位//置。函数返回插入成功的信息if(last==maxSize-1)returnfalse;//表满 if(i<0||i>last+1)returnfalse; //参数i不合理for(intj=last;j>=i;j--)//依次后移data[j]=data[j-1];//空出第i个位置data[i]=x; //插入 last++;returntrue; //插入成功}18插入算法的性能分析将新表项插入到第i个表项后面时,必须从后向前循环,逐个向后移动n-i项。最好情形为在第n个表项后面追加,移动表项个数为0,最差情形为在第1个表项位置插入新表项,移动表项个数为n考虑所有插入位置,相等插入概率时,平均移动元素个数为:19表项的删除253457501648096301234567data16删除x2534575048096301234567data20表项的删除算法template<classT>boolSeqList<T>::Remove(inti,T&x){//从表中删除第i(1≤i≤last+1)个表项,通过引用型参数x返回被删元素。函数返回删除成功信息 if(last==-1)returnfalse; //表空if(i<1||i>last+1)returnfalse; //参数i不合理x=data[i-1]; for(intj=i;j<=last;j++)//依次前移,填补data[j-1]=data[j]; last--;returntrue; }21删除算法的性能分析删除第i个表项,必须从前向后循环,逐个移动n-i个表项,最好情形是删去的第n个表项,移动表项个数为0,最差情形是删去第1个表项,移动表项个数为n-1考虑表中所有可能删除位置,相等删除概率时,平均移动元素个数为:22顺序表的应用:集合的“并”运算voidUnion(SeqList<int,int>&LA,SeqList<int,int>&LB){

intn1=LA.Length(),n2=LB.Length();inti,k,x;

for(i=0;i<n2;i++){LB.getData(i,x);

//在LB中取一元素 k=LA.Search(x);

//在LA中搜索它

if(k==0) //若在LA中未找到插入它 {LA.Insert(n1,x);n1++;}

//插入到第n个表项位置}}23

voidIntersection(SeqList<int,int>

&LA,SeqList<int,int>

&LB){

intn1=LA.Length();intx,k,i=0;

while(i<n1){LA.getData(i,x);//在LA中取一元素

k=LB.Search(x);//在LB中搜索它

if(k==0)

//若在LB中未找到{LA.Remove(i,x);n1--;}//在LA中删除它 elsei++;//未找到在A中删除它

}}程序:SequentialList顺序表的应用:集合的“交”运算24特点每个元素(表项)由结点(Node)构成。线性结构

结点之间可以连续,可以不连续存储结点的逻辑顺序与物理顺序可以不一致表可扩充单链表(SinglyLinkedList)datalinka1a2a3a4a5Λfirst25单链表的存储映像free(a)可利用存储空间a0a2a1a3freefirst(b)经过一段运行后的单链表结构26//链表类和链表结点类定义(结构方式)structLinkNode{

//链表结点类

intdata; LinkNode*link; };classList{

//链表类,直接使用链表结点类的数据和操作

private:ListNode*first;

//表头指针};//链表中的结点属于链表私有,别人无法访问27单链表中的插入与删除操作插入

第一种情况:在链表最前端插入

newnode->link=first;first=newnode;(插入前)(插入后)

firstnewnodenewnodefirst28(插入前)(插入后)

第二种情况:在链表中间插入

newnode->link=current->link; current->link=newnode;newnodecurrentnewnodecurrent29

第三种情况:在链表末尾插入

newnode->link=current->link; current->link=newnode;(插入前)(插入后)newnodenewnodecurrentcurrent30单链表的插入算法boolList::Insert(inti,int&x){//将新元素x插入到第i个结点之后。i从1开始,//i=0表示插入到首元结点之前。if(first==NULL||i==0){ //空表或首元结点前 LinkNode*newNode=newLinkNode(x); //建立一个新结点

if(newNode==NULL){cerr<<“存储分配错误\n”;exit(1)} newNode->link=first;first=newNode;

//新结点成为首元结点} else{//否则,寻找插入位置LinkNode*current=first; 31 for(intk=1;k<i;k++)//找到第i个节点 if(current==NULL)break;elsecurrent=current->link; if(current==NULL)//链短 {cerr<<“无效的插入位置!\n”;returnfalse;}else{ //插入在链表的中间 LinkNode*newNode=newLinkNode(x); newNode->link=current->link;current->link=newNode;} } returntrue;}32删除第一种情况:删除表中第一个元素第二种情况:删除表中或表尾元素在单链表中删除含ai的结点ai-1ai-1aiaiai+1ai+1pq删除前删除后33单链表的删除算法boolList::Remove(inti,int&x){//将链表中的第i个元素删去,i从1开始。LinkNode*del,*current; if(i<=1){del=first;first=first->link;} else{current=first;for(intk=1;k<i-1;k++)//找i-1号结点 if(current==NULL)break;elsecurrent=current->link; if(current==NULL||current->link==NULL) {cout<<“无效的删除位置!\n”;returnfalse;} 34 del=current->link; //删中间/尾结点 current->link=del->link; } x=del->data;deletedel; //取出被删结点数据 returntrue; };实现单链表的插入和删除算法,不需要移动元素,只需修改结点指针,比顺序表方便。情况复杂,要专门讨论空表和在表头插入的特殊情形。寻找插入或删除位置只能沿着链顺序检测。35带表头结点的单链表表头结点位于表的最前端,本身不带数据,仅标志表头非空表 空表0ana1firstfirst036在带表头结点的单链表最前端插入新结点

newnode->link=current->link;

current->link=newnode;firstnewnodefirstnewnode插入firstnewnode0firstnewnode0插入pcurrentpcurrentfirstnewnodefirstnewnode插入firstnewnode0firstnewnode0插入pcurrentpcurrent37

del=current->link;

current->link=del->link;deletedel;从带表头结点的单链表中删除最前端的结点(非空表)(空表)firstfirstfirst0first0currentdelcurrentdel38

用模板定义的单链表类template<classT>//定义在“LinkedList.h”structLinkNode{ //链表结点类的定义 Tdata; //数据域 LinkNode<T>*link;//链指针域LinkNode(LinkNode<T>*ptr=NULL) {link=NULL;}//构造函数 LinkNode(constT&item,LinkNode<T>*ptr=NULL){data=item;link=ptr;}//构造函数};39template<classT>classList:publicLinearList<T>{protected: LinkNode<T>*first; //表头指针public: List(){first=newLinkNode<T>;}//构造函数 List(T&x){first=newLinkNode<T>(x);}List(List<T>&L); //复制构造函数 ~List(){makeEmpty();} //析构函数

voidmakeEmpty(); //将链表置为空表 intLength()const; //计算链表的长度40LinkNode<T>*Search(Tx); //搜索含x元素 LinkNode<T>*Locate(inti); //定位第i个元素boolgetData(inti,T&x); //取出第i元素值voidsetData(inti,T&x); //更新第i元素值 boolInsert(inti,T&x); //在第i元素后插入 boolRemove(inti,T&x); //删除第i个元素boolIsEmpty()const //判表空否{returnfirst->link==NULL?true:false;}LinkNode<T>*getHead()const{returnfirst;}

voidSort(); //排序};41template<classT>

voidList<T>::makeEmpty(){ LinkNode<T>*q; while(first->link!=NULL){ q=first->link;//保存被删结点 first->link=q->link;//从链上摘下该结点 deleteq; //删除 }}链表置空算法(保留表头结点)42template<classT>intList<T>::Length()const{LinkNode<T>*p=first->link;

//检测指针p指示第一号结点intcount=0;

while(p!=NULL){//逐个结点检测

p=p->link;count++;}

returncount;}求单链表的长度的算法43单链表的搜索算法template<classT>LinkNode<T>*List<T>::Search(Tx){//在表中搜索含数据x的结点,搜索成功时函数返//该结点地址;否则返回NULL。 LinkNode<T>*current=first->link; while(current!=NULL&¤t->data!=x) current=current->link;

//沿着链找含x结点 returncurrent;}44单链表的定位算法template<classT>LinkNode<T,E>*List<T>::Locate(inti){//函数返回表中第i个元素的地址。若i<0或i超//出表中结点个数,则返回NULL。 if(i<0)returnNULL; //i不合理 LinkNode<T>*current=first;intk=0; while(current!=NULL&&k<i){current=current->link; k++;}returncurrent; //返回第i号结点地址或NULL}45单链表的插入算法template<classT>boolList<T>::Insert(inti,T&x){//将新元素x插入在链表中第i个结点之后。LinkNode<T>*current=Locate(i); if(current==NULL)returnfalse; //插入不成功 LinkNode<T>*newNode=newLinkNode<T>(x); //创建新结点newNode->link=current->link;//链入current->link=newNode; returntrue; //插入成功}46单链表的删除算法template<classT>boolList<T,E>::Remove(inti,T&x){//删除链表第i个元素,通过引用参数x返回元素值LinkNode<T>*current=Locate(i-1); if(current==NULL||current->link==NULL)returnfalse; //删除不成功

LinkNode<T>*del=current->link;current->link=del->link; x=del->data; deletedel; returntrue;}47前插法建立单链表从一个空表开始,重复读入数据:生成新结点将读入数据存放到新结点的数据域中将该新结点插入到链表的前端直到读入结束符为止。firstnewnodefirstnewnode0048template<classT>voidList::inputFront(TendTag){LinkNode<T>*newNode,Tval;MakeEmpty(); cin>>val;while(val!=endTag){newNode=newLinkNode<T>(val);if(newNode==NULL) {cerr<<“存储分配错误”<<endl;exit(1);}newNode->link=first->link; //插在表前端 first->link=newNode; cin>>val;}}49循环链表最后一个节点不是指向空,而是指向第一个节点an-1firsta1a0first(空表)(非空表)50循环链表的插入51约瑟夫问题用循环链表求解约瑟夫问题n个人围成一个圆圈,首先第2个人从1开始一个人一个人顺时针报数,报到第m个人,令其出列。然后再从下一个人开始,从1顺时针报数,报到第m个人,再令其出列,…,如此下去,直到圆圈中只剩一个人为止。此人即为优胜者。例如n=8m=352约瑟夫问题的解法#include<iostream.h>#include“CircList.h”voidJosephus(intn,intm){for(inti=0;i<n-1;i++){//执行n-1次for(intj=0;j<m-1;j++)Next();cout<<“Deleteperson”<<getData()<<endl;//数m-1个人Remove();//删去}}53voidmain(){CircList<int>clist; intn,m; cout<<“EntertheNumberofContestants?”;cin>>n>>m;for(inti=1;i<=n;i++)clist.insert(i);//形成约瑟夫环clist.Josephus(n,m);//解决约瑟夫问题}542.4.2双向链表(DoublyLinkedList)双向链表结点结构:priordatanext指向直接前驱指向直接后继非空表空表firstfirst55双向循环链表的定义typedefintListData;typedefstructdnode{ListNodedata;structdnode*prior,*next;}DblNode;typedefDblNode*DblList;56建立空的双向循环链表voidCreateDblList(DblList&first){first=(DblNode*)malloc(sizeof(DblNode));if(first==NULL){print(“存储分配错!\n”);exit(1);}first->prior=first->next=first;

//表头结点的链指针指向自己}57计算双向循环链表的长度intLength(DblListfirst){//计算带表头结点的双向循环链表的长度DblNode*p=first->next;intcount=0;while(p!=first){p=p->next;count++;}returncount;}58双向循环链表的插入(非空表)

q->prior=p; q->next=p->next;p->next=q;q->next->prior=q;在结点*p后插入25firstfirst314815pp31482515q59双向循环链表的插入(空表)

q->prior=p; q->next=p->next;

p->next=q;q->next->prior=q;

pqfirst25f

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论