240 likes | 322 Vues
例. 假设 : 有两个 集合 A 和 B 分别用两个 线性表 LA 和 LB 表示,即:线性表中的数据元素即为集合中的成员。 现要求一个新的集合 A = A∪B 。. 上述问题可演绎为:. 要求对线性表作如下操作: 扩大线性表 LA ,将 存在于线性表 LB 中 而 不存在于线性表 LA 中 的数据元素 插入到线性表 LA 中 去。. 操作步骤:. 1 . 从线性表 LB 中依次察看每个数据元素 ;. Get(LB, i, x). 2 . 依值在线性表 LA 中进行查访 ;. Locate(LA, x). 3 . 若不存在,则插入。.
E N D
例 假设:有两个集合 A 和 B 分别用两个线性表 LA 和 LB 表示,即:线性表中的数据元素即为集合中的成员。 现要求一个新的集合A=A∪B。
上述问题可演绎为: 要求对线性表作如下操作: 扩大线性表 LA,将存在于线性表LB 中而不存在于线性表 LA 中的数据元素插入到线性表 LA 中去。
操作步骤: 1.从线性表LB中依次察看每个数据元素; Get(LB, i, x) 2.依值在线性表LA中进行查访; Locate(LA, x) 3.若不存在,则插入。 Insert(LA, n+1, x)
void union(List &La, List Lb) { La_len = Length(La); Lb_len = Length(Lb); for (i = 1; i <= Lb_len; i++) { x=Get(Lb, i); if (!Locate(La, x) ) Insert(La, ++La_len, x); } } // union
静态链表结构 利用数组定义,运算 过程中存储空间大小不变 分配节点:j = avil; avil = A[avil].link; 释放节点: A[i].link = avil; avil = i;
循环链表 (Circular List)
循环链表是单链表的变形。 • 循环链表最后一个结点的link指针不为 0 (NULL),而是指向了表的前端。 • 为简化操作,在循环链表中往往加入表头结点。 • 循环链表的特点是:只要知道表中某一结点的地址,就可搜寻到所有其他结点的地址。
循环链表的示例 • 带表头结点的循环链表
用循环链表求解约瑟夫问题 • 约瑟夫问题的提法 n 个人围成一个圆圈,首先第2个人从1开始一个人一个人顺时针报数, 报到第m个人,令其出列。然后再从下一个人开始,从1顺时针报数,报到第m个人,再令其出列,…,如此下去, 直到圆圈中只剩一个人为止。此人即为优胜者。 • 例如 n = 8 m = 3
约瑟夫问题的解法 #include <iostream.h> #include “CircList.h” void Josephus ( intn, int m ) { for ( inti=0;i<n-1;i++ ) {//执行n-1次 for ( intj=0;j<m-1;j++ ) Next ( ); cout << “Delete person ” << getData ( ) << endl; //数m-1个人 Remove ( ); //删去 } }
voidmain ( ) { CircList<int> clist; intn, m; cout << “Enter the Number of Contestants?”; cin >> n >> m; for ( inti=1;i<=n;i++ ) clist.insert (i); //形成约瑟夫环 clist.Josephus (n, m); //解决约瑟夫问题 }
多项式及其相加 • 在多项式的链表表示中每个结点增加了一个数据成员link,作为链接指针。 • 优点是: • 多项式的项数可以动态地增长,不存在存储溢出问题。 • 插入、删除方便,不移动元素。
多项式(polynomial)类的链表定义 structTerm { int coef; int exp; voidInit ( intc,inte ) { coef = c; exp = e;} }; class Polynomial { List<Term> poly; friendPolynomialoperator + (constPolynomial &,constPolynomial &); };
多项式链表的相加 AH = 1 - 10x6 + 2x8 +7x14 BH = - x4 + 10x6 - 3x10 + 8x14 +4x18
Polynomial operator + ( constPolynomial & ah,constPolynomial & bh ) { Term *pa, *pb, *pc, *p; ListIterator<Element> Aiter ( ah.poly ); ListIterator<Element> Biter ( bh.poly ); //建立两个多项式对象 Aiter、 Biter pa = pc = Aiter.First ( ); //pa检测指针 pb = p= Biter.First ( ); // pb检测指针 pa = Aiter.Next ( ); pb = Biter.Next; // pa, pb越过表头结点 deletep;
while ( Aiter.NotNull ( )&& Biter.NotNull ( ) ) switch ( compare ( pa→exp, pb→exp ) ){ case '=' : pa→coef = pa→coef + pb→coef; p = pb; pb = Biter.Next ( );delete p; if ( !pa→coef ) { p = pa; pa = Aiter.Next ( ); deletep; } else { pc→link = pa; pc = pa; pa = Aiter.Next ( ); } break;
case ‘>' : pc→next = pb; pc = pb; pb = Biter.Next ( ); break; case ‘<' : pc→next = pa; pc = pa; pa = Aiter.Next ( ); break; } if ( Aiter.NotNull ( ) ) pc→next = pa; else pc→next = pb; }
双向链表 (Doubly Linked List) • 双向链表是指在前驱和后继方向都能游历(遍历)的线性链表。 • 双向链表每个结点结构: 前驱方向 后继方向 • 双向链表通常采用带表头结点的循环链表形式。
非空表 空表 • 结点指向p ==p→lLink→rLink == p→rLink→lLink
顺序表与链表的比较 基于空间的比较 • 存储分配的方式 • 顺序表的存储空间是静态分配的 • 链表的存储空间是动态分配的 • 存储密度 = 结点数据本身所占的存储量/结点结构所占的存储总量 • 顺序表的存储密度 = 1 • 链表的存储密度 < 1
顺序表与链表的比较 基于时间的比较 • 存取方式 • 顺序表可以随机存取,也可以顺序存取 • 链表是顺序存取的 • 插入/删除时移动元素个数 • 顺序表平均需要移动近一半元素 • 链表不需要移动元素,只需要修改指针 • 若插入/删除仅发生在表的两端,宜采用带尾指针的循环链表
线性表小结 主要介绍了如下一些基本概念: 线性表:一个线性表是n≥0个数据元素a0,a1,a2,…,an-1的有限序列。 线性表的顺序存储结构:在计算机中用一组地址连续的存储单元依次存储线性表的各个数据元素,称作线性表的顺序存储结构。 线性表的链式存储结构:线性表的链式存储结构就是用一组任意的存储单元——结点(可以是不连续的)存储线性表的数据元素。表中每一个数据元素,都由存放数据元素值的数据域和存放直接前驱或直接后继结点的地址(指针)的指针域组成。
循环链表:循环链表(Circular Linked List)是将单链表的表中最后一个结点指针指向链表的表头结点,整个链表形成一个环,从表中任一结点出发都可找到表中其他的结点。 双向链表:双向链表中,在每一个结点除了数据域外,还包含两个指针域,一个指针(next)指向该结点的后继结点,另一个指针(prior)指向它的前驱结点。 除上述基本概念以外,学生还应该了解:线性表的基本操作(初始化、插入、删除、存取、复制、合并)、顺序存储结构的表示、线性表的链式存储结构的表示、一元多项式Pn(x),Josephus问题。