第2章 线性表 丽水学院工学院.

Slides:



Advertisements
Similar presentations
数据结构概论 第2章 线性表 董黎刚 浙江工商大学信电学院
Advertisements

第三章 鏈結串列 Linked List.
第二章 线性表 £2.4 线性表的应用 £2.1 线性表的类型定义 £2.2 线性表的顺序存储结构 £2.3 线性表的链式存储结构
第二章 线性表 2.1 线性表的逻辑结构 一. 线性表定义如下:
第二章 线性表 ⒈教学内容:2.1 线性表逻辑结构; 2.2 线性表的顺序存储及运算实现; 2.3 线性表的链式存储和实现。
第二章 线性表.
第2章 线性表 2.1 线性表的概念及运算 2.2 线性表的顺序存储 2.3 线性表的链式存储 2.4 一元多项式的表示及相加.
第2章 线性表 线性结构 是一个数据元素的有序集合。.
其他类型的链表主要内容 静态链表 循环链表 双向链表.
计算机软件技术基础 数据结构与算法(2).
第三章 栈和队列 Stack and Queue
第二章 线性表 线性表 顺序表 链表 顺序表与链表的比较.
数 据 结 构 Ch.2 线性表 计 算 机 学 院 肖明军
第三章 线性表 3.1 线性表的类型定义 3.2 顺序存储的线性表 3.3 链式存储的线性表 3.4 有序表 3.5 顺序表和链表的综合比较.
线性表 顺序表 单链表 循环链表 双向链表 多项式
第2章 线性表(三) 1/.
数据结构 第二章 线性表.
制作:崔广才
数据结构 Data Structure 中南大学 主讲人:王国军,郑瑾 中南大学信息院计科系
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
第2章 线性表 2.1 线性表的基本概念 2.2 线性表的顺序存储 2.3 线性表的链式存储 2.4 线性表的应用 2.5 有序表 本章小结.
本 章 说 明 2.1 线性表的类型定义 2.2 线性表的顺序表示和实现 2.3 线性表的链式存储结构 2.4 循环链表和双向链
辅导课程六.
西安交通大学计教中心 ctec.xjtu.edu.cn
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
第 1 章 数据结构 1.1 基本数据结构与算法 1.2 线性表 1.3 栈和队列 1.4 树和二叉树 1.5 查找 1.6 内部排序 65
第2章 线性表 2.1 线性表 2.2 顺序表 2.3 单链表 2.4 循环单链表 2.5 双向链表 2.6 仿真链表
第2章 线性表 2.1 线性表的类型定义 2.2 线性表的顺序表示和实现 2.3 线性表的链式表示和实现 2.4 一元多项式的表示.
线性表是一种最简单的线性结构 线性结构的基本特征为: 线性结构 是 一个数据元素的有序(次序)集 1.集合中必存在唯一的一个“第一元素”;
第 3 讲 线性表(一).
第二章 线性表.
内容回顾 线性表的定义和特点 线性表的顺序存储及查找、插入和删除.
第二章 线性表 2.1 线性表的类型定义 2.2线性表的顺序存储 2.3线性表的链式存储 2.4一元多项式的表示和相加.
(知识点三) 2.3 线性表的链式表示和实现 本节将介绍线性表的另一存储结构—— 链式存储及其对应的操作。
线性表练习.
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
cn/~dongeliu/dsa.html 刘 东 信息学院6系 中国科学技术大学
第四讲 线性表(三) 1/.
顺序表的插入.
王玲 第 2 章 线性表 王玲 2019/2/25.
第2章 线性表 本章主要介绍下列内容 线性表的定义和基本操作 线性表的顺序存储结构 线性表的链式存储结构 线性表的应用举例.
第二章 线性表.
3.1 线性表及逻辑结构 3.2 线性表的顺序存储 3.3 线性表的链式存储 3.4 链式存储结构的应用
严蔚敏、吴伟民编著 清华大学出版社 学习网站:中国网页设计
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
顺序表的删除.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
单链表的基本概念.
顺序查找.
线性结构 线性结构的特点: 线性结构的种类 在数据元素的非空有限集中, (1)存在唯一的一个被称做“第一个”的数据元素;
第 四 讲 线性表(二).
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
第二章 线性表.
第三章 数据组织与处理.
3.16 枚举算法及其程序实现 ——数组的作用.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
第七讲 栈和队列(二) 1/.
第三章 线性表 3.1 线性表的类型定义 3.2 顺序存储的线性表 3.3 链式存储的线性表 3.4 有序表 3.5 顺序表和链表的综合比较.
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
西安交通大学计教中心 ctec.xjtu.edu.cn
算法3.3 void InitList_sq(SqList &L,int msize=LIST_INIT_SIZE)
插入排序的正确性证明 以及各种改进方法.
第二章 线性表 线性表是一种最简单的线性结构 线性结构是一个数据元素的有序(次序)集.
第二部分 数据结构—— 用面向对象方法与C++描述.
第二章 线性表 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
Presentation transcript:

第2章 线性表 丽水学院工学院

第2章 线性表 第3章 栈和队列 第4章 串、数组和广义表 线性结构 近5周 上课 内容 线性结构的定义: 第2章 线性表 第3章 栈和队列 第4章 串、数组和广义表 线性结构 近5周 上课 内容 (逻辑、存储和运算) 线性结构的定义: 若结构是非空有限集,则有且仅有一个开始结点和一个终端结点,并且所有结点都最多只有一个直接前趋和一个直接后继。 可表示为:(a1 , a2 , ……, an) 丽水学院工学院

简言之,线性结构反映结点间的逻辑关系是 一对一 的 线性结构表达式:(a1 , a2 , ……, an) 线性结构的特点: ① 只有一个首结点和尾结点; ② 除首尾结点外,其他结点只有一个直接前驱和一个直接后继。 简言之,线性结构反映结点间的逻辑关系是 一对一 的 线性结构包括线性表、堆栈、队列、字符串、数组等等,其中,最典型、最常用的是 线性表 丽水学院工学院

教学目标 第2章 线性表 1. 了解线性结构的特点 2.掌握顺序表的定义、查找、插入和删除 3.掌握链表的定义、创建、查找、插入和删除 第2章 线性表 教学目标 1. 了解线性结构的特点 2.掌握顺序表的定义、查找、插入和删除 3.掌握链表的定义、创建、查找、插入和删除 4.能够从时间和空间复杂度的角度比较两种存储结构的不同特点及其适用场合 丽水学院工学院

教学内容 2.1 线性表的定义和特点 2.2 案例引入 2.3 线性的类型定义 2.4 线性表的顺序表示和实现 2.2 案例引入 2.3 线性的类型定义 2.4 线性表的顺序表示和实现 2.5 线性表的链式表示和实现 2.6 顺序表和链表的比较 2.7 线性表的应用 2.8 案例分析与实现 丽水学院工学院

2.1 线性表的定义和特点 (a1, a2, … ai-1,ai, ai+1 ,…, an) 线性表的定义:用数据元素的有限序列表示 空表 线性起点 ai的直接前趋 ai的直接后继 线性终点 n为元素总个数,即表长 下标,是元素的序号,表示元素在表中的位置 空表 n=0时称为 丽水学院工学院

数据元素都是字母; 元素间关系是线性 数据元素都是记录; 元素间关系是线性 同一线性表中的元素必定具有相同特性 例1 分析26 个英文字母组成的英文表 ( A, B, C, D, …… , Z) 数据元素都是字母; 元素间关系是线性 例2 分析学生情况登记表 学号 姓名 性别 年龄 班级 041810205 于春梅 女 18 04级计算机1班 041810260 何仕鹏 男 20 04级计算机2班 041810284 王 爽 19 04级计算机3班 041810360 王亚武 04级计算机4班 : 数据元素都是记录; 元素间关系是线性 同一线性表中的元素必定具有相同特性 丽水学院工学院

2.2 案例引入 案例2.1 :一元多项式的运算 Pn(x) = p0 + p1x + p2x2 + … + pnxn 线性表P = (p0,p1,p2,…,pn) 数组表示 (每一项的指数i隐含在其系数pi的序号中) P(x) = 10 + 5x - 4x2 + 3x3 + 2x4 指数 (下标i) 1 2 3 4 系数p[i] 10 5 -4 丽水学院工学院

Rn(x) = Pn(x) + Qm(x) 稀疏多项式S(x) = 1 + 3x10000 + 2x20000 丽水学院工学院 线性表R = (p0 + q0,p1 + q1,p2 + q2,…,pm + qm,pm+1,…,pn) 稀疏多项式S(x) = 1 + 3x10000 + 2x20000 丽水学院工学院

线性表P =((p1, e1), (p2, e2),…,(pm, em)) 案例2.2 :稀疏多项式的运算 多项式非零项的数组表示 (a)A(x) = 7 + 3x + 9x8 + 5x17 (b)B(x) = 8x + 22x7 − 9x8 下标i 1 2 3 系数a[i] 7 9 5 系数 b[i] 8 22 -9 指数 17 线性表P =((p1, e1), (p2, e2),…,(pm, em)) 创建一个新数组c 分别从头遍历比较a和b的每一项 指数相同,对应系数相加,若其和不为零,则在c中增加一个新项 指数不相同,则将指数较小的项复制到c中 一个多项式已遍历完毕时,将另一个剩余项依次复制到c中即可 北京林业大学信息学院

链式存储结构 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb 顺序存储结构存在问题 存储空间分配不灵活 运算的空间复杂度高 链式存储结构 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 -1 7 3 1 9 8 5 17 22 -9 A B pa pb 丽水学院工学院

多项式相加 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb A -1 7 3 1 3 1 9 8 5 17 B -1 8 1 22 7 -9 8 pb 丽水学院工学院

多项式相加 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb A -1 7 11 1 11 1 9 8 5 17 B -1 8 1 22 7 -9 8 pb 丽水学院工学院

多项式相加 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb A -1 7 11 1 11 1 9 8 5 17 B -1 8 1 22 7 -9 8 pb 丽水学院工学院

多项式相加 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb A -1 7 11 1 11 1 9 8 5 17 B -1 8 1 22 7 -9 8 pb 丽水学院工学院

案例2.3 :图书信息管理系统 (1)查找 (2)插入 (3)删除 (4)修改 (5)排序 (6)计数 丽水学院工学院

图书顺序表 图书链表 丽水学院工学院

丽水学院工学院 线性表中数据元素的类型可以为简单类型,也可以为复杂类型。 许多实际应用问题所涉的基本操作有很大相似性,不应为每个具体应用单独编写一个程序。 从具体应用中抽象出共性的逻辑结构和基本操作(抽象数据类型),然后实现其存储结构和基本操作。 丽水学院工学院

2.3 线性表的类型定义 线性表的重要基本操作 1. 初始化 2. 取值 3. 查找 4. 插入 5. 删除 丽水学院工学院

2.4 线性表的顺序表示和实现 线性表的顺序表示又称为顺序存储结构或顺序映像。 顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。 简言之,逻辑上相邻,物理上也相邻 顺序存储方法:用一组地址连续的存储单元依次存储线性表的元素,可通过数组V[n]来实现。 丽水学院工学院

顺序存储 丽水学院工学院 元素n …….. 元素i 元素2 元素1 Lo Lo+m Lo+(i-1)*m Lo+(n-1)*m 存储地址 存储内容 Loc(元素i)=Lo+(i-1)*m 顺序存储 丽水学院工学院

顺序表的类型定义 丽水学院工学院 #define MAXSIZE 100 //最大长度 typedef struct { ElemType *elem; //指向数据元素的基地址 int length; //线性表的当前长度 }SqList; 丽水学院工学院

图书表的顺序存储结构类型定义 丽水学院工学院 #define MAXSIZE 10000 //图书表可能达到的最大长度 typedef struct //图书信息定义 { char no[20]; //图书ISBN char name[50]; //图书名字 float price; //图书价格 }Book; typedef struct Book *elem; //存储空间的基地址 int length; //图书表中当前图书个数 }SqList; //图书表的顺序存储结构类型为SqList 丽水学院工学院

malloc(m):开辟m字节长度的地址空间,并返回这段空间的首地址 补充:C语言的动态分配函数( <stdlib.h> ) malloc(m):开辟m字节长度的地址空间,并返回这段空间的首地址   sizeof(x):计算变量x的长度 free(p):释放指针p所指变量的存储空间,即彻底删除一个变量 丽水学院工学院

int *p1= new int; 或 int *p1 = new int[10]; 补充:C++的动态存储分配 new 类型名T(初值列表) 功能: 申请用于存放T类型对象的内存空间,并依初值列表赋以初值 结果值: 成功:T类型的指针,指向新分配的内存 失败:0(NULL) int *p1= new int; 或 int *p1 = new int[10]; delete 指针P 功能: 释放指针P所指向的内存。P必须是new操作的返回值 delete p1; 丽水学院工学院

线性表的重要基本操作 1. 初始化 2. 取值 3. 查找 4. 插入 5. 删除 丽水学院工学院

重要基本操作的算法实现 在进行函数调用时,在函数体内,对形参进行运算相当于对实参进行运算。 初始化线性表L (参数用引用) 丽水学院工学院 Status InitList_Sq(SqList &L){ //构造一个空的顺序表L L.elem=new ElemType[MAXSIZE]; //为顺序表分配空间 if(!L.elem) exit(OVERFLOW); //存储分配失败 L.length=0; //空表长度为0 return OK; } 丽水学院工学院

初始化线性表L (参数用指针) 丽水学院工学院 Status InitList_Sq(SqList *L){ //构造一个空的顺序表L L-> elem=new ElemType[MAXSIZE]; //为顺序表分配空间 if(! L-> elem) exit(OVERFLOW); //存储分配失败 L-> length=0; //空表长度为0 return OK; } L-> elem L-> length 丽水学院工学院

补充:几个简单基本操作的算法实现 销毁线性表L 清空线性表L 丽水学院工学院 void DestroyList(SqList &L) { if (L.elem) delete[]L.elem; //释放存储空间 } 清空线性表L void ClearList(SqList &L) { L.length=0; //将线性表的长度置为0 } 丽水学院工学院

补充:几个简单基本操作的算法实现 求线性表L的长度 判断线性表L是否为空 int IsEmpty(SqList L) { int GetLength(SqList L) { return (L.length); } 判断线性表L是否为空 int IsEmpty(SqList L) { if (L.length==0) return 1; else return 0; } 丽水学院工学院

线性表的重要基本操作 1. 初始化 2. 取值 3. 查找 4. 插入 5. 删除 丽水学院工学院

2. 取值(根据位置i获取相应位置数据元素的内容) 获取线性表L中的某个数据元素的内容 int GetElem(SqList L,int i,ElemType &e) {if (i<1||i>L.length) return ERROR; //判断i值是否合理,若不合理,返回ERROR e=L.elem[i-1]; //第i-1的单元存储着第i个数据 return OK; } 丽水学院工学院

顺序查找图示 查找 16 查找成功 3.查找(根据指定数据获取数据所在的位置) data 25 34 57 16 48 09 i 0 1 2 3 4 5 data 25 34 57 16 48 09 查找 16 i 25 34 57 16 48 09 i 25 34 57 16 48 09 i 25 34 57 16 48 09 i 查找成功 丽水学院工学院

3. 查找(根据指定数据获取数据所在的位置) data 25 34 57 16 48 查找 50 i 25 34 57 16 48 i 0 1 2 3 4 data 25 34 57 16 48 查找 50 i 25 34 57 16 48 i 25 34 57 16 48 i 25 34 57 16 48 i 25 34 57 16 48 查找失败 i 丽水学院工学院

3. 查找(根据指定数据获取数据所在的位置) 查找算法时间效率分析 ??? 在线性表L中查找值为e的数据元素 int LocateELem(SqList L,ElemType e) { for (i=0;i< L.length;i++) if (L.elem[i]==e) return i+1; return 0; } 查找算法时间效率分析 ??? 丽水学院工学院

4. 插入(插在第 i 个结点之前) 插第 4 个结点之前,移动 6-4+1 次 插在第 i 个结点之前,移动 n-i+1 次 2 3 4 5 6 7 8 9 25 12 47 89 36 14 25 12 47 89 36 14 25 12 47 89 36 14 25 12 47 89 36 14 25 12 47 99 89 36 14 99插入 插第 4 个结点之前,移动 6-4+1 次 插在第 i 个结点之前,移动 n-i+1 次 丽水学院工学院

【算法步骤】 丽水学院工学院 (1)判断插入位置i 是否合法(合法值为1≤i≤length+1)。 (2)判断顺序表的存储空间是否已满。 (4)将要插入的新元素e放入第i个位置。 (5)表长加1,插入成功返回OK。 丽水学院工学院

【算法描述】 4. 在线性表L中第i个数据元素之前插入数据元素e 丽水学院工学院 Status ListInsert_Sq(SqList &L,int i ,ElemType e){ if(i<1 || i>L.length+1) return ERROR; //i值不合法 if(L.length==MAXSIZE) return ERROR; //当前存储空间已满 for(j=L.length-1;j>=i-1;j--) L.elem[j+1]=L.elem[j]; //插入位置及之后的元素后移 L.elem[i-1]=e; //将新元素e放入第i个位置 ++L.length; //表长增1 return OK; } 丽水学院工学院

【算法分析】 算法时间主要耗费在移动元素的操作上 若插入在尾结点之后,则根本无需移动(特别快); 若插入在首结点之前,则表中元素全部后移(特别慢); 若要考虑在各种位置插入(共n+1种可能)的平均移动次数,该如何计算? 丽水学院工学院

5. 删除(删除第 i 个结点) 删除第 4 个结点,移动 6-4 次 删除第 i 个结点,移动 n-i 次 丽水学院工学院 1 2 3 4 7 8 9 25 12 47 89 36 14 25 12 47 36 14 25 12 47 36 14 25 12 47 36 14 删除 删除第 4 个结点,移动 6-4 次 删除第 i 个结点,移动 n-i 次 丽水学院工学院

【算法步骤】 (1)判断删除位置i 是否合法(合法值为1≤i≤L.length)。 (2)将欲删除的元素保留在e中。 (4)表长减1,删除成功返回OK。 丽水学院工学院

【算法描述】 5. 将线性表L中第i个数据元素删除 丽水学院工学院 Status ListDelete_Sq(SqList &L,int i){ if((i<1)||(i>L.length)) return ERROR; //i值不合法 for (j=i;j<=L.length-1;j++)    L.elem[j-1]=L.elem[j]; //被删除元素之后的元素前移 --L.length; //表长减1 return OK; } 丽水学院工学院

【算法分析】 算法时间主要耗费在移动元素的操作上 若删除尾结点,则根本无需移动(特别快); 若删除首结点,则表中n-1个元素全部前移(特别慢); 若要考虑在各种位置删除(共n种可能)的平均移动次数,该如何计算? 丽水学院工学院

显然,顺序表的空间复杂度S(n)=O(1) 查找、插入、删除算法的平均时间复杂度为    O(n) 显然,顺序表的空间复杂度S(n)=O(1) (没有占用辅助空间) 丽水学院工学院

顺序表(顺序存储结构)的特点 (1)利用数据元素的存储位置表示线性表中相邻数据元素之间的前后关系,即线性表的逻辑结构与存储结构一致 (2)在访问线性表时,可以快速地计算出任何一个数据元素的存储地址。因此可以粗略地认为,访问每个元素所花时间相等   这种存取元素的方法被称为随机存取法 丽水学院工学院

链表 顺序表的优缺点 缺点: 在插入、删除某一元素时,需要移动大量元素 浪费存储空间 属于静态存储形式,数据元素的个数不能自由扩充 优点: 存储密度大(结点本身所占存储量/结点结构所占存储量) 可以随机存取表中任一元素 缺点: 在插入、删除某一元素时,需要移动大量元素 浪费存储空间 属于静态存储形式,数据元素的个数不能自由扩充 链表 为克服这一缺点 丽水学院工学院

2.5 线性表的链式表示和实现 链式存储结构 结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻 线性表的链式表示又称为非顺序映像或链式映像。 丽水学院工学院

单链表的存储映像 如何实现? 通过指针来实现 (a) 可利用存储空间 free free first (b) 经过一段运行后的单链表结构  free first (b) 经过一段运行后的单链表结构 丽水学院工学院

例 画出26 个英文字母表的链式存储结构 逻辑结构:( a, b, … ,y, z) 链式存储结构: a b z 丽水学院工学院 …… 例 画出26 个英文字母表的链式存储结构 逻辑结构:( a, b, … ,y, z) 链式存储结构: a head b /\ z …… 丽水学院工学院

指针 数据 各结点由两个域组成: 数据域:存储元素数值数据 指针域:存储直接后继结点的存储位置 丽水学院工学院

1、结点:数据元素的存储映像。由数据域和指针域两部分组成 与链式存储有关的术语 1、结点:数据元素的存储映像。由数据域和指针域两部分组成 2、链表: n 个结点由指针链组成一个链表。它是线性表的链式存储映像,称为线性表的链式存储结构 丽水学院工学院

单链表示意图: 3、单链表、双链表、循环链表: 结点只有一个指针域的链表,称为单链表或线性链表 a b z 丽水学院工学院 …… head /\ z …… 丽水学院工学院

3、单链表、双链表、循环链表: 有两个指针域的链表,称为双链表 双链表示意图: 丽水学院工学院

3、单链表、双链表、循环链表: 首尾相接的链表称为循环链表 循环链表示意图: 丽水学院工学院

4、头指针、头结点和首元结点 头指针 头结点 首元结点 头指针是指向链表中第一个结点的指针 首元结点是指链表中存储第一个数据元素a1的结点 head a2 … info an ^ 头指针是指向链表中第一个结点的指针 首元结点是指链表中存储第一个数据元素a1的结点 头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息 丽水学院工学院

上例链表的逻辑结构示意图有以下两种形式: ① ZHAO QIAN LI SUN ZHOU WU ZHENG /\ WANG H ② ZHAO QIAN LI SUN ZHOU WU ZHENG /\ WANG H 区别:① 无头结点 ② 有头结点 丽水学院工学院

有头结点时,当头结点的指针域为空时表示空表 讨论1. 如何表示空表? 有头结点时,当头结点的指针域为空时表示空表 非空表 空表 an a0 head ^ 表头结点 第一个结点 丽水学院工学院

首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无须进行特殊处理; 讨论2. 在链表中设置头结点有什么好处? ⒈便于首元结点的处理 首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无须进行特殊处理; ⒉便于空表和非空表的统一处理 无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一了。 丽水学院工学院

讨论3. 头结点的数据域内装的是什么? 头结点的数据域可以为空,也可存放线性表长度等附加信息,但此结点不能计入链表长度值。 H 头结点的数据域 丽水学院工学院

链表(链式存储结构)的特点 (1)结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻 (2)访问时只能通过头指针进入链表,并通过每个结点的指针域向后扫描其余结点,所以寻找第一个结点和最后一个结点所花费的时间不等  这种存取元素的方法被称为顺序存取法 丽水学院工学院

链表的优缺点 优点 数据元素的个数可以自由扩充 插入、删除等操作不必移动数据,只需修改链接指针,修改效率较高 丽水学院工学院

链表的优缺点 缺点 存储密度小 存取效率不高,必须采用顺序存取,即存取数据元素时,只能按链表的顺序进行访问(顺藤摸瓜) 丽水学院工学院

2.5.1 单链表的定义和实现 非空表 空表 单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名 若头指针名是L,则把链表称为表L 丽水学院工学院

单链表的存储结构定义 LNode *p LinkList p typedef struct LNode{ ElemType data; //数据域 struct LNode *next; //指针域 }LNode,*LinkList; // *LinkList为Lnode类型的指针 LNode *p LinkList p 丽水学院工学院

LNode *p 注意区分指针变量和结点变量两个不同的概念 指针变量p:表示结点地址 结点变量*p:表示一个结点 若p->data=ai, 则p->next->data=ai+1 丽水学院工学院

2.5.2 单链表基本操作的实现 1. 初始化 2. 取值 3. 查找 4. 插入 5. 删除 丽水学院工学院

1.初始化(构造一个空表 ) 【算法步骤】 (1)生成新结点作头结点,用头指针L指向头结点。 (2)头结点的指针域置空。 【算法描述】 Status InitList_L(LinkList &L){ L=new LNode; L->next=NULL;      return OK; } 丽水学院工学院

线性表的重要基本操作 1. 初始化 2. 取值 3. 查找 4. 插入 5. 删除 丽水学院工学院

2. 取值(根据位置i获取相应位置数据元素的内容) e=L.elem[i-1]; //第i-1的单元存储着第i个数据 链表的查找:要从链表的头指针出发,顺着链域next逐个结点往下搜索,直至搜索到第i个结点为止。 丽水学院工学院

例:分别取出表中i=3和i=15的元素 L i=3 i=15 21 18 30 75 42 56 ∧ p p p p p p j 6 7 2 3 1 1 从第1个结点(L->next)顺链扫描,用指针p指向当前扫描到的结点,p初值p = L->next。 j做计数器,累计当前扫描过的结点数,j初值为1。 当p=p->next指向扫描到的下一结点时,计数器j加1。 当j = i时,p所指的结点就是要找的第i个结点。\ 当p为空或j=i时,结束查找。 【算法步骤】 丽水学院工学院

2. 取值(根据位置i获取相应位置数据元素的内容) //获取线性表L中的某个数据元素的内容 Status GetElem_L(LinkList L,int i,ElemType &e){ p=L->next;j=1; //初始化 while(p&&j<i){ //向后扫描,直到p指向第i个元素或p为空 p=p->next; ++j; } if(!p || j>i)return ERROR; //第i个元素不存在 ,i>n或i<1 e=p->data; //取第i个元素 return OK; }//GetElem_L 丽水学院工学院

L 21 18 30 75 30 56 p p p p p p j 1 2 1 3 7 6 3.查找(根据指定数据获取数据所在的位置) x=30 x=51 21 18 30 75 30 56 ∧ p p p p p p j 1 2 1 3 7 6 未找到,返回0 找到,返回i 从第一个结点起,依次和e相比较。 如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”或地址; 如果查遍整个链表都没有找到其值和e相等的元素,则返回0或“NULL”。 丽水学院工学院

【算法描述】 //在线性表L中查找值为e的数据元素 int LocateELem_L (LinkList L,Elemtype e) { p=L->next; j=1; while(p &&p->data!=e) {p=p->next; j++;} if(p) return j; else return 0; } 丽水学院工学院

【算法描述】 //在线性表L中查找值为e的数据元素 LNode *LocateELem_L (LinkList L,Elemtype e) { //返回L中值为e的数据元素的地址,查找失败返回NULL p=L->next; while(p &&p->data!=e) p=p->next; return p; } 丽水学院工学院

s->next=p->next; p->next=s 3. 插入(插在第 i 个结点之前) 将值为x的新结点插入到表的第i个结点的位置上,即插入到ai-1与ai之间 s->next=p->next; p->next=s 思考:步骤1和2能互换么? 丽水学院工学院

【算法步骤】 (1)找到ai-1存储位置p (2)生成一个新结点*s (3)将新结点*s的数据域置为x (4)新结点*s的指针域指向结点ai 04:18 丽水学院工学院

【算法描述】 //在L中第i个元素之前插入数据元素e 丽水学院工学院 Status ListInsert_L(LinkList &L,int i,ElemType e){ p=L;j=0; while(p&&j<i−1){p=p->next;++j;} //寻找第i−1个结点 if(!p||j>i−1)return ERROR; //i>n+1或i<1 s=new LNode; //生成新结点s s->data=e; //将结点s的数据域置为e s->next=p->next; //将结点s插入L中 p->next=s; return OK; }//ListInsert_L 丽水学院工学院

(3)令p->next指向ai的直接后继结点 (4)释放结点ai的空间 步骤: (1)找到ai-1存储位置p (2)保存要删除的结点的值 (3)令p->next指向ai的直接后继结点 (4)释放结点ai的空间 丽水学院工学院

p->next = q->next ??? 5. 删除(删除第 i 个结点)  ai-1  ai ai+1 删除前  ai-1 ai ai+1  p q 删除后 p->next = q->next ??? 丽水学院工学院

【算法步骤】 (1)找到ai-1存储位置p (2)临时保存结点ai的地址在q中,以备释放 (3)令p->next指向ai的直接后继结点 (4)将ai的值保留在e中 (5)释放ai的空间

【算法描述】 //将线性表L中第i个数据元素删除 Status ListDelete_L(LinkList &L,int i,ElemType &e){ p=L;j=0; while(p->next &&j<i-1){//寻找第i个结点,并令p指向其前驱 p=p->next; ++j; } if(!(p->next)||j>i-1) return ERROR; //i>n或i<1删除,位置不合理 q=p->next; //临时保存被删结点的地址以备释放 p->next=q->next; //改变删除结点前驱结点的指针域 e=q->data; //保存删除结点的数据域 delete q; //释放删除结点的空间 return OK; }//ListDelete_L

链表的运算时间效率分析 1. 查找: 因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间复杂度为 O(n)。 丽水学院工学院

单链表的建立(前插法) 从一个空表开始,重复读入数据: 生成新结点 将读入数据存放到新结点的数据域中 将该新结点插入到链表的前端 丽水学院工学院

p->data=an p->data=an-1 单链表的建立(前插法) p->next= L->next L->next=p p->next= L->next p->data=an p->data=an-1 丽水学院工学院

【算法描述】 void CreateList_F(LinkList &L,int n){ L=new LNode; L->next=NULL; //先建立一个带头结点的单链表 for(i=n;i>0;--i){ p=new LNode; //生成新结点 cin>>p->data; //输入元素值 p->next=L->next;L->next=p; //插入到表头 } }//CreateList_F 丽水学院工学院

单链表的建立(尾插法) 丽水学院工学院 从一个空表L开始,将新结点逐个插入到链表的尾部,尾指针r指向链表的尾结点。 初始时,r同L均指向头结点。每读入一个数据元素则申请一个新结点,将新结点插入到尾结点后,r指向新结点。 丽水学院工学院

【算法描述】 丽水学院工学院 void CreateList_L(LinkList &L,int n){ //正位序输入n个元素的值,建立带表头结点的单链表L L=new LNode; L->next=NULL; r=L; //尾指针r指向头结点 for(i=0;i<n;++i){ p=new LNode;   //生成新结点 cin>>p->data; //输入元素值 p->next=NULL; r->next=p; //插入到表尾 r=p; //r指向新的尾结点 } }//CreateList_L 丽水学院工学院

2.6 顺序表和链表的比较 存储结构 比较项目 顺序表 链表 空间 存储空间 预先分配,会导致空间闲置 或溢出现象 预先分配,会导致空间闲置 或溢出现象 动态分配,不会出现存储 空间闲置或溢出现象 存储密度 不用为表示结点间的逻辑关 系而增加额外的存储开销, 存储密度等于1 需要借助指针来体现元素 间的逻辑关系,存储密度 小于1 时间 存取元素 随机存取,按位置访问元素 的时间复杂度为O(1) 顺序存取,按位置访问元 素时间复杂度为O(n) 插入、删除 平均移动约表中一半元素, 时间复杂度为O(n) 不需移动元素,确定插入、 删除位置后,时间复杂度 为O(1) 适用情况 ① 表长变化不大,且能事先 确定变化的范围 ② 很少进行插入或删除操作, 经常按元素位置序号访问数 据元素 ① 长度变化较大 ② 频繁进行插入或删除操 作

2.7 线性表的应用 线性表的合并 有序表的合并 1 2 丽水学院工学院

2.7.1 线性表的合并 问题描述: 假设利用两个线性表La和Lb分别表示两个集合A和B,现要求一个新的集合 A=AB 2.7.1  线性表的合并 问题描述: 假设利用两个线性表La和Lb分别表示两个集合A和B,现要求一个新的集合 A=AB La=(7, 5, 3, 11) Lb=(2, 6, 3) La=(7, 5, 3, 11, 2, 6) . 丽水学院工学院

【算法步骤】 依次取出Lb 中的每个元素,执行以下操作:  在La中查找该元素  如果找不到,则将其插入La的最后 丽水学院工学院

【算法描述】 void union(List &La, List Lb){ //求线性表的长度 La_len=ListLength(La); Lb_len=ListLength(Lb); //依次取LB中第i个数据元素赋给e for(i=1;i<=Lb_len;i++){ GetElem(Lb,i,e); //如果LA中不存在和e相同的数据元素,则插入之 if(!LocateElem(La,e)) ListInsert(&La,++La_len,e); }} 丽水学院工学院

【算法描述】 void union(List &La, List Lb){ //求线性表的长度…… //依次取LB中第i个数据元素赋给e for(i=1;i<=Lb_len;i++){ GetElem(Lb,i,e); //如果LA中不存在和e相同的数据元素,则插入之 if(!LocateElem(La,e)) ……} } 丽水学院工学院

2.7.2  有序表的合并 问题描述: 已知线性表La和Lb中的数据元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列。 La=(1 ,7, 8) Lb=(2, 4, 6, 8, 10, 11) Lc=(1, 2, 4, 6, 7 , 8, 8, 10, 11) . 丽水学院工学院

【算法步骤】-有序的顺序表合并 (1) 创建一个空表Lc; (2) 依次从 La 或 Lb 中“摘取”元素值较小的结点插入到 Lc 表的最后,直至其中一个表变空为止; (3) 继续将 La 或 Lb 其中一个表的剩余结点插入在 Lc 表的最后。 丽水学院工学院

【算法描述】-有序的顺序表合并 丽水学院工学院 void MergeList_Sq(SqList LA,SqList LB,SqList &LC){ //指针pa和pb的初值分别指向两个表的第一个元素 pa=LA.elem; pb=LB.elem; //新表长度为待合并两表的长度之和 LC.length=LA.length+LB.length; //为合并后的新表分配一个数组空间 LC.elem=new ElemType[LC.length]; //指针pc指向新表的第一个元素 pc=LC.elem; //指针pa_last指向LA表的最后一个元素 pa_last=LA.elem+LA.length-1; //指针pb_last指向LB表的最后一个元素 pb_last=LB.elem+LB.length-1; 丽水学院工学院

【算法描述】-有序的顺序表合并 T(n)= 丽水学院工学院 S(n)= O(n) //两个表都非空 while(pa<=pa_last && pb<=pb_last) //依次“摘取”两表中值较小的结点 { if(*pa<=*pb) *pc++=*pa++; else *pc++=*pb++; } //LB表已到达表尾 while(pa<=pa_last) *pc++=*pa++; //LA表已到达表尾 while(pb<=pb_last) *pc++=*pb++; }//MergeList_Sq T(n)= S(n)= O(n) 丽水学院工学院

要求结果链表仍使用原来两个链表的存储空间, 不另外占用其它的存储空间。 有序链表合并--重点掌握 将两个有序链表合并成一个有序的单链表。 要求结果链表仍使用原来两个链表的存储空间, 不另外占用其它的存储空间。 表中允许有重复的数据。 丽水学院工学院

有序链表合并--重点掌握 La Lb La 合并后 丽水学院工学院 1 7 8 2 4 6 8 10 11 1 2 4 6 7 8 10

【算法步骤】-有序的链表合并 (1)Lc指向La (2) 依次从 La 或 Lb 中“摘取”元素值较小的结点插入到 Lc 表的最后,直至其中一个表变空为止 (3) 继续将 La 或 Lb 其中一个表的剩余结点插入在 Lc 表的最后 (4) 释放 Lb 表的表头结点 丽水学院工学院

有序链表合并(初始化) La 1 7 8 Lc = pc pa Lb 2 4 6 8 10 11 pb 丽水学院工学院

有序链表合并( pa->data < =pb->data ) La(Lc ,pc) 1 7 8 pa Lb 2 4 6 8 10 11 pb pc->next = pa; 丽水学院工学院

有序链表合并( pa->data < =pb->data ) La(Lc) 1 1 7 8 pc Pa Lb 2 4 6 8 10 11 pb pc->next = pa; pc= pa; 丽水学院工学院

有序链表合并( pa->data < =pb->data ) La(Lc) 1 1 7 8 pc pa = pa->next; pa Lb 2 4 6 8 10 11 pb pc->next = pa; pc= pa; 丽水学院工学院

有序链表合并( pa->data >pb->data ) La(Lc) 1 1 7 8 pc pa Lb 2 4 6 8 10 11 pb pc->next = pb; 丽水学院工学院

有序链表合并( pa->data >pb->data ) La(Lc) 1 1 7 8 pa Lb 2 2 4 6 8 10 11 pc pc= pb; pb pc->next = pb; 丽水学院工学院

有序链表合并( pa->data >pb->data ) La(Lc) 1 1 7 8 pa Lb 2 2 4 6 8 10 11 pc pc= pb; pb =pb->next; pb pc->next = pb; 丽水学院工学院

pc-> next=pa?pa:pb; 有序链表合并 La(Lc) 1 7 8 pa(NULL) 2 4 6 8 10 11 pc pb pc-> next=pa?pa:pb; 丽水学院工学院

有序链表合并 合并后 La(Lc) 1 7 8 delete Lb; 2 4 6 8 10 11 丽水学院工学院

【算法描述】-有序的链表合并 丽水学院工学院 void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc) { //pa和pb的初值分别指向两个表的第一个结点 pa=La->next; pb=Lb->next; //用LA的头结点作为LC的头结点 LC = LA; //pc的初值指向LC的头结点 pc = LC; …… 丽水学院工学院

【算法描述】-有序的链表合并 丽水学院工学院 void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc){ …… //两个表都非空 while(pa && pb){ //依次"摘取"两表中值较小的结点插入到LC表的最后 if(pa->data<=pb->data) {//将pa所指结点链接到pc所指结点之后 pc->next=pa;pc=pa;pa=pa->next;} //将pb所指结点链接到pc所指结点之后 else{pc->next=pb; pc=pb; pb=pb->next;} 丽水学院工学院

【算法描述】-有序的链表合并 丽水学院工学院 void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc){ …… //插入剩余段 pc->next=pa?pa:pb; //释放Lb的头结点 delete Lb; } T(n)= S(n)= O(1) 丽水学院工学院

思考1:要求合并后的表无重复数据,如何实现? La(Lc) 1 7 8 2 4 6 8 10 11 提示:要单独考虑 pa->data = =pb->data 丽水学院工学院

2.8 案例分析与实现 案例2.1 :一元多项式的运算 P(x) = 10 + 5x - 4x2 + 3x3 + 2x4 10 5 -4 数组表示 (每一项的指数i隐含在其系数pi的序号中) P(x) = 10 + 5x - 4x2 + 3x3 + 2x4 指数 (下标i) 1 2 3 4 系数p[i] 10 5 -4 Rn(x) = Pn(x) + Qm(x) 线性表R = (p0 + q0,p1 + q1,p2 + q2,…,pm + qm,pm+1,…,pn) 丽水学院工学院

线性表P =((p1, e1), (p2, e2),…,(pm, em)) 案例2.2 :稀疏多项式的运算 多项式非零项的数组表示 (a)A(x) = 7 + 3x + 9x8 + 5x17 (b)B(x) = 8x + 22x7 − 9x8 下标i 1 2 3 系数a[i] 7 9 5 系数 b[i] 8 22 -9 指数 17 线性表P =((p1, e1), (p2, e2),…,(pm, em)) 创建一个新数组c 分别从头遍历比较a和b的每一项 指数相同,对应系数相加,若其和不为零,则在c中增加一个新项 指数不相同,则将指数较小的项复制到c中 一个多项式已遍历完毕时,将另一个剩余项依次复制到c中即可

链式存储结构 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 顺序存储结构存在问题 存储空间分配不灵活 运算的空间复杂度高 链式存储结构 typedef struct PNode { float coef;//系数 int expn; //指数 struct PNode *next; //指针域 }PNode,*Polynomial;   A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 -1 7 3 1 9 8 5 17 22 -9 A B 丽水学院工学院

多项式创建---【算法步骤】 丽水学院工学院 ① 创建一个只有头结点的空链表。 ② 根据多项式的项的个数n,循环n次执行以下操作: 生成一个新结点*s; 输入多项式当前项的系数和指数赋给新结点*s的数据域; 设置一前驱指针pre,用于指向待找到的第一个大于输入项指数的结点的前驱,pre初值指向头结点; 指针q初始化,指向首元结点; 循链向下逐个比较链表中当前结点与输入项指数,找到第一个大于输入项指数的结点*q; 将输入项结点*s插入到结点*q之前。 丽水学院工学院

多项式创建---【算法描述】 丽水学院工学院 void CreatePolyn(Polynomial &P,int n) {//输入m项的系数和指数,建立表示多项式的有序链表P //先建立一个带头结点的单链表 P=new PNode; P->next=NULL; //依次输入n个非零项 for(i=1;i<=n;++i){ //生成新结点 s=new PNode; //输入系数和指数 cin>>s->coef>>s->expn; //pre用于保存q的前驱,初值为头结点 pre=P; //q初始化,指向首元结点 q=P->next; } 丽水学院工学院

多项式创建---【算法描述】 丽水学院工学院 void CreatePolyn(Polynomial &P,int n) { //输入m项的系数和指数,建立表示多项式的有序链表P …… //找到第一个大于输入项指数的项*q while(q&&q->expn<s->expn) { pre=q; q=q->next; } //while //将输入项s插入到q和其前驱结点pre之间 s->next=q; pre->next=s; } //for } 丽水学院工学院

A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb -1 7 3 1 9 8 5 17 3 1 9 8 5 17 22 -9 A B pa pb 丽水学院工学院

多项式相加 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb A -1 7 3 1 3 1 9 8 5 17 B -1 8 1 22 7 -9 8 pb 丽水学院工学院

多项式相加 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb A -1 7 11 1 11 1 9 8 5 17 B -1 8 1 22 7 -9 8 pb 丽水学院工学院

多项式相加 A17(x)=7+3x+9x8+5x17 B8(x)=8x+22x7-9x8 丽水学院工学院 pa pb A -1 7 11 1 11 1 9 8 5 17 B -1 8 1 22 7 -9 8 pb 丽水学院工学院

A17(x) = 7 + 3x + 9x8 + 5x17 B8(x) = 8x + 22x7 − 9x8 丽水学院工学院

多项式相加---【算法步骤】 丽水学院工学院 ① 指针p1和p2初始化,分别指向Pa和Pb的首元结点。 ③ 当指针p1和p2均未到达相应表尾时,则循环比较p1和p2所指结点对应的指数值(p1->expn与p2->expn),有下列3种情况: 当p1->expn等于p2->expn时,则将两个结点中的系数相加,若和不为零,则修改p1所指结点的系数值,同时删除p2所指结点,若和为零,则删除p1和p2所指结点; 当p1->expn小于p2->expn时,则应摘取p1所指结点插入到“和多项式”链表中去; 当p1->expn大于p2->expn时,则应摘取p2所指结点插入到“和多项式”链表中去。 ④ 将非空多项式的剩余段插入到p3所指结点之后。 ⑤ 释放Pb的头结点。 丽水学院工学院

小结 问1:线性表的逻辑结构特点是什么?其顺序存储结构和链式存储结构的特点是什么? 答: 线性表逻辑结构特点是,只有一个首结点和尾结点;除首尾结点外其他结点只有一个直接前驱和一个直接后继。简言之,线性结构反映结点间的逻辑关系是一对一(1:1)的。 顺序存储时,相邻数据元素的存放地址也相邻(逻辑与物理统一);要求内存中可用存储单元的地址必须是连续的。 链式存储时,相邻数据元素可随意存放,但所占存储空间分两部分,一部分存放结点值,另一部分存放表示结点间关系的指针。

小结 问2:顺序存储和链式存储各有哪些优缺点? 答: 顺序存储的优点是存储密度大(=1),存储空间利用率高。缺点是插入或删除元素时不方便。 链式存储的优点是插入或删除元素时很方便,使用灵活。缺点是存储密度小(<1),存储空间利用率低。 事实上,链表插入、删除运算的快捷是以空间代价来换取时间。

问3:在什么情况下用顺序表比链表好? 答: 顺序表适宜于做查找这样的静态操作;链表宜于做插入、删除这样的动态操作。 若线性表的长度变化不大,且其主要操作是查找,则采用顺序表; 若线性表的长度变化较大,且其主要操作是插入、删除操作,则采用链表。