1 / 64

第 2 章 线 性 表

第 2 章 线 性 表. 2 . 1 线性表的类型定义 2.2 线性表的顺序表示和实现 2.3 线性表的链式表示和实现 2.4 一元多项式的表示及相加. 2.1 线性表的类型定义. 线性表: 是 n 个类型相同的数据元素的有限序列,数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后继 。. 例 1 英文字母表( A , B , C , … , Z) 是一个线性表 例 2. 数据元素. 线性表的定义. 线性表 是由 n (n≥0) 个类型相同的数据元素 a 1 ,a 2 , … , a n 组成的有限序列,记做

cathy
Download Presentation

第 2 章 线 性 表

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第 2 章 线 性 表 2.1 线性表的类型定义 2.2 线性表的顺序表示和实现 2.3 线性表的链式表示和实现 2.4 一元多项式的表示及相加

  2. 2.1 线性表的类型定义 线性表:是n个类型相同的数据元素的有限序列,数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后继 。

  3. 例1 英文字母表(A,B,C,…,Z)是一个线性表 例2 数据元素

  4. 线性表的定义 线性表是由n (n≥0)个类型相同的数据元素a1,a2,…,an组成的有限序列,记做 (a1,a2,…,ai-1,ai,ai+1, …,an)。 n为线性表的长度,n=0时称为空表. 线性表的特点 同一性:线性表由同类数据元素组成,每一个ai必须属于同一数据对象。 有穷性:线性表由有限个数据元素组成,表长度就是表中数据元素的个数。n=0时称为空表。 有序性:线性表中相邻数据元素之间存在着序偶关系<ai,ai+1>。

  5. 线性表的抽象数据类型定义 ADT  List{ 数据元素:D={ai| ai∈D0,   i=1,2,…,n ,  n≥0 ,D0为某一数据对象} 关系:R1={<ai-1,ai> | ai, ai-1∈D,i=2, …,n} 基本操作: (1)InitList(&L) 操作前提:L为未初始化线性表。 操作结果:将L初始化为空表。 (2)DestroyList(&L) 操作前提:线性表L已存在。 操作结果:将L销毁。

  6. (3)ClearList(&L) 操作前提:线性表L已存在 。 操作结果:将表L置为空表。 (4)EmptyList(L) 操作前提:线性表L已存在。 操作结果:如果L为空表则返回真,否则返回假。 (5)ListLength(L) 操作前提:线性表L已存在。 操作结果:如果L为空表则返回0,否则返回表中的元素个数。 (6)Locate(L,e) 操作前提: 表L已存在,e为合法元素值。 操作结果: 如果L中存在元素e,则将“当前指针”指向元素e所在位置并返回真,否则返回假。

  7. (7)GetData(L,i) 操作前提:表L存在,且i值合法,即1≤i≤ListLength(L)) 操作结果:返回线性表L中第i个元素的值。 (8)ListInsert (&L,i,e) 操作前提:表L已存在,e为合法元素值且1≤i≤ListLength(L)+1。 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。 (9)ListDelete(&L,i,&e) 操作前提:表L已存在且非空, 1≤i≤ListLength(L)。 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1。 }ADT List

  8. 2.2 线性表的顺序表示和实现

  9. 2.2.1 线性表的顺序存储结构 线性表的顺序存储结构(顺序映像): 用一组地址连续的存储单元依次存储线性表的数据元素。 顺序表: 采用顺序存储结构的线性表通常称为顺序表

  10. 存储地址 内存 元素序号 a1 LOC(a1) 1 LOC(a1) +L a2 2 n LOC(a1) +(n-1)L an 备用空间 • 元素地址计算方法: • LOC(ai)=LOC(a1)+(i-1)*L • LOC(ai+1)=LOC(ai)+L • 其中: • L—一个元素占用的存储单元个数 • LOC(ai)—线性表第i个元素的地址 • 特点: • 实现逻辑上相邻—物理地址相邻 • 实现随机存取

  11. 顺序存储结构的实现 可以借助于高级程序设计语言中的数组来表示,一维数组的下标与元素在线性表中的序号相对应。

  12. 以C语言为例 : // 线性表的顺序存储结构 #define LIST_INIT_SIZE 100 /*存储空间的初始分配量*/ typedef struct { ElemType elem [LIST_INIT_SIZE]; //存储空间基址 int length; //当前长度 }SqList;

  13. 2.2.2 线性表顺序存储结构上的运算 • 查找 • 插入 • 删除 • 合并

  14. 顺序表的查找运算 线性表有两种基本的查找运算。 按序号查找GetData(L,i): 要求查找线性表L中第i个数据元素,其结果是L.elem[i-1]或L->elem[i-1]。 按内容查找Locate(L,e):要求查找线性表L中与给定值e相等的数据元素,其结果是:若在表L中找到与e相等的元素,则返回该元素在表中的序号;若找不到,则返回一个“空序号”,如-1。

  15. 顺序表的查找运算 算法分析:查找运算可采用顺序查找法实现,即从第一个元素开始,依次将表中元素与e相比较,若相等,则查找成功,返回该元素在表中的序号;若e与表中的所有元素都不相等,则查找失败,返回“-1”。

  16. 算法实现: int  Locate(SqList L,ElemType e) { i=0 ;  //i为计数器,从第一个元素开始比较 while ((i<=L.length-1)&&(L.elem[i]!=e))  /*顺序扫描表,直到找到值为e的元素,或扫描到表尾而没找到*/ i++; if  (i<=L.length-1)         return(i+1);  /*若找到值为e的元素,则返 回其序号*/ else            return(-1);  /*若没找到,则返回空序号*/ }

  17. 顺序表的插入运算 定义: 在第i(1i  n+1)个元素前插入一个新的数据元素e,使长度为n的线性表 (a1,a2,……,ai-1,ai,……,an) 变成长度为n+1的线性表 (a1,a2,……,ai-1,e,ai,……,an) 算法分析:

  18. 数组下标 数组下标 内存 元素序号 元素序号 内存 0 0 a1 a1 1 1 a2 2 2 a2 1 1 插入e i-1 i-1 ai i i ai i i ai+1 i+1 i+1 ai+1 n n an an-1 n-1 n-1 n+1 n+1 n n an e

  19. 算法实现: Status ListInsert_Sq(Sqlist &L,int i,ElemType e){ if(i<1||i>L.length+1) return ERROR; if(L.length>=LIST_INIT_SIZE){ //当前存储已满 return ERROR ;} q=&(L.elem[i-1]); // q为插入位置 for(p=&(L.elem[L.length-1]);p>=q;- -p) *(p+1)=*p; //插入位置之后元素后移 *q=e; ++L.length; return OK;}

  20. 算法实现2: Status ListInsert_Sq(Sqlist &L,int i,ElemType e){ if(i<1||i>L.length+1) return ERROR; if(L.length>=LIST_INIT_SIZE){ //当前存储已满 return ERROR ;} for(k=L.length-1;k>=i-1;- -k) L.elem[k+1]=L. elem[k]; //插入位置之后元素后移 L.elem[i-1]=e; ++L.length; return OK;}

  21. 算法时间复杂度T(n) 设Pi是在第i个元素之前插入一个元素的概率,则在长度为n的线性表中插入一个元素时,所需移动的元素次数的期望值(平均次数)为:

  22. 顺序表的删除运算 • 定义: 线性表的删除是指将第i(1i  n)个元素删除,使长度为n的线性表 (a1,a2,……,ai-1,ai,ai+1,……,an) 变成长度为n-1的线性表 (a1,a2,……,ai-1, ai+1, ……,an) • 算法分析: 需将第i+1至第n共(n-i)个元素前移

  23. 数组下标 内存 元素序号 数组下标 内存 元素序号 0 a1 1 a1 0 1 a2 2 a2 2 1 1 ai-1 ai-1 i-2 i-1 i-2 i-1 删除ai i-1 ai i i-1 ai+1 i i ai+1 i+1 i ai+2 i+1 an n-1 n-2 n an n-1 n-1 n n+1 n

  24. 算法实现: Status ListDelete_Sq(Sqlist &L,int i,ElemType &e){ if(i<1||i>L.length) return ERROR; p=&(L.elem[i-1]); // p为被删除元素的位置 e=*p; // 被删除元素的值赋给e q=&L.elem[L.length-1]; // 表尾元素的位置 for(++p;p<=q;++p) *(p-1)=*p; // 被删除元素之后的元素左移 - -L.length; // 表长减1 return OK; }

  25. 算法实现2: Status ListDelete_Sq(Sqlist &L,int i,ElemType &e){ if(i<1||i>L.length) return ERROR; e= L.elem[i-1]; // 被删除元素的值赋给e for(k=i;k<=L.length-1;++k) L.elem[k-1]=L.elem[k]; // 被删除元素之后的元素左移 - -L.length; // 表长减1 return OK; }

  26. 算法时间复杂度 设Qi是删除第i个元素的概率,则在长度为n的线性表中删除一个元素所需移动的元素次数的(期望值)平均次数为:

  27. 算法评价: • 在顺序表中插入或删除一个元素时,平均移动表的一半元素,当n很大时,效率很低。

  28. 例:顺序表的合并.有两个顺序表LA和LB,其元素均为非递减有序排列,编写一个算法,将它们合并成一个顺序表LC,要求LC也是非递减有序排列。例如LA=(2, 2, 3), LB=(1, 3, 3, 4), 则LC=(1, 2, 2, 3, 3, 3, 4)。 算法分析:设表LC是一个空表,为使LC也是非递减有序排列,可设两个指针i、j分别指向表LA和LB中的元素,若LA.elem[i]>LB.elem[j],则当前先将LB.elem[j]插入到表LC中,若LA.elem[i]≤LB.elem[j] ,当前先将LA.elem[i]插入到表LC中,如此进行下去,直到其中一个表被扫描完毕,然后再将未扫描完的表中剩余的所有元素放到表LC中。

  29. 算法模拟 LA LB LC 下标 值 下标 值 下标 值 i 0 j k 2 2 0 1 1 0 k i 2 2 j 1 1 1 3 3 k i j 2 2 2 3 3 3 3 j k i 3 4 4 3 k 4 j k 5 6 k k

  30. 算法实现: void   merge(SqList LA,  SqList LB,  SqList &LC)   {  i=0;j=0;k=0;    while(i<=LA.length-1&&j<=LB.length-1)      if(LA.elem[i]<=LB.elem[j]) {         LC.elem[k]= LA.elem[i];    i++; k++;  }          else         { LC.elem[k]=LB.elem[j];    j++; k++;     }      while(i<=LA.length-1)      /*当表LA有剩余元素时,则将表LA余下的元素赋给表LC*/      {   LC.elem[k]= LA.elem[i];  i++; k++;     }      while(j<=LB.length-1)  /*当表LB有剩余元素时,则将表LB余下的元素赋给表LC*/      {   LC.elem[k]= LB.elem[j];    j++;  k++;    }         LC.length=LA.length+LB.length;    }

  31. 顺序存储结构的优缺点: 优点 逻辑相邻,物理相邻 可随机存取任一元素 缺点 插入、删除操作需要移动大量的元素

  32. 结点 数据域 指针域 2.3 线性表的链式存储结构 特点: • 用一组任意的存储单元存储线性表的数据元素 • 利用指针实现了用不相邻的存储单元存放逻辑上相邻的元素 • 每个数据元素ai,除存储本身信息外,还需存储其直接后继的信息 • 结点 • 数据域:元素本身信息 • 指针域:指示直接后继的存储位置

  33. H 存储地址 数据域 指针域 LI ZHAO SUN QIAN 1 LI 7 QIAN 13 WANG ZHOU ZHENG WU ^ SUN 19 H WANG 25 31 WU 31 ZHAO 37 ZHENG 43 ZHOU 例 线性表 (ZHAO,QIAN,SUN,LI,ZHOU,WU,ZHENG,WANG) 43 头指针 13 1 NULL 37 7 19 25

  34. next data p 结点(*p) 2.3.1 线性链表 • 定义:结点中只含一个指针域的链表叫~,也叫单链表 typedef struct LNode { ElemTypedata; struct LNode *next; }LNode,*LinkList; • 实现 LinkList L,p; (*p)表示p所指向的结点 (*p).datap->data表示p指向结点的数据域 (*p).nextp->next表示p指向结点的指针域 生成一个LNode型新结点:p=(LinkList)malloc(sizeof(LNode)); 系统回收p结点:free(p)

  35. 头结点:在单链表第一个结点前附设一个结点叫头结点.头结点指针域为空表示线性表为空头结点:在单链表第一个结点前附设一个结点叫头结点.头结点指针域为空表示线性表为空 头结点 p …... L an ^ a1 a2 L ^ 空表 第一个数据元素的值:L->next->data 第二个数据元素的指针:L->next->next p->data p->next p->next->data p->next->next

  36. 单链表的基本运算 1.头插法建立单链表 2.尾插法建立单链表 3.查找 4.插入 5.删除

  37. p L a b p 1.头插法建立单链表 算法描述: 逆位序输入n个元素的值,建立带头结点的单链表 算法演示:如输入二个元素a,b,头插法建立单链表 ^ ^

  38. 1.头插法建立单链表 算法实现: void CreateList_L(LinkList &L,int n){ L=(LinkList)malloc(sizeof(LNode)); L->next=NULL;//先建立一个带头结点的单链表 for(i=n;i>0;--i){ p=(LinkList)malloc(sizeof(LNode));//生成新结点 scanf(&p->data);//输入元素值 p->next=L->next;L->next=p;//插入到表头 } }

  39. r r L p 2.尾插法建立单链表 算法描述: 正位序输入n个元素的值,建立带头结点的单链表 算法演示:如输入二个元素a,b,尾插法建立单链表 ^ b a ^

  40. 2.尾插法建立单链表 算法实现: void CreateList_L2(LinkList &L,int n){ L=(LinkList)malloc(sizeof(LNode)); L->next=NULL;//先建立一个带头结点的单链表 r=L;//r为表尾元素指针 for(i=n;i>0;--i){ p=(LinkList)malloc(sizeof(LNode));//生成新结点 scanf(&p->data);//输入元素值 p->next=NULL;r->next=p;r=p; //插入到表尾 } }

  41. 3.查找 • 按序号查找 • 按值查找

  42. 按序号查找 算法描述:设带头结点的单链表的头指针为L,要查找表中第i个结点,则需从单链表的头指针L出发,从头结点开始,顺着链域扫描.用指针p指向当前扫描到的结点,初值指向第一个结点(p=L->next).用j做计数器,累计当前扫描过的结点数(初值为1),当j=i时,指针p所指的结点就是要找的第i个结点.

  43. p a b m n i 算法演示 L Status GetElem_L(LinkList L,int i,ElemType &e) {p=L->next;j=1; while(p&&j<i){ p=p->next;++j;} if(!p||j>i) return ERROR; e=p->data; return OK;} …… …… ^

  44. 按值查找

  45. p a b e n 算法演示 L LinkList Locate_L(LinkList L,ElemType e)} p=L->next; while(p){ if(p->data==e) break; else p=p->next;} return p;} …… …… ^

  46. b p a x s 4.插入 插入:在线性表两个数据元素a和b间插入x,已知p指向a p->next=s; s->next=p->next; 算法评价

  47. 算法实现 Status ListInsert_L(ListList &L,int I,ElemType e){ //在带头结点的单链表L中第i个位置之前插入元素e p=L;j=0; while(p&&j<i-1){p=p->next;++j;}//寻找第i-1个结点 if(!p||j>i-1) return ERROR; s=(LinkList)malloc(sizeof(LNode));//生成新结点 s->data=e;s->next=p->next; p->next=s; return OK; }

  48. p b a c q 5.删除 • 删除:单链表中删除b,设p指向a p->next=q->next; 算法评价

  49. 算法实现 Status ListDelete_L(ListList &L,int I,ElemType &e){//在带头结点的单链表L中删除第i个元素,由//e返回其值 p=L;j=0; while(p->next&&j<i-1){p=p->next;++j;}//寻找第i-1个结点 if(!(p->next)||j>i-1) return ERROR; q=p->next;p->next=q->next; e=q->data;free(q); return OK; }

More Related