本 章 说 明 5.1 数组的定义 5.2 数组的顺序表示和实现 5.3 矩阵的压缩存储 5.4 广义表的定义 5.5 广义表的存贮结构

Slides:



Advertisements
Similar presentations
人類起源 一 天上來的 一 天上來的 : 1 中國布朗族 : 人是從天上掉下來的。洪荒時 代,天下無人,一天刮起狂風暴雨,天落 下五人,為各族的祖先。 2 中國崩龍族 : 天上下來八個神造世界,他 們聞到大地的香味而吃了芳香的泥土,在 地上住了九千年,其中四個變成女人,四 個變成男人,成了人類最早的父母。
Advertisements

一、模型与计算公式 二、基本的组合分析公式 三、概率直接计算的例子 第 1.3 节 古典概率 四、抽签与顺序无关 五、二项分布与超几何分布 六、概率的基本性质.
2.2.1 等比数列的概念和通项公式.
秦始皇兵马俑.
情緒與壓力管理─背部舒緩 指導老師:彭易璟 第六組組員:會資三乙 499A0047 謝宛霖 會資三乙 499A0019 吳汶諭
鉴赏诗歌的形象.
第五章 数组和广义表.
班级安全文化建设的思考与实践 夯实安全基础 规范安全行为 培养安全习惯 训练安全能力 尤 学 文 管 理 学 博 士
形体训练与形象塑造.
十 代 词 制作 阚景忠 讲授 阚景忠.
顶碗少年.
第三章 鏈結串列 Linked List.
数据结构——树和二叉树 1/96.
数据结构算法 模拟练习及解答二 绍兴文理学院 计算机系计算机应用教研室.
数据结构 课程性质:专业基础课 授课时段:2004年下半学期 授课单位:软件学院 任课教师:李青山、徐学洲.
第十章 内部排序 10.1 概述 10.2 插入排序 直接插入排序 其他插入排序 希尔排序
第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例.
行為改變技術 班級:幼保二甲 組員: 4A10H081 蘇靖婷 4A1I0014 陳佳瑩 4A1I0023 尤秀惠 4A1I0074 邱乃晏 指導老師: 楊淑娥 老師.
权力的行使:需要监督 北京市京源学校 冯 悦.
丹江口市实验中学 王元智.
RFID電磁相容與檢測期中報告– RFID技術提昇醫療作業管理品質
数据结构与算法 数据结构与算法实验
专题研讨课二: 数组在解决复杂问题中的作用
第9章 排序.
1、基本概念 2、插入排序 3、交换排序 4、选择排序 5、归并排序 6、基数排序 7、外部排序
第五章 数组和广义表 £5.1 数组 £5.2 矩阵的压缩存储 £5.3 广义表 £5.1.1 数组的定义 £5.2.1 特殊矩阵
第五章 数组和 广义表 数组 稀疏矩阵 广义表.
第五章 数组和广义表.
Array & General List.
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
第12章 樹狀搜尋結構 (Search Trees)
数据结构 第5章 数组与广义表.
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
1.1 数据结构讨论的范畴 1.2 基本概念 1.3 算法和算法的量度.
本章重点难点 重点:顺序查找、二分查找、二叉排序树查找以及散列表查找的基本思想和算法实现。
第 3 讲 线性表(一).
数据结构 Data Structure 中南大学 主讲人:王国军,郑瑾 中南大学信息院计科系
第二章 线性表.
第一章 绪论.
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
中央广播电视大学开放教育试点课程 数据结构 辅导教师 倪政林.
第9章 内部排序 9.1 概述 9.2 插入排序 9.3 快速排序 9.4 选择排序 9.5 归并排序 9.6 基数排序
临海市沿江镇中心校 许慧飞.
第三章 栈和队列.
資料結構 第4章 堆疊.
第三章 链表 单链表 (Singly Linked List) 循环链表 (Circular List) 多项式及其相加
排列组合 1. 两个基本原理 分类加法计数原理 分步乘法计数原理.
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
王玲 第 2 章 线性表 王玲 2019/2/25.
第五章 数组 5.1 数组的定义 5.2 数组的表示和实现* 5.3 数组的压缩.
第五章 串和数组 5.1 串的定义和操作 5.2 串的表示和实现 5.3 字符串应用 5.4 字符串匹配算法 5.5 数组
第三章 链表 单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵.
7.1 广义表的概念 广义表是n(n≥0)个数据元素组成的序列,其中每个数据元素或是单个数据元素(简称原子),或仍然是一个广义表 。
C语言版 软件与理论教研室 张泽宝 哈尔滨工程大学计算机科学与技术学院.
第五章 递归与广义表 递归的概念 递归过程与递归工作栈 递归与回溯 广义表.
第五章 数组和广义表.
第6章 数组与广义表 6.1 数组的定义及其基本操作 6.2 数组的顺序存储结构 6.3 矩阵的压缩存储 6.4 广义表的概念
Chapter 05 Sparse Matrix & Lists 第五章 稀疏数组和广义表
陣列 (Array)      授課老師:蕭志明.
第三节 常见天气系统.
第五章 串和数组 5.1 串的定义和操作 5.2 串的表示和实现 5.3 字符串应用 5.4 字符串匹配算法 5.5 数组
第四章 串和数组 4.1 串的定义* 4.2 串的表示和实现* 4.3 数组 4.4 数组的压缩.
第八章 矩阵论.
第 六 讲 栈和队列(一).
陣列的位址計算.
Ch.5 数组和广义表 黄刘生 中国科学技术大学计算机系 国家高性能计算中心(合肥)
Chap 7 数 组 7.1 排序问题 7.2 找出矩阵中最大值所在的位置 7.3 进制转换.
制作:黎卓强 等差数列.
Chapter 2 Entity-Relationship Model
一粒貌不惊人的种子,往往隐藏着一个花季的灿烂;一条丑陋的毛虫,可能蜕(tuì)变为一只五色斑斓的彩蝶。因为,生命本身就是一桩奇迹。
Presentation transcript:

本 章 说 明 5.1 数组的定义 5.2 数组的顺序表示和实现 5.3 矩阵的压缩存储 5.4 广义表的定义 5.5 广义表的存贮结构 5.1 数组的定义 5.2 数组的顺序表示和实现 5.3 矩阵的压缩存储 5.4 广义表的定义 5.5 广义表的存贮结构 本 章 小 结 返回主目录

理解数组类型的特点及其在高级编程语言中的存储表示和实现方法,并掌握数组在“以行为主” 、“以列为主”的存储表示中的地址计算方法。 本章说明 学习目标 理解数组类型的特点及其在高级编程语言中的存储表示和实现方法,并掌握数组在“以行为主” 、“以列为主”的存储表示中的地址计算方法。 掌握特殊矩阵的存储压缩表示方法。 理解稀疏矩阵的两类存储压缩方法的特点及其适用范围,领会以三元组表示稀疏矩阵时进行矩阵运算所采用的处理方法。 从学习利用高级语言编制程序开始,数组是大家惯用的存储批量数据的工具,前几章讨论的线性结构的顺序存储结构也都是利用数组来描述的,那么数组本身又是怎么实现的呢?因此本章的学习目的主要是了解数组类型的特点以及在高级编程语言中的实现方法。对于本章讨论的随机稀疏矩阵运算的各个算法主要是理解问题的处理方法。  

数组的类型定义、数组的存储表示、特殊矩阵的压缩存储表示方法、随机稀疏矩阵的压缩存储表示方法。 本章说明 重点和难点 重点是学习数组类型的定义及其存储表示。 知识点 数组的类型定义、数组的存储表示、特殊矩阵的压缩存储表示方法、随机稀疏矩阵的压缩存储表示方法。 从学习利用高级语言编制程序开始,数组是大家惯用的存储批量数据的工具,前几章讨论的线性结构的顺序存储结构也都是利用数组来描述的,那么数组本身又是怎么实现的呢?因此本章的学习目的主要是了解数组类型的特点以及在高级编程语言中的实现方法。对于本章讨论的随机稀疏矩阵运算的各个算法主要是理解问题的处理方法。  

5.1 数组的定义 数组是线性表的推广 数组可以看成是一种特殊的线性表,即线性表中数据元素本身也是一个线性表。 列向量 行向量 二维数组可定义为"其数据元素为一维数组的线性表"。可表示为:   A(2) = ( A(1)0,A(1)1,……,A(1)m-1 )  其中每个数据元素是一个一维数组   A(1)i = ( ai,0,ai,1,……,ai,n-1 ) i = 0,1,……,m-1  类似地,N维数组是N-1维数组的线性表   A(N) = ( A(N-1)0,A(N-1)1,……,A(N-1)s-1 ) 行向量

5.1 数组的定义 数组的抽象数据类型定义 ADT Array { 数据对象:ji=0,..., bi-1, i=1,2,..,n D={aj1,j2,...jn|n(>0)为数组的维数,bi为数组第i维的长度, ji为数组元素的第i维下标, aj1,j2,...jn ∈ElemSet } 数据关系:R={R1, R2, ..., Rn} Ri={< aj1,…,ji, …,jn, aj1,…,ji+1, …,jn > |          0≤jk≤bk-1, 1≤k≤n 且ki,          0≤ji≤bi-2,          aj1,…,ji, …,jn, aj1,…,ji+1, …,jn ∈D, i=2,...,n } 二维数组中共有 mn 个元素,每个元素 同时处于"行"和"列"的两个关系中,它既在"行关系ROW"中是 (i>0)的后继,又在"列关系COL"中是 (j>0)的后继。   

5.1 数组的定义 基本操作: InitArray(&A, n, bound1, ..., boundn) 操作结果:若维数 n 和各维长度合法,则构造相应的数组A。 DestroyArray(&A) 初始条件:数组 A 已经存在。 操作结果:销毁数组 A。 Value(A, &e, index1, ..., indexn) 初始条件:A 是 n 维数组,e 为元素变量,随后是 n 个下标值。 操作结果:若各下标不超界,则e赋值为所指定的A的元素值,并返回OK。 Assign(&A, e, index1, ..., indexn) 初始条件:A 是 n 维数组,e 为元素变量,随后是 n 个下标值。 操作结果:若下标不超界,则将 e 的值赋给A中指定下标的元素。 } ADT Array 数组一旦被定义,其维数(N)和每一维的上、下界均不能再变,数组中元素之间的关系也不再改变。因此数组的基本操作除初始化和结构销毁之外,只有通过给定的"一组下标"索引取得元素或修改元素的值。

“以行(序)为主(序)” :对二维数组进行“按行切分”,即将数组中的数据元素“按行依次排放”在存储器中 5.2 数组的顺序表示和实现 用一组连续的存储单元来表示数组。 有两种映象方法: “以行(序)为主(序)” :对二维数组进行“按行切分”,即将数组中的数据元素“按行依次排放”在存储器中 “以列(序)为主(序)”对二维数组进行“按列切分”,即将数组中的数据元素"按列依次排放"在存储器中。  由于数组不作插入和删除的操作,因此,采用顺序存储结构表示数组是自然的事。这是我们只介绍数组的顺序存储表示的原因。 由于数组中的数据元素之间是一个"多维"的关系,而存储地址是一维的,因此数组的顺序存储表示要解决的是一个"如何用一维的存储地址来表示多维的关系"的问题。 现有的高级语言中的大多数都是按"以行为主"实现数组类型的。

5.2 数组的顺序表示和实现 按行序为主序存放 a00 1 a01 ……. a0,n-1 n-1 a10 n a11 …….. a1,n-1 1 n-1 m*n-1 n a00   按行序为主序存放 a01 ……. a0,n-1 a10 a11 …….. a1,n-1 ……… am-1,0 am-1,1 …….. am-1,n-1

5.2 数组的顺序表示和实现 按列序为主序存放 a00 a10 1 ……. am-1,1 m-1 m a01 a11 …….. am-1,1   按列序为主序存放 1 m-1 m*n-1 m a00 a10 ……. am-1,1 a01 a11 …….. am-1,1 ………. a0,n-1 a1,n-1 …….. am-1 ,n-1

5.2 数组的顺序表示和实现 按行序为主序存放 每个数据元素占L个存储单元;   按行序为主序存放 am-1,n-1 …….. am-1,1 am-1,0 ……… a1,n-1 a11 a10 a0,n-1 ……. a01 a00 1 n-1 m*n-1 n 每个数据元素占L个存储单元; LOC(0,0)表示数据元素a00的存储地址 是数组的起始地址(基地址); LOC(i,j)表示下标为(i,j)的数据元素 aij的存储地址 LOC(i,j)=LOC(0,0)+(i*n+j)*L 这个公式可以推广到n维数组。

5.2 数组的顺序表示和实现 按列序为主序存放 每个数据元素占L个存储单元;   按列序为主序存放 am-1 ,n-1 …….. a1,n-1 a0,n-1 ………. am-1,1 a11 a01 ……. a10 a00 1 m-1 m*n-1 m 每个数据元素占L个存储单元; LOC(0,0)表示数据元素a00的存储地址, 是数组的起始地址(基地址) LOC(i,j)表示下标为(i,j)的数据元素 aij的存储地址 LOC(i,j)=LOC(0,0)+(j*m+i)*L 这个公式可以推广到n维数组。

为多个值相同的矩阵元只分配一个存储空间;对零元不分配空间。 5.3 矩阵的压缩存储 压缩存储 为多个值相同的矩阵元只分配一个存储空间;对零元不分配空间。 矩阵是很多科学与工程计算问题中研究的对象,在数值分析中,经常出现一些阶数很高的矩阵,同时在矩阵中有许多值相同的元素或者零元素。 为了节省存储空间,可以对这类矩阵进行压缩存储。

值相同的元素或者零元素在矩阵中的分布有一定规律 5.3 矩阵的压缩存储 5.3.1 特殊矩阵 特殊矩阵 值相同的元素或者零元素在矩阵中的分布有一定规律 对称矩阵 n阶矩阵; aij=aji 1i,j n

特殊矩阵 5.3 矩阵的压缩存储 值相同的元素或者零元素在矩阵中的分布有一定规律 n阶矩阵; 三角矩阵 n阶矩阵; 下(上)三角矩阵:矩阵的上(下)三角(不包括对角线)中的元均为常数c或零。

特殊矩阵 5.3 矩阵的压缩存储 值相同的元素或者零元素在矩阵中的分布有一定规律 n阶矩阵 所有的非零元都集中在以主对角线为中心的带状区域中 对角矩阵 n阶矩阵 所有的非零元都集中在以主对角线为中心的带状区域中

5.3 矩阵的压缩存储 压缩存储——对称矩阵 a11 a12 …. … ….. a1n a21 a22 …….. ……. a2n 仅存储下三角 压缩存储——对称矩阵 a11 a12 …. … ….. a1n a21 a22 …….. ……. a2n an1 an2 …….. ann …………………. 按行序为主序: 虽然可以压缩存储,但是不能改变随机存储的性质,即任意给定I,j,应能立即找到其值。 4 3 2 1 k=0 a11 a21 a22 a31 a32 … an1 … ann

5.3 矩阵的压缩存储 压缩存储——下三角矩阵 a11 1 1 …….. 1 a21 a22 1 …….. 1 …………………. 1 仅存储下三角 压缩存储——下三角矩阵 a11 1 1 …….. 1 a21 a22 1 …….. 1 an1 an2 an3…….. ann …………………. 1 按行序为主序: a11 4 3 2 1 k=0 a21 a22 a31 a32 … an1 … ann 1 虽然可以压缩存储,但是不能改变随机存储的性质,即任意给定I,j,应能立即找到其值。

5.3 矩阵的压缩存储 压缩存储——对角矩阵 a11 a12 0 …………… . 0 a21 a22 a23 0 …………… 0 仅存储主对角线非0元素 压缩存储——对角矩阵 a11 a12 0 …………… . 0 a21 a22 a23 0 …………… 0 0 0 … an-1,n-2 an-1,n-1 an-1,n 0 0 … … … an,n-1 an,n 0 a32 a33 a34 0 ……… 0 …………………………… 公式:请同学们自己写出来,可以到图书馆查找结果 按行序为主序: 4 3 2 1 k=0 a11 a12 a21 a22 a23 … an,n-1 an,n

5.3 矩阵的压缩存储 5.3.2 稀疏矩阵 稀疏矩阵 非零元较零元少,且分布没有一定规律的矩阵。 压缩存储原则:只存矩阵的行列维数和每个非零元的行列下标及其值。 矩阵维数 (6,7) 非零元 (1,2,12) (1,3,9) (3,1,-3) (3,6,14) (4,3,24) (5,2,18) (6,1,15) (6,4,-7) 请学生思考为什么要存储维数?

5.3 矩阵的压缩存储 1.压缩存储——稀疏矩阵(三元组顺序表) 以顺序存储结构来表示三元组。 稀疏矩阵的三元组顺序表存储表示 #define MAXSIZE 12500 //假设非零元个数的最大值为12500 typedef struct{ int i,j; //该非零元的行下标和列下标 ElemType e; }Triple; typedef struct{ Triple data[MAXSIZE+1]; //非零元三元组表,data[0]未用 int mu, nu, tu; //矩阵的行数、列数和非零元个数 }TSMatrix ; 行序 共有三种压缩存储的方法,本节介绍的是顺序存储

5.3 矩阵的压缩存储 行列下标 非零元值 data i j e 0 1 2 3 4 5 6 7 8 6 7 8 1 2 12 1 3 9 3 1 -3 3 6 14 data[0].i,data[0].j,data[0].e分别存放矩阵行列维数和非零元个数 4 3 24 三元组表所需存储单元个数为3(tu+1),其中tu为非零元个数 5 2 18 6 1 15 6 4 -7

5.3 矩阵的压缩存储 求转置矩阵 问题描述 已知一个稀疏矩阵的三元组表,求该矩阵转置矩阵的三元组表。 解决思路 将矩阵行、列维数互换; 将每个三元组中的i和j相互调换; 重排三元组次序。

5.3 矩阵的压缩存储 6 7 8 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 i j e 0 1 2 3 4 5 6 7 M.data i j e 7 6 8 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24 4 6 -7 6 3 14 0 1 2 3 4 5 6 7 T.data 两种转换方法:一、按data2中的顺序,在data1中找到合适的值进行转置;二、按data1的顺序,在data2中找到合适的位置进行转置。 ?

5.3 矩阵的压缩存储 方法一:按矩阵的列序转置 按T.data中三元组次序依次在M.data中找到相应的三元组进行转置 Col从1~n在M中找每1列 6 7 8 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 i j e 0 1 2 3 4 5 6 7 8 M.data i j e 0 1 2 3 4 5 6 7 8 T.data 7 6 8 p p q 1 3 -3 p p q 1 6 15 col=1 p p q 2 1 12 p 为找到转置矩阵中每一列所有非零元素,需对其三元组表a.data从第一行起扫描一遍。由于a.data中以矩阵行序为主序,所以由此得到的恰是b.data中应有的顺序 p q 2 5 18 col=2 p p q 3 1 9 p p 3 4 24 p p 4 6 -7 p p 6 3 14

5.3 矩阵的压缩存储 按矩阵的列序转置的算法思想 (1)令T.mu=M.nu, T.nu=M.mu, T.tu=M.tu, col=1,q=1(T的三元组下标初始化,指向转置后的第1个位置),p=1 (指向M的第1个位置) (2)如p所指元素的列下标=col,则送q所指位置,q++ (3)p++,若p<=M.tu(1~最后1个非0元),则(2),否(4) (4)col++,如果col<=M.nu,转(2),否(5) (5)结束 当tu和mu*nu同数量级时,算法的时间复杂度为O(mu*nu2),例如在100*500的矩阵中有tu=10000个非零元素 虽然空间节省了,但时间复杂度提高了。因为不经压缩的矩阵在求转置矩阵的时间复杂度为O(mu*nu), 算法实现: 算法5.1 适用于tu<<mu*nu 时间复杂度为O(nutu)

按M.data中三元组次序转置,转置结果放入T.data中恰当位置。 5.3 矩阵的压缩存储 方法二:按矩阵的行序转置 按M.data中三元组次序转置,转置结果放入T.data中恰当位置。 此法关键是要预先确定M.data中每一列第一个非零元在T.data中位置。(cpot[col]) 为确定这些位置,转置前应先求得M.data的每一列中非零元个数。(num[col]) 设num[col]记录M中第col列中非0元个数,cpot[col]记录M中第col列的第1个非0元在T中的恰当位置,有: cpot[1]=1; cpot[col]=cpot[col-1]+num[col-1] 2≤col≤M.mu

5.3 矩阵的压缩存储 p p p p p p p p M.data T.data col num[col] cpot[col] 1 2 3 4 7 8 6 9 2 4 6 8 9 3 5 7 6 7 8 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 i j e 0 1 2 3 4 5 6 7 8 M.data i j e 0 1 2 3 4 5 6 7 8 T.data 7 6 8 p 1 3 -3 p 1 6 15 p 2 1 12 num[col]:表示矩阵M中第col列中非零元个数 cpot[col]:指示M中第col列第一个非零元在mb中位置 cpot[1]=1; cpot[col]=cpot[col-1]+num[col-1]; (2col ma[0].j) p 2 5 18 p 3 1 9 p 3 4 24 p 4 6 -7 p 6 3 14

方法二:按矩阵的行序转置的实现 5.3 矩阵的压缩存储 时间复杂度为O(nu+tu) 算法5.2 用空间换取时间 在tu与mu*nu同数量级时,其时间复杂为O(nu*mu),和经典算法的时间复杂度相同。 时间复杂度为O(nu+tu)

非零元在表中按行序有序存储,便于进行依行序处理的矩阵运算。 5.3 矩阵的压缩存储 三元组顺序表的特点 优点 非零元在表中按行序有序存储,便于进行依行序处理的矩阵运算。 缺点 若需按行号存取某一行的非零元,则需从头开始进行查找。

2.压缩存储——稀疏矩阵(行逻辑链接的的顺序表) 5.3 矩阵的压缩存储 2.压缩存储——稀疏矩阵(行逻辑链接的的顺序表) 为了便于随机存储任意一行的非零元,需要知道每一行的第一个非零元在三元组表中的位置 解决方法:将cpot固定在稀疏矩阵的存储结构中。 #define MAXSIZE 12500 //假设非零元个数的最大值为12500 typedef struct{ int i,j; //该非零元的行下标和列下标 ElemType e; }Triple; typedef struct{ Triple data[MAXSIZE+1]; //非零元三元组表,data[0]未用 int rpos[MAXRC+1]; //各行第一个非零元的位置表 int mu,nu,tu; //矩阵的行数、列数和非零元个数 }RLSMatrix ; 矩阵压缩存储的第二种方法,

5.3 矩阵的压缩存储 矩阵乘法运算 如何求? M.data N.data Q.data 3 4 4 1 1 3 1 4 5 2 2 -1 3 4 4 1 1 3 1 4 5 2 2 -1 3 1 2 i j e 0 1 2 3 4 M.data 4 2 4 1 2 2 2 1 1 3 1 -2 3 2 4 i j e 0 1 2 3 4 N.data 3 2 3 1 2 6 2 1 -1 3 2 4 i j e 0 1 2 3 Q.data

5.3 矩阵的压缩存储 (1)稀疏矩阵MxN,只需在M、N中找到相应的各对非0元素相乘,即M.data中的j值和N.data中的i值相等的各对非0元素相乘。例如M中的(1,1,3)p=1和N中的(1,1,0) 、(1,2,2)q=1相乘。为此,设两个:num[brow]表示N中第brow行的非0元个数,rpos[brow]表示N中第brow行的第1个非0元在N.data中的位置,N.rpos[1]=1, N.rpos[brow]=rpos[brow-1]上一行+num[brow-1]上一行,2≤brow≤n。N.rpos[brow]、M.rpos[arow]称为行逻辑链接的顺序表。(并在进入下面的算法前,预先求得一维数组rpos的值。 (2)乘积矩阵Q中每个元素的值是个累计和(也可能为和),对每个元素设一中间变量,temp[]列数,初值为0,将相应非0元素的乘积累加。例如,Ma中的(1,1,3)1与Nb中的(1,1,1)1的乘积,以及Ma中的(1,3,4)2与Nb中的(3,1,-2)3的乘积累加为Q中的(1,1,-5)1 (3)因(M)是“以行为主”排列,(Q)也应“以行为主”排列,故对Q逐行处理。中间变量ctemp[最大为Q的列数]存放Q的一行,检查这行中各元素是否零,然后,再将非0元素(结果)存到Q.data中。 累加器的时间复杂度为O(M.mu*N.nu),求Q所有非零元的时间复杂度为O(M.tu*N.tu/N.mu),进行压缩存储的时间复杂度为O(M.mu*N.nu),

5.3 矩阵的压缩存储 6 4 ctemp累加器 arow=2 arow=1 arow=3 rpos[row] M.data N.data ctemp累加器 arow=2 arow=1 arow=3 4 3 1 rpos[row] 2 row 矩阵M的rpos 5 矩阵N的rpos 1 1 3 1 4 5 2 2 -1 3 1 2 i j e 0 1 2 3 4 M.data 3 4 4 1 2 2 2 1 1 3 1 -2 3 2 4 N.data 4 2 4 6 p p -1 p p 4 p p p 矩阵Q的rpos row 1 2 3 rpos[row] 1 2 3 i j e 0 1 2 3 Q.data 3 2 0 1 2 6 2 1 -1 3 2 4

5.3 矩阵的压缩存储 算法思想 ①初始化(行数Q<=M,列数Q<=N赋值,Q的下标Q.tu=0,准备接收); ②for(arow=1;arow<=M.mu;++arow),处理M的每一行; ③中间变量一维数组ctemp(行)清0(例子中,Q一行只有2列,故ctemp[1],ctemp[2]即2)。顺便记下Q当前行非0元的起始位置Q.tu ④对M的当前行中的非0元,(逐个)做:(p<tp) ⑤取M中当前非0元的列号(j),即为N中的i(N中的行号brow); ⑥根据N的行号,对该行的非0元逐个做:(有几个就做几次)(q<t) ⑦取N中当前非0元的列号为Q的列号(Q的列号为ccol); ⑧M、N中相应的非0元相乘,并累加到ctemp[Q的列号]ccol中; ⑨逐个将当前Q的一行中的非0元素存入Q中。 累加器的时间复杂度为O(M.mu*N.nu),求Q所有非零元的时间复杂度为O(M.tu*N.tu/N.mu),进行压缩存储的时间复杂度为O(M.mu*N.nu),

矩阵相乘算法实现 5.3 矩阵的压缩存储 算法时间复杂度 累加器ctemp[]初始化的时间复杂度为: O(M.mu×N.nu) 算法5.3 算法时间复杂度 累加器ctemp[]初始化的时间复杂度为: O(M.mu×N.nu) 求Q的所有非0元的时间复杂度为: O(M.nu×N.tu/N.mu) 压缩存储的时间复杂度为: 所以,总的时间复杂度为: O(M.mu×N.nu+M.tu×N.tu/N.mu) 累加器的时间复杂度为O(M.mu*N.nu),求Q所有非零元的时间复杂度为O(M.tu*N.tu/N.mu),进行压缩存储的时间复杂度为O(M.mu*N.nu),

5.3 矩阵的压缩存储 3.压缩存储——稀疏矩阵(十字链表) 引入原因 当矩阵的非零元的个数发生变化时,不宜采用三元组表。如A=A+B,非零元的插入或删除将会引起A.data中的数据移动,这是顺序结构三元组的弱势。 十字链表结点形式 非零元的行、列、值 typedef struct OLNode{ int i,j; ElemType e; struct OLNode *right,*down; }OLNod; *OLink; typedef struct Olink *rhead,*chead; int mu, nu, tu; }CrossList; i j e down right 同一行下一个非零元 同一列下一个非零元

5.3 矩阵的压缩存储 列链表头指针 M.chead M.rhead 1 3 4 8 2 5 ^ 行链表头指针 ^ ^ ^ ^ ^ ^

5.3 矩阵的压缩存储 建立十字链表的思想 m=4,n=3,t=5 1,1,3 2,2,5 2,3,4 4,1,8 2,1,7 ^ 1 3 M. rhead M.cread 2,3,4 4,1,8 1 3 ^ 2,1,7 2 1 7 ^ 2 5 ^ 2 3 4 ^ 4 1 8 ^

5.3 矩阵的压缩存储 建立十字链表的算法思想 (1)初始化 (2)循环输入各非0元的(i,j,e),直到最后一个,重复做: (3)申请结点,赋值 (4)寻找行i插入位置,插入 (5)寻找列j插入位置,插入 对于m行、n列有t个非零元的稀疏矩阵,算法的执行时间为O(t*s),s=max(m.n),因为每建立一个非零元的结点时都要寻查它在行表和列表中的插入位置。 建立十字链表的算法实现 算法5.4 时间复杂度为O( t*s) ,s=max(m.n)

广义表(列表) 5.4 广义表的定义 是线性表的推广,广泛地应用于人工智能等领域的表处理语言LISP语言。 一般记作LS=(a1,a2,…,an) (n0) 名称:LS; 长度:n; 原子:ai是单个元素,一般用小写字母表示; 子表:ai是广义表,一般用大写字母表示。 表头(Head):非空广义表 LS的第一个数据元素a1; 表尾(Tail):非空广义表 LS除第一个数据元素外的其余数据元素构成的广义表 (a2,…,an) 。 由于广义表本属线性类型的数据结构,它和数组类似,每个数据元素本身又可以是一个数据结构,因此在教材中和“数组”合为一章。但由于广义表比数组更为复杂,它兼有“多层次”的特点,特别是它的存储表示和操作的实现和树的操作极为类似。因此在本章的学习中应善于和第六章的内容相对照,反之通过本章的学习恰好是对实现树操作的递归算法的复习和巩固。希望你通过本章的学习能自己总结出如何利用“分治法”的算法思想设计递归定义的结构的递归算法的规律来 广义表是递归的概念,描述广义表时又用到了广义表的概念。 和数组不同,二维数组中的每个数据元素是结构相同的一维数组,而广义表中的每个数据元素,其结构不一定相同。

广义表的元素可以是子表,而子表的元素还可是子表 广义表可以为其它列表共享 广义表可以是一个递归的表 5.4 广义表的定义 广义表与数组的区别 广义表特性 A=() F=(b,(c,d,e)) E=(b,(c),(d,e)) D=(E,A,F) C=(A,D,F) B=(a,B)=(a,(a,(a,v...))) 广义表中的数据元素有固定的相对次序   广义表的元素可以是子表,而子表的元素还可是子表 广义表可以为其它列表共享 广义表可以是一个递归的表

广义表中元素的“长度"应由最外层括弧中的"逗号"来定。 5.4 广义表的定义 操作——长度 A=() F=(b,(c,d,e)) E=(b,(c),(d,e)) D=(E,A,F) C=(A,D,F) B=(a,B)=(a,(a,(a,v...))) A的长度为0 F的长度为2 E的长度为3 D的长度为3 C的长度为3 B的长度为2 ()和(())是不同的,前者长度为0,后者长度为1 广义表中元素的“长度"应由最外层括弧中的"逗号"来定。

操作——取表头、取表尾 F=(b,(c,d,e)) 5.4 广义表的定义 操作——取表头、取表尾 F=(b,(c,d,e)) GetHead(F)=b GetTail(F)=((c,d,e))=F1 GetHead(F1)=(c,d,e)=F2,GetTail(F1)=( ) GetHead(F2)=c,GetTail(F2)=(d,e)=F3 GetHead(F3)=d,GetTail(F3)=(e)=F4 GetHead(F4)=e,GetTail(F4)=( ) ()和(())是不同的,前者不能进行这两个操作,后者可以进行这两个操作。 两个操作只对非空表有意义; 取表头的结果可能是原子,也可能是个广义表; 取表尾"必定"是个广义表,但可能是个空的广义表。

5.5 广义表的存储结构 采用链式存储结构。 两种结构的结点 表结点:用来表示列表; 原子结点:用来表示子表。 表尾指针 表结点 tag=1 hp tp 原子结点 tag=0 atom 因为,广义表的数据元素可以具有不同的结构,采用顺序存储结构表示将非常困难,通常采用链式结构。 标志域 值域 标志域 表头指针

5.5 广义表的存储结构 A=() B=(e) C=(a,(b,c,d)) D=(A,B,C) E=(a,E) A C B D E 1  e a 1 1 1  结构复杂 D 1  b c d 1 1  E 1 1  a

5.5 广义表的存储结构 另一种结点结构 下一个元素指针 值域 表结点 tag=1 hp tp 原子结点 tag=0 atom tp 标志域 表头指针 下一个元素指针

5.5 广义表的存储结构 A=() B=(e) C=(a,(b,c,d)) D=(A,B,C) E=(a,E) A C B D E 1  a 1  e  D 1  b c d  结构复杂 1  1 1  E 1  a 1 

本章小结 了解数组的类型定义及其在高级语言中实现的方法。 数组的特点是一种多维的线性结构,并只进行存取或修改某个元素的值,因此它只需要采用顺序存储结构。 介绍了稀疏矩阵的三种表示方法。至于在具体应用问题中采用哪一种表示法这取决于该矩阵主要进行什么样的运算。 广义表是一种递归定义的线性结构,因此它兼有线性结构和层次结构的特点。

基础知识题(数组部分) 假设有二维数组 A6×8,每个元素用相邻的6个字节存储,存储器按字节编址。已知A的起始存储位置(基地址)为 1000,计算: 数组 A 的存储; 数组 A 的最后一个元素 a5,7 的第一个字节的地址; 按行存储时,元素 a1,4 的第一个字节的地址; 按列存储时,元素 a4,7 的第一个字节的地址。

基础知识题(广义表部分) 求下列广义表操作的结果: GetHead((p,h,w)); GetTail((b,k,p,h)); GetHead(((a,b),(c,d))); GetTail(((a,b),(c,d))); GetHead(GetTail(((a,b),(c,d)))); GetTail(GetHead(((a,b),(c,d)))); GetHead(GetTail(GetHead(((a,b),(c,d))))); GetTail(GetHead(GetTail(((a,b),(c,d)))))。

基础知识题(广义表部分) 利用广义表的 GetHead 和 GetTail 操作写出函数表达式,把原子 banana 分别从下列广义表中分离出来。 L1 = (apple,pear,banana,orange); L2 = ((apple,pear),(banana,orange)); L3 = (((apple),(pear),(banana),(orange))); L4 = (apple,(pear),((banana)),(((orange)))); L5 = ((((apple))),((pear)),(banana),orange); L6 = ((((apple),pear),banana),orange); L7 = (apple,(pear,(banana),orange));

基础知识题(广义表部分) 画出下列广义表的存储结构图。 ((( )), a, ((b, c), ( ), d), (((e)))) ((((a), b)), ((( ), (d)), (e, f))) 已知右侧各图为广义表的存储结构图,写出各图表示的广义表。