第2章 线性表
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第4页
§2.1 线性表的基本概念
InsElem(sq, x, i) 初始条件:sq已经存在,1≤i≤GetLength(sq)+1 操作结果:在sq中第i个位置插入x (1,2,3,4,5,6,7,8) DelElem(sq, i) 初始条件:sq已经存在,1≤i≤GetLength(sq) 操作结果:删除sq中第i个位置的元素 DispList(sq) 初始条件:sq已经存在 操作结果:按照先后顺序输出线性表sq中的所有元素
data
next
第24页
§2.3 链式存储结构
§2.2 线性表的存储结构
(6)删除元素 int DelElem (SqList &sq, int i) { //删除线性表中第i个元素 //删除成功表长减1,并返回1;否则返回0 int j; if ( i<1 || i>sq.len) return 0; for (j=i; j<sq.len; j++) sq.data[j-1] = sq.data[j]; sq.len--; return 1; }
因此插入算法的平均时间复杂度为O(n)
第18页
§2.2 线性表的存储结构
(a1,a2,a3,a4,a5,a6,a7) 删除算法DelElem()分析 结点移动的次数也和表长n及删除结点位置i有关 当i=n时,移动次数为0,最小值 当i=1时,移动次数为n-1,最大值 线性表中共有n个结点可以被删除,假设在每个结点 删除的概率相等为pi=1/n,则在长度为n的线性表中 删除一个结点时所需移动结点的平均次数为:
因此删除算法的平均时间复杂度为O(n)
第19页
§2.2 线性表的存储结构
顺序表小结 特点:逻辑关系上相邻的两个元素在物理位置上也相 邻。 优点: 1)简单,节省存储空间 2)可以随机存取表中任一个元素 缺点: 1)插入、删除时需要移动大量元素,效率较低 2)时间复杂度不是十分理想O(n) *应用:适合于一旦建立就不经常进行增删元素的数 据表(静态数据表)的快速查找。 对于元素个数需要经常变化的动态数据表,顺序表的 效率会明显降低。
L a b c d e f Λ
头结点:可以不存储任何信息,也可以存储如线性表的长度之类 的信息。带头结点的单链表能够简化运算的实现过程。 L指向头结点,当头结点的指针域值为空(L->next=NULL)时, 表示表长为0
第23页
§2.3 链式存储结构
单链表的类型定义
typedef struct node { ElemType data; //数据域 struct node *next; //指针域 } SLink;
void delete(SqList &A, SqList B) { int i, k; ElemType x; for(i=1; i<=GetLength(B); i++) { x = GetElem(B,i); k = Locate(A,x); if (k>0) DelElem(A, k); } }
SqList c d e f
第8页
§2.2 线性表的存储结构
顺序表中元素的地址计算 假定 1)存储一个ElemType类型的变量占用l(l≥1)个内存 单元; 2)存储线性表的数组的入口地址为b(数组的首地 址)。 结论 线性表中第i个元素的存储地址= b + (i - 1)×l 基本运算在顺序表中的实现 a 300 301 b (1)初始化线性表 302 c void InitList(SqList &sq) 303 d 304 e { //初始化线性表 305 f sq.len = 0; //将sq的len域置0
§2.2 线性表的存储结构
(4)按值查找 int Locate (SqList sq, ElemType x) { //查找sq中是否包含值为x的元素 //查找成功返回该元素所在位置,否则返回0 int i = 0; while (sq.data[i] != x && i<sq.len) i++; if (i >= sq.len) return 0; else return i+1; }
{ int i=0, j=A.len-1, k; ElemType temp; while(i<=j) { while(A.data[i]%2 == 0) i++; while(A.data[j]%2 == 1) j--; if (i<j) { temp = A.data[i]; A.data[i] = A.data[j]; A.data[j] = temp; } }
第12页
§2.2 线性表的存储结构
(5)插入元素 int InsElem (SqList &sq, ElemType x, int i) { //向线性表中第i个位置插入一个元素x //插入成功顺序表长度加1,并返回1;否则返回0 int j; if ( i<1 || i>sq.len+1) return 0; for (j=sq.len; j>=i; j--) sq.data[j] = sq.data[j-1]; sq.data[i-1] = x; sq.len++; return 1; } 第13页
第3页
§2.1 线性表的基本概念
线性表的基本运算
InitList(sq) 操作结果:构造一个空的线性表sq GetLength(sq) (1,2,3,4,5,6,7,8) 初始条件:sq已经存在 操作结果:返回sq的长度 GetElem(sq, i) 初始条件:sq已经存在,且1≤i≤GetLength(sq) 操作结果:返回sq中第i个元素的值 Locate(sq, x) 初始条件:sq已经存在 操作结果:返回sq中第一个和x值相同的元素的序号
第17页
§2.2 线性表的存储结构
(a1,a2,a3,a4,a5,a6,a7) 插入算法InsElem()分析 结点移动的次数和表长n有关,还和插入位置i有关 当i=n+1时,移动次数为0,最小值 当i=1时,移动次数为n,最大值 线性表中共有n+1个可以插入元素的位置,假设在每 个位置上插入的概率相等为pi=1/(n+1),则在长度为 的线性表中插入一个结点时所需移动结点的平均次数 为:
《算法与数据结构》
第2章 线性表
主讲人:黄伯虎
§2.1 线性表的基本概念
线性表(linear_list)定义
最常用最简单的一种数据结构。是一个由n个数据元素 组成的有穷序列。 形式: (a1, a2, a3 … ai … an)
数据元素,可以拥有不同的 含义 ,但是同一线性表中的 数据元素应具有相同含义。 a1为起始元素 an为终端元素 举例:(1,2,3,4,5,6,7,8)
data next
其中data为数据域,用于存储线性表元素值 next为指针域(链域),用于存放该结点直接后继结点 的地址 (a,b,c,d,e,f)
a b c d e f
a
b
c
d
e
f
Λ
第22页
§2.3 链式存储结构
单链表的分类
不带头结点的单链表
L a b c d e f Λ
L为头指针,指向表中第一个结点。L为空(L=NULL) 表示表长为0 带头结点的单链表
基本运算
通过以上基本运算可以实现更为复杂的运
第5页
线性表 复杂运算
§2.1 线性表的基本概念
举例:P12页例2.1 利用线性表的基本运算,编写在线性表A中删除线性表B中出现元素的算法 A (a1, a2, a3 … ai … an) B (b1, b2, b3 … bi … bn) 思路:依次检查B中的每一个元素,看是否在线性表A中存在值相同的元 素,若存在则从A中删除该元素。
第16页
}
§2.2 线性表的存储结构
顺序实现的算法分析(时间复杂度)
插入、删除操作是顺序表的主要运算,因此我们将对这 两种操作着重分析 一个合理的依据:移动为这类算法中的主要操作,在移 动结点上所花费的时间往往要比其它操作多很多(如条 件判断、算术表达式计算等),因此我们以结点的移动 作为基本的操作来分析算法的时间复杂度。
第20页
§2.3 链式存储结构
单链表
使用一组任意的存储单元存储线性表的数据元素,这组 存储单元可以是连续的,也可以是不连续的
?数据之间的关系如何表示 增加能存储逻辑关系信息的域 ?如何实现 指针
第21页
§2.3 链式存储结构
单链表的基本思想
使用一个指针来表示结点间的逻辑关系。其结点的形式 如下:
第7页
§2.2 线性表的存储结构
由于在高级程序设计语言中数组(如:int A[10])具有 连续的存储空间,且可以进行随机存取,符合顺序存储 的特征,因此程序设计时常用数组来描述数据结构中的 顺序存储结构。 C/C++语言中,顺序表描述如下: const int MAXSIZE=顺序表的容量 typedef struct { ElemType data[MAXSIZE]; //存放顺序表中的数 据元素 data len a int len; //顺序表的长度 6 b (a,b,c,d,e,f) }SqList;
第9页
§2.2 线性表的存储结构
值传递 实参将数据传递给形 参,实参和形参拥有各 自独立的存储空间,除 了值相同之外没有任何 联系,形参变量中值的 变化不会对实参变量产 生任何影响,形参不能 返回值,是一个局部变 量,函数调用结束后形 参随函数一起销毁。 地址传递 实参将地址值传递给形 参(是一个指针),实 参和形参指向同一个存 储空间,改变形参的值 实际上就是改变实参的 值,形参能够返回值, 是一个局部变量,函数 调用结束后形参随函数 一起销毁,但是其值则 保存了下来。 引用调用(C++)
百度文库
第6页
§2.2 线性表的存储结构
线性表的存储结构分两种:
顺序存储结构 链式存储结构
顺序存储结构(顺序表)
定义:是按照顺序存储方式构造的线性表 基本思想: 顺序表中的一个存储单元存储一个数据元素 以元素之间的排列顺序来表示元素之间的逻辑关系 (a,b,c,d,e,f)
a b c d e f
特点:逻辑结构中相邻的结点在存储结构中仍然相 邻,也就是说以元素在计算机内“物理位置”的相邻 来表示线性表中数据元素之间的逻辑关系。
原理同地址传递基本相 同,只是在概念上有区 别。 1. 引用是一种隐含的 指针,是一个别名 。 2. 指针操作语法复杂 ,而定义引用变量 后其操作方法和普 通变量相同。 3. 指针太灵活因此更 容易出错,使用引 用可以减少出错几 率。
第10页
§2.2 线性表的存储结构
(2)求线性表长度 int GetLength(SqList sq) { //求线性表的长度 return sq.len; //返回sq的len域值 } (3)求线性表中第i个元素 int GetElem(SqList sq, int i) { //输出线性表中第i个元素 //i有效时返回第i个元素,无效时返回0 if (i<1 || i>sq.len) return 0; else return sq.data[i-1]; } 第11页
第14页
§2.2 线性表的存储结构
(7)输出顺序表中各个元素的值 void DispList (SqList sq) { //依次输出各个元素的值 int i; for (i=1; i<=sq.len; i++) count << sq.data[i-1] << “ ”; cout << endl; }
表长:线性表中数据元素的个数 空表:表长为0的线性表,记做()或Ф
第2页
§2.1 线性表的基本概念
线性表的特征
元素(结点)个数L≥0 若L≥1 则: 除了起始结点和终端结点外的其它结点有且仅有一个 前驱结点和一个后继结点; 起始结点有且只有一个后继结点,无前驱; 终端结点有且只有一个前驱结点,无后继; (1,2,3,4,5,6,7,8)
第15页
§2.2 线性表的存储结构
举例: 例P17-2.4:已知线性表(a1, a2 … an)按顺序存储,且每个元素都是互不相等 的整数。设计把所有奇数移到所有的偶数前边的算法(要求时间最少,辅助 空间最少) 思路:从左向右找偶数data[i],从右向左找奇数data[j],然后交换两者位置, 直到i>j为止 void move(SqList &A)
§2.1 线性表的基本概念
InsElem(sq, x, i) 初始条件:sq已经存在,1≤i≤GetLength(sq)+1 操作结果:在sq中第i个位置插入x (1,2,3,4,5,6,7,8) DelElem(sq, i) 初始条件:sq已经存在,1≤i≤GetLength(sq) 操作结果:删除sq中第i个位置的元素 DispList(sq) 初始条件:sq已经存在 操作结果:按照先后顺序输出线性表sq中的所有元素
data
next
第24页
§2.3 链式存储结构
§2.2 线性表的存储结构
(6)删除元素 int DelElem (SqList &sq, int i) { //删除线性表中第i个元素 //删除成功表长减1,并返回1;否则返回0 int j; if ( i<1 || i>sq.len) return 0; for (j=i; j<sq.len; j++) sq.data[j-1] = sq.data[j]; sq.len--; return 1; }
因此插入算法的平均时间复杂度为O(n)
第18页
§2.2 线性表的存储结构
(a1,a2,a3,a4,a5,a6,a7) 删除算法DelElem()分析 结点移动的次数也和表长n及删除结点位置i有关 当i=n时,移动次数为0,最小值 当i=1时,移动次数为n-1,最大值 线性表中共有n个结点可以被删除,假设在每个结点 删除的概率相等为pi=1/n,则在长度为n的线性表中 删除一个结点时所需移动结点的平均次数为:
因此删除算法的平均时间复杂度为O(n)
第19页
§2.2 线性表的存储结构
顺序表小结 特点:逻辑关系上相邻的两个元素在物理位置上也相 邻。 优点: 1)简单,节省存储空间 2)可以随机存取表中任一个元素 缺点: 1)插入、删除时需要移动大量元素,效率较低 2)时间复杂度不是十分理想O(n) *应用:适合于一旦建立就不经常进行增删元素的数 据表(静态数据表)的快速查找。 对于元素个数需要经常变化的动态数据表,顺序表的 效率会明显降低。
L a b c d e f Λ
头结点:可以不存储任何信息,也可以存储如线性表的长度之类 的信息。带头结点的单链表能够简化运算的实现过程。 L指向头结点,当头结点的指针域值为空(L->next=NULL)时, 表示表长为0
第23页
§2.3 链式存储结构
单链表的类型定义
typedef struct node { ElemType data; //数据域 struct node *next; //指针域 } SLink;
void delete(SqList &A, SqList B) { int i, k; ElemType x; for(i=1; i<=GetLength(B); i++) { x = GetElem(B,i); k = Locate(A,x); if (k>0) DelElem(A, k); } }
SqList c d e f
第8页
§2.2 线性表的存储结构
顺序表中元素的地址计算 假定 1)存储一个ElemType类型的变量占用l(l≥1)个内存 单元; 2)存储线性表的数组的入口地址为b(数组的首地 址)。 结论 线性表中第i个元素的存储地址= b + (i - 1)×l 基本运算在顺序表中的实现 a 300 301 b (1)初始化线性表 302 c void InitList(SqList &sq) 303 d 304 e { //初始化线性表 305 f sq.len = 0; //将sq的len域置0
§2.2 线性表的存储结构
(4)按值查找 int Locate (SqList sq, ElemType x) { //查找sq中是否包含值为x的元素 //查找成功返回该元素所在位置,否则返回0 int i = 0; while (sq.data[i] != x && i<sq.len) i++; if (i >= sq.len) return 0; else return i+1; }
{ int i=0, j=A.len-1, k; ElemType temp; while(i<=j) { while(A.data[i]%2 == 0) i++; while(A.data[j]%2 == 1) j--; if (i<j) { temp = A.data[i]; A.data[i] = A.data[j]; A.data[j] = temp; } }
第12页
§2.2 线性表的存储结构
(5)插入元素 int InsElem (SqList &sq, ElemType x, int i) { //向线性表中第i个位置插入一个元素x //插入成功顺序表长度加1,并返回1;否则返回0 int j; if ( i<1 || i>sq.len+1) return 0; for (j=sq.len; j>=i; j--) sq.data[j] = sq.data[j-1]; sq.data[i-1] = x; sq.len++; return 1; } 第13页
第3页
§2.1 线性表的基本概念
线性表的基本运算
InitList(sq) 操作结果:构造一个空的线性表sq GetLength(sq) (1,2,3,4,5,6,7,8) 初始条件:sq已经存在 操作结果:返回sq的长度 GetElem(sq, i) 初始条件:sq已经存在,且1≤i≤GetLength(sq) 操作结果:返回sq中第i个元素的值 Locate(sq, x) 初始条件:sq已经存在 操作结果:返回sq中第一个和x值相同的元素的序号
第17页
§2.2 线性表的存储结构
(a1,a2,a3,a4,a5,a6,a7) 插入算法InsElem()分析 结点移动的次数和表长n有关,还和插入位置i有关 当i=n+1时,移动次数为0,最小值 当i=1时,移动次数为n,最大值 线性表中共有n+1个可以插入元素的位置,假设在每 个位置上插入的概率相等为pi=1/(n+1),则在长度为 的线性表中插入一个结点时所需移动结点的平均次数 为:
《算法与数据结构》
第2章 线性表
主讲人:黄伯虎
§2.1 线性表的基本概念
线性表(linear_list)定义
最常用最简单的一种数据结构。是一个由n个数据元素 组成的有穷序列。 形式: (a1, a2, a3 … ai … an)
数据元素,可以拥有不同的 含义 ,但是同一线性表中的 数据元素应具有相同含义。 a1为起始元素 an为终端元素 举例:(1,2,3,4,5,6,7,8)
data next
其中data为数据域,用于存储线性表元素值 next为指针域(链域),用于存放该结点直接后继结点 的地址 (a,b,c,d,e,f)
a b c d e f
a
b
c
d
e
f
Λ
第22页
§2.3 链式存储结构
单链表的分类
不带头结点的单链表
L a b c d e f Λ
L为头指针,指向表中第一个结点。L为空(L=NULL) 表示表长为0 带头结点的单链表
基本运算
通过以上基本运算可以实现更为复杂的运
第5页
线性表 复杂运算
§2.1 线性表的基本概念
举例:P12页例2.1 利用线性表的基本运算,编写在线性表A中删除线性表B中出现元素的算法 A (a1, a2, a3 … ai … an) B (b1, b2, b3 … bi … bn) 思路:依次检查B中的每一个元素,看是否在线性表A中存在值相同的元 素,若存在则从A中删除该元素。
第16页
}
§2.2 线性表的存储结构
顺序实现的算法分析(时间复杂度)
插入、删除操作是顺序表的主要运算,因此我们将对这 两种操作着重分析 一个合理的依据:移动为这类算法中的主要操作,在移 动结点上所花费的时间往往要比其它操作多很多(如条 件判断、算术表达式计算等),因此我们以结点的移动 作为基本的操作来分析算法的时间复杂度。
第20页
§2.3 链式存储结构
单链表
使用一组任意的存储单元存储线性表的数据元素,这组 存储单元可以是连续的,也可以是不连续的
?数据之间的关系如何表示 增加能存储逻辑关系信息的域 ?如何实现 指针
第21页
§2.3 链式存储结构
单链表的基本思想
使用一个指针来表示结点间的逻辑关系。其结点的形式 如下:
第7页
§2.2 线性表的存储结构
由于在高级程序设计语言中数组(如:int A[10])具有 连续的存储空间,且可以进行随机存取,符合顺序存储 的特征,因此程序设计时常用数组来描述数据结构中的 顺序存储结构。 C/C++语言中,顺序表描述如下: const int MAXSIZE=顺序表的容量 typedef struct { ElemType data[MAXSIZE]; //存放顺序表中的数 据元素 data len a int len; //顺序表的长度 6 b (a,b,c,d,e,f) }SqList;
第9页
§2.2 线性表的存储结构
值传递 实参将数据传递给形 参,实参和形参拥有各 自独立的存储空间,除 了值相同之外没有任何 联系,形参变量中值的 变化不会对实参变量产 生任何影响,形参不能 返回值,是一个局部变 量,函数调用结束后形 参随函数一起销毁。 地址传递 实参将地址值传递给形 参(是一个指针),实 参和形参指向同一个存 储空间,改变形参的值 实际上就是改变实参的 值,形参能够返回值, 是一个局部变量,函数 调用结束后形参随函数 一起销毁,但是其值则 保存了下来。 引用调用(C++)
百度文库
第6页
§2.2 线性表的存储结构
线性表的存储结构分两种:
顺序存储结构 链式存储结构
顺序存储结构(顺序表)
定义:是按照顺序存储方式构造的线性表 基本思想: 顺序表中的一个存储单元存储一个数据元素 以元素之间的排列顺序来表示元素之间的逻辑关系 (a,b,c,d,e,f)
a b c d e f
特点:逻辑结构中相邻的结点在存储结构中仍然相 邻,也就是说以元素在计算机内“物理位置”的相邻 来表示线性表中数据元素之间的逻辑关系。
原理同地址传递基本相 同,只是在概念上有区 别。 1. 引用是一种隐含的 指针,是一个别名 。 2. 指针操作语法复杂 ,而定义引用变量 后其操作方法和普 通变量相同。 3. 指针太灵活因此更 容易出错,使用引 用可以减少出错几 率。
第10页
§2.2 线性表的存储结构
(2)求线性表长度 int GetLength(SqList sq) { //求线性表的长度 return sq.len; //返回sq的len域值 } (3)求线性表中第i个元素 int GetElem(SqList sq, int i) { //输出线性表中第i个元素 //i有效时返回第i个元素,无效时返回0 if (i<1 || i>sq.len) return 0; else return sq.data[i-1]; } 第11页
第14页
§2.2 线性表的存储结构
(7)输出顺序表中各个元素的值 void DispList (SqList sq) { //依次输出各个元素的值 int i; for (i=1; i<=sq.len; i++) count << sq.data[i-1] << “ ”; cout << endl; }
表长:线性表中数据元素的个数 空表:表长为0的线性表,记做()或Ф
第2页
§2.1 线性表的基本概念
线性表的特征
元素(结点)个数L≥0 若L≥1 则: 除了起始结点和终端结点外的其它结点有且仅有一个 前驱结点和一个后继结点; 起始结点有且只有一个后继结点,无前驱; 终端结点有且只有一个前驱结点,无后继; (1,2,3,4,5,6,7,8)
第15页
§2.2 线性表的存储结构
举例: 例P17-2.4:已知线性表(a1, a2 … an)按顺序存储,且每个元素都是互不相等 的整数。设计把所有奇数移到所有的偶数前边的算法(要求时间最少,辅助 空间最少) 思路:从左向右找偶数data[i],从右向左找奇数data[j],然后交换两者位置, 直到i>j为止 void move(SqList &A)