1 / 121

第二章 线性表

第二章 线性表. 线性结构的基本特征 :. 线性结构 是 一个数据元素的有序(次序)集. 1 .集合中必存在唯一的一个“第一元素”. 2 .集合中必存在唯一的一个 “最后元素”. 3 .除最后元素在外,均有 唯一的后继. 4 .除第一元素之外,均有 唯一的前驱. 2.1 线性表的类型定义. 2.2 线性表类型的实现  顺序映象. 2.3 线性表类型的实现  链式映象. 2.4 一元多项式的表示. ADT List {. 数据对象 :.

ryder
Download Presentation

第二章 线性表

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. 线性结构的基本特征: 线性结构 是 一个数据元素的有序(次序)集 1.集合中必存在唯一的一个“第一元素” 2.集合中必存在唯一的一个 “最后元素” 3.除最后元素在外,均有 唯一的后继 4.除第一元素之外,均有 唯一的前驱

  3. 2.1 线性表的类型定义 2.2 线性表类型的实现  顺序映象 2.3 线性表类型的实现  链式映象 2.4 一元多项式的表示

  4. ADT List { 数据对象: D={ ai | ai ∈ElemSet, i=1,2,...,n, n≥0 } { 称n为线性表的表长; 称n=0时的线性表为空表。} 数据关系: R1={ <ai-1 ,ai >|ai-1 ,ai∈D, i=2,...,n } { 设线性表为 (a1,a2, . . . ,ai,. . . ,an), 称 i 为 ai 在线性表中的位序。}

  5. 基本操作: 结构初始化操作 结构销毁操作 引用型操作 加工型操作 } ADT List

  6. {结构初始化} InitList( &L ) 操作结果:构造一个空的线性表 L。 CreateList( &L, A[], n) 初始条件:A[]中存在线性表的 n 个 数据元素。 操作结果:构造一个含 n 个数据元素 的线性表 L。

  7. {销毁结构} DestroyList( &L ) 初始条件:线性表 L 已存在。 操作结果:销毁线性表 L。

  8. {引用型操作} ListEmpty( L ) ListLength( L ) PriorElem( L, cur_e, &pre_e ) NextElem( L, cur_e, &next_e ) GetElem( L, i, &e ) LocateElem( L, e, compare( ) ) ListTraverse(L, visit( ))

  9. ListEmpty( L ) (线性表判空) 初始条件: 操作结果: 线性表 L 已存在。 若 L 为空表,则返回 TRUE,否则FALSE。 ListLength( L ) (求线性表的长度) 初始条件: 操作结果: 线性表 L 已存在。 返回线性表 L中元素个数。

  10. 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无定义。

  11. GetElem( L, i, &e )( 求线性表中某个元素) 初始条件: 操作结果: 且1≤i≤LengthList(L)。 线性表 L 已存在 以 e带回 L中第 i个数据元素值。 LocateElem( L, e, compare( ) )(定位函数) 初始条件: 操作结果: 线性表 L 已存在,compare()为判定函数。 返回 L 中第 1 个与 e 满足关系compare( )的元素的位序,若不存在这样的元素,则返回0。

  12. ListTraverse( L, visit( ) )( 遍历线性表) 初始条件: 操作结果: 线性表 L 已存在,visit( )为数据元素的访问函数。 依次对 L的每个数据元素调用函数 visit( ),一旦 visit( ) 失败,则遍历操作失败。

  13. {加工型操作} ClearList( &L ) ( 线性表置空 ) PutElem( &L, i, &e ) ( 改变数据元素的值 ) ListInsert( &L, i, e ) ( 插入数据元素 ) ListDelete( &L, i, &e ) ( 删除数据元素 )

  14. ClearList( &L ) 初始条件: 操作结果: 线性表 L 已存在。 将 L 重置为空表。 PutElem( &L, i, e ) 初始条件: 操作结果: 线性表 L 已存在, 且 1≤i≤LengthList(L)。 L 中第 i 个元素赋值和 e 相同。

  15. ListInsert( &L, i, e ) ,1≤i≤LengthList(L)+1。 初始条件: 操作结果: 线性表 L 已存在 在 L 的第 i 个元素之前插入新的元素e, L 的长度增 1。 ListDelete( &L, i, e ) 初始条件: 操作结果: ,1≤i≤LengthList(L)。 线性表 L 已存在 删除 L 中第 i 个元素,并以 e 带回其值, L 的长度减 1。

  16. 例 2-1 假设有两个集合 A 和 B 分别用两个线性表 LA 和 LB 表示,即:线性表中的数据元素即为集合中的成员。 现要求一个新的集合A=A∪B。 即:需对线性表作如下操作: 扩大线性表 LA,将存在于线性表LB 中而不存在于线性表 LA 中的数据元素插入到线性表 LA 中去。

  17. 操作步骤: 1.取得线性表 LB 中一个数据元素; ListDelete(Lb, 1, e); 2.依值在线性表 LA 中进行查访; LocateElem(LA, e, equal( )); 3.若不存在,则插入之。 ListInsert(LA, n+1, e); ( n 表示线性表 LA 当前长度)

  18. void union(List &La, List Lb) { // 将线性表Lb中所有在线性表La中不存在的数据元素 // 插入到线性表La中 La_len = ListLength(La);// 求线性表La的长度 while (!ListEmpty(Lb)) { ListDelete(Lb, 1, e);// 删除Lb中第1个数据元素赋给e if (!LocateElem(La, e, equal( )) ) ListInsert(La, ++La_len, e); // La中不存在和 e 相同的数据元素,则插入之 }//while } // union

  19. 例 2-2 已知一个“非纯集合” B,试构造一个纯集合A,使 A 中只包含 B 中所有值各不相同的数据元素。 若仍然以线性表表示集合,则算法的策略应该和例一基本相同,差别是什么? 1.集合 A 的初态是“空集” 2.不破坏集合 B

  20. void purge(List &La, List Lb) { La_len=0; Lb_len=ListLength(Lb); } // pugre InitList(La); // 构造(空的)线性表LA for (i = 1; i <= Lb_len; i++) { }//for GetElem(Lb, i, e); // 取Lb中第 i 个数据元素赋给 e if (!LocateElem(La, e, equal( )) ) ListInsert(La, ++La_len, e); // La中不存在和 e 相同的数据元素,则插入之

  21. 判别两个集合是否相等。 例 2-3 集合相等的条件是:两者所含元素个数相同,且所有对应元素都相等。 仍以线性表表示集合,并假设这两个集合是“纯集合”。 则算法的策略为:在两个线性表的长度相等的前提下,只要判别一个表中的元素在另一个表中都存在即可。

  22. bool isEqual(List LA, List LB) { // 若线性表LA和LB不仅长度相等,且所含数据 // 元素也相同,则返回 TRUE, 否则返回 FALSE }//isEqual La_len = Listlength(LA); Lb_len = Listlength(LB); if ( La_len != Lb_len ) return FALSE; // 两表的长度不等 else {} ………

  23. while ( i<= La_len && found ) { }//while return found; i = 1; found = TRUE; GetElem(LA, i, e); // 取得LA中一个元素 if (LocateElem(LB, e, equal( )) i++; // 依次处理下一个 else found = FALSE; // LB中没有和该元素相同的元素

  24. 一、顺序表 ---线性表的顺序映象 二、顺序表中基本操作的实现 三、顺序表的其它操作举例

  25. 顺序映象 ——以 x 的存储位置和 y 的存储位置之间某种关系表示逻辑关系<x,y> 最简单的一种顺序映象方法是: 令 y 的存储位置和 x 的存储位置相邻。

  26. a1 a2… ai-1 ai… an 用一组地址连续的存储单元 依次存放线性表中的数据元素 线性表的起始地址, 称作线性表的基地址

  27. 以“存储位置相邻”表示有序对<ai-1,ai> 即:LOC(ai) = LOC(ai-1) + C 一个数据元素所占存储量↑ 所有数据元素的存储位置均取决于 第一个数据元素的存储位置 LOC(ai) =LOC(a1)+ (i-1)×C 基地址

  28. 顺序表的 C 语言描述 // 存储结构 typedef struct { } SqList; // 俗称 顺序表 ElemType *elem; // 存储空间基址 int length; // 当前长度 int listsize; // 当前分配的存储容量 // (以sizeof(ElemType)为单位) // 基本操作接口

  29. void purge(SqList &La, SqList Lb) { // 构造顺序表La,使其只包含Lb中所有值不 //相同的数据元素, 算法不改变顺序表Lb bool b; int Lb_len = Listlength(Lb); // 求线性表Lb的长度 InitList(La, Lb_len); // 创建一个空的线性表La int La_len = 0; for (i = 1; i <= Lb_len; i++){ // 依次处理Lb中每个元素 }//for } //purge

  30. b = GetElem(Lb, i, e); // 取Lb中第i个数据元素赋给e if (!LocateElem(La, e, equal( )) { ++La_len; b = ListInsert(La, La_len, e); //当La中不存在和e 值相同的数据 //元素时进行插入 }

  31. 线性表的基本操作在顺序表中的实现 InitList(&L) // 结构初始化 LocateElem(L, e, compare()) // 查找 ListInsert(&L, i, e) // 插入元素 ListDelete(&L, i) // 删除元素

  32. Status InitList( SqList& L, int maxsize ) { // 构造一个最大容量为 maxsize 的顺序表 } // InitList L.elem = new ElemType[maxsize]; //为顺序表分配大小为 maxsize 的数组空间 if (!L.elem) exit(OVERFLOW); L.length = 0; L.listsize = maxsize; return OK; O(1) 算法时间复杂度:

  33. L.listsize L.elem 23 75 41 38 54 62 17 p p p p p p L.length = 7 例如:顺序表 可见,基本操作是, 将顺序表中的元素 逐个和给定值 e 相比较。 i = 1 2 3 4 1 8 假设 e = 50 38

  34. int LocateElem(SqList L, ElemType e, Status (*compare)(ElemType, ElemType)) { //在顺序表中查询第一个满足判定条件的数据元素, // 若存在,则返回它的位序,否则返回 0 } // LocateElem i = 1; // i 的初值为第 1 元素的位序 p = L.elem;// p 的初值为第 1 元素的存储位置 while (i <= L.length && !(*compare)(*p++, e)) ++i; (*compare)(*p++, e) if (i <= L.length) return i; else return 0; //找到满足条件的元素 // 没有找到满足条件的元素 算法的时间复杂度为: O( ListLength(L) )

  35. 线性表操作 ListInsert(&L, i, e)的实现: 首先分析: 插入元素时, 线性表的逻辑结构发生什么变化 ?

  36. a1 a2… ai-1 ai… an a1 a2… ai-1 ai … an e 表的长度增加 (a1, …, ai-1, ai, …, an) 改变为 (a1, …, ai-1, e, ai, …, an) <ai-1, ai> <ai-1, e>, <e, ai>

  37. Status ListInsert(SqList &L, int i, ElemType e) { //在顺序表L的第 i 个元素之前插入新的元素e, // i 的合法范围为 1≤i≤L.length+1 } // ListInsert …… for (j=L.length-1; j>=pos-1; --j) L.elem[j+1] = L.elem[j]; // 插入位置及之后的元素右移 L.elem[pos-1] = e; // 插入e ++L.length; // 表长增1 return TRUE; 元素右移 算法时间复杂度为: O( ListLength(L) )

  38. 考虑移动元素的平均情况: 假设在第i 个元素之前插入的概率为 pi, 则在长度为n的线性表中插入一个元素所需移动元素次数的期望值为: 若假定在线性表中任何一个位置上进行插入的概率都是相等的,则移动元素的期望值为:

  39. if (i < 1 || i > L.length+1) return ERROR; //插入位置不合法 if (L.length >= L.listsize) return OVERFLOW; // 当前存储空间已满

  40. j j j 21 18 30 75 42 56 87 21 18 30 75 例如:ListInsert(L, 5, 66) for (j=L.length-1; j >=pos-1; --j) L.elem[j+1]= L.elem[j]; 0 4 L.length-1 66 42 56 87

  41. 线性表操作 ListDelete(&L, i, &e)的实现: 首先分析: 删除元素时, 线性表的逻辑结构发生什么变化?

  42. a1 a2… ai-1 aiai+1 … an a1 a2… ai-1 (a1, …, ai-1, ai, ai+1, …, an) 改变为 (a1, …, ai-1, ai+1, …, an) <ai-1, ai>, <ai, ai+1> <ai-1, ai+1> ai+1 … an 表的长度减少

  43. Status ListDelete (SqList &L, int i, ElemType &e) { } // ListDelete if ((i < 1) || (i > L.length)) return ERROR; // 删除位置不合法 for (j = pos; j<L.length; ++j) L.elem[j-1] = L.elem[j]; // 被删除元素之后的元素左移 --L.length; // 表长减1 returnTRUE; 元素左移 算法时间复杂度为: O( ListLength(L))

  44. 考虑移动元素的平均情况: 假设删除第i 个元素的概率为 qi , 则在长度为n 的线性表中删除一个元素所需移动元素次数的期望值为: 若假定在线性表中任何一个位置上进行删除的概率都是相等的,则移动元素的期望值为:

  45. j j j 21 18 30 75 42 56 87 63 21 18 30 75 例如:ListDelete(L, 5, e) for (j=pos; j<L.length; ++j) L.elem[j-1] = L.elem[j]; 0 5 L.length-1 56 87 63

  46. 例 2-4 试设计一个算法,用尽可能少的辅助空间将顺序表中前 m 个元素和后 n 个元素进行互换,即将线性表 (a1, a2, …, am, b1, b2, …, bn ) 改变成 (b1, b2, …, bn, a1, a2, …, am ) 。 算法 1 从b1开始,从原地删除之后插入到 a1 之前直至 bn。 算法 2 进行三次“逆转顺序表”的操作。

  47. i i i j j j g 1 2 a 3 a b c b a d b c c e d d f e e f g f g 1 2 3 5 1 4 2 3 4 2 5 1 g a f b e c d e c f b a g

  48. void invert( ElemType &R[],int s, int t ) // 本算法将数组 R 中下标自 s 到 t 的元素逆置, // 即将(Rs, Rs+1, …, Rt-1, Rt) // 改变为(Rt, Rt-1, …, Rs+1, Rs) void exchange ( SqList &A; int m ) { // 本算法实现顺序表中前 m 个元素 // 和后 n 个元素的互换 n = A.length – m; invert( A.elem, 0, A.length ); invert( A.elem, 0, n-1 ); invert( A.elem, n, m+n-1 ); } // exchange 算法的时间复杂度为: O(m+n)

  49. void exchange( SqList &A, int m ) { // 实现顺序表 A 中前 m 个元素和后 n 个元素互换 } exchange for ( i=0; j = m; j<A.length; i++,j++ ) { } x = A.elem[j]; for ( k=j; k>i; k-- ) A.elem[j] = A.elem[j-1]; A.elem[i] = x; 算法的时间复杂度 为: O(mn)

  50. 例 2-5 试编写算法,删除顺序表中“多余” 的数据元素 。 从a1开始,检查在它之后的数据元素,如有和它相等的,则从表中删除之。 算法 1 回顾例2-2的算法,试按“构造”一个新的顺序表的思想来进行,设想这两个表“共享”一个存储空间。 算法 2

More Related