数组和广义表

5.1 数组的定义

数组:由一组类型相同、下标不同的变量构成。

特点:各个元素具有统一类型、下标 具有固定上界和下界、基本操作简单(初始化、销毁、修改、存取)

N维数组:n个下标,每个元素受到n个关系约束;一个n维数组可以看成是由若干个n-1维数组成的线性表。

5.2 数组的顺序存储

计算机的存储结构是一维的,而数组一般是多维的,那么就要进行一维化:事先约定按某种次序将数组元素排成一列序列,然后将这个线性表存入存储器中。例如:二维数组可以规定按行存储,也可以规定按列存储。C中采用行优先顺序。

利用一维线性存储的特性,可以计算数组元素的地址,必须知道的参数:①开始节点的存放地址即基地址②维数和每维的上下界③每个数组元素所占用的单元数。

n维数组任意元素的地址计算公式:

Loc(j1,j2,j3,…,jn)=Loc(0,0,..,0)+  其中cn=L,ci-1=bi*ci , 1<i≤n。

N维数组的顺序存储表示:

#define MAX_ARRAY_DIM 8 //假设最大维数为8

typedef struct{

     ElemType *base; //数组元素基址

  int dim;//数组维数

  int *bound;//数组各维长度信息保存区基址

  int *constants;//数组映像函数常量的基址

}Array;

数组的链式存储方式—用带行指针向量的单链表表示。

5.3 矩阵的压缩存储

为了节省数组元素的存储空间,所谓的压缩存储就是为多个值相同的元素只分配一个存储空间;对0元素不分配空间。若值相同的元素或0元素在矩阵中的分布有一定规律,则称此类矩阵为特殊矩阵;反之,成为稀疏矩阵(非0元素少)。

那么在稀疏矩阵中如何存储那些非0元素,稀疏矩阵的表示方法:

①  三元组:(i,j,aij

②  十字链表:

i

J

V

Down

right

    

 

 

 

down:同一列中下一非零元素的指针

right:同一行中下一非零元素的指针

每行非零元素链接成带表头结点的循环链表;每列非零元素也链接成带表头结点的循环链表。

③  三元组矩阵表:失去时机存储功能

④  带辅助向量的三元组表示。增加两个辅助向量。

记录每行非0元素个数,用NUM(i)表示;每行第一个非0元素在压缩后的三元组中的行号,用POS(i)表示。示例:

对于稀疏矩阵:
0  12 9  0  0  0

0  0   0 0  0  0

-3  0  0 0  14  0

0  0   24 0 0   0

0  18  0 0  0   0

15  0  0 -7  0  0

辅助向量表:

i

1

2

3

4

5

6

NUM(i)

2

0

2

1

1

2

POS(i)

1

3

3

5

6

7

POS(i)=POS(i-1)+NUM(i-1)

  三元组矩阵表:

i

j

v

6

6

8

1

2

12

1

3

9

3

1

-3

3

5

14

4

3

24

5

2

18

6

1

15

6

4

-7

 

 

稀疏矩阵的转置,实现方法:压缩转置和快速转置。(以三元组表的形式表示稀疏矩阵)

压缩转置:反复扫描原表序列,从j=1-n依次进行转置。

快速转置:生成矩阵三元组表的按列优先的辅助向量,然后实现快速转置。 该辅助矩阵中num行记录第col列的非零个数,第一个cpos默认为1,之后的cpos为前一项的col和num之和。

col

1

2

3

4

5

6

num[col]

2

2

2

1

1

0

cpos[col]

1

3

5

7

8

8

利用上面的辅助向量进行转置:遍历非零元素,通过元素的col列查找到相应的cpos[col]即其在转置矩阵中的位置为cpos[col],将该元素与三元矩阵相应的第cpos[col]交换后将矩阵表中的cpos[col]++和num[col]--。

两个算法的比较:记矩阵中列数为n,非零元素为t,m为总行数,则压缩转置时间复杂度为O(m*t),快速转置则为O(n+t)。快速转置增设辅助向量,空间换取时间。

5.4 广义表的定义

广义表:元素的值非原子类型,可以再分解,表中元素也可是一个线性表;所有数据元素仍然属于同一数据类型。

定义:广义表是线性表的推广,也称为列表。记为:LS=(a1,a2,…,an);其中表名为LS,表头为a1,表尾包括了从a2到an

约定:①用小写字母表示原子类型,用大写字母表示列表;②第一个元素是表头,而其余元素则组成表尾。

广义表中元素既可是原子类型,也可是列表;当每个元素都为原子且类型相同时,就是线性表。

特点:1.次序性:每个元素都有一个直接前驱和一个直接后继,首尾有点特殊性2.有长度,表中元素个数3.有深度,表中括号重数4.可递归,自己作为自己的字表5.可共享

 

5.5 广义表的存储结构

   通常用链式结构,每个元素用一个结点表示。

   原子结点:表示原子,可设2个域或三个域。例如(tag=0,value)或(tag=0,atom,tp),其中tp是指向表尾的指针域。

   表结点:表示列表,若表不空,可以分解为表头和表位,三个域:tag=1,表头指针(指向表头元素),表尾指针(指向表尾列表)。

5.6 总结

1. 数组可以视为一种广义线性表

2. 数组的存储有行/低地址优先和列/高地址优先两种不同的顺序

3. 对于稀疏矩阵,有较好的压缩存储和运算方法

4. 广义表是线性表的推广,也是一种线性结构

5. 任何一个非空表,表头可能是原子,也可能是列表,但是表尾一定是列表

5.7相关试题

1. 现在有一数组,已知一个数出现的次数超过一半,请用O(n)的复杂度的算法找出这个数。

  答案1:创建一个hash_map,key为数组中的数,value为此数出现的次数。遍历一遍数组,用hash_map统计每个数出现的次数,并用两个值存储目前出现次数最多的数和对应出现的次数。这样可以做到O(n)的时间复杂度和O(n)的空间复杂度。

  答案2:使用两个变量A和B,其中A存储某个数组中的数,B用来计数。开始时将B初始化为0。遍历数组,如果B=0,则令A等于当前数,令B等于1;如果当前数与A相同,则B=B+1;如果当前数与A不同,则令B=B-1。遍历结束时,A中的数就是要找的数。  这个算法的时间复杂度是O(n),空间复杂度为O(1)。

 

2. 一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法,求出这个文件的整数里不包含的一个整数。

   答:申请一个大数组,数组中的每一位表示一个int型数字。由于每个整数为四个字节,总共只有2^32约等于4G种可能,故需要512MB个bit,所以数组的大小为512MB,并初始化为0。首先遍历40亿个整数,并将对应的bit置为1。对于重复的数字只统计一次,可以使用或操作来实现。然后遍历一下数组的各个bit,是0就将对应的数字打印出来或保存起来。

 

3. 1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现

一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空

间,能否设计一个算法实现?。

答:将1001个元素相加减去1,2,3,……1000数列的和,得到的差即为重复的元素。

 

4.题目:求1+2+…n

 要求:不能使用乘法、for、while、if、else、switch、case等关键字,以及条件判断语句(A?B:C).

 答:定义一个类,new 一含有n 个这种类型元素的数组,那么该类的构造函数将确定会被调用n 次。我们可以将需要执行的代码放到构造函数里。


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大胖5566

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值