数组与广义表
一、认识数组
- 认识
- 可以看成是线性表的推广
- 数组是一组(下标值,数组元素值)构成的集合
- 在数组中,对于一组有意义的下标,都存在一个与其对应的值。
- 定义
- 数组是由n(n > 1)个具有相同数据类型的数据元素组成的有序序列,且该序列必须存储在一块地址连续的存储单元中
- 数组的ADT
ADT Queue{
数据对象
数据关系
基本操作
InitArray(&A, n, bound1,..., boundn);
DestroyArray(&A);
Value(A, &e, index1, ...,indexn);
Assign(&A, e, index1,..., indexn);
}
-
基本性质
- 数据元素个数为超长方体
- n维数组也可看成线性表的推广
-
一维数组
L o c ( i ) = { a , i = 0 L o c ( i − 1 ) + l = a + i ∗ l , i > 0 Loc(i) = \begin{cases} a, & \text {i = 0} \\ Loc(i - 1) + l = a + i * l, & \text {i > 0} \end{cases} Loc(i)={a,Loc(i−1)+l=a+i∗l,i = 0i > 0 -
二维数组(每个元素占a个存储单元)
L o c ( i , j ) = a + ( n ∗ i + j ) ∗ L Loc(i, j) = a + (n * i + j) * L Loc(i,j)=a+(n∗i+j)∗L -
n维数组
L o c ( j 1 , j 2 , … , j n ) = a + ( b 2 ∗ b 3 ∗ ⋯ ∗ b n ∗ j 1 + b 3 ∗ b 4 ∗ ⋯ ∗ b n ∗ j 2 + ⋯ + b n ∗ j n − 1 + j n ) Loc(j_1, j_2,\dots, j_n) = a + (b_2 * b_3 * \dots * b_n * j_1 + b_3 * b_4 * \dots * b_n * j_2 + \dots + b_n * j_{n - 1} + j_n) Loc(j1,j2,…,jn)=a+(b2∗b3∗⋯∗bn∗j1+b3∗b4∗⋯∗bn∗j2+⋯+bn∗jn−1+jn)
令
C
n
=
L
,
c
i
−
1
=
c
i
∗
b
i
C_n = L, c_{i - 1} = c_i * b_i
Cn=L,ci−1=ci∗bi
得
L
O
C
(
j
1
,
j
2
,
…
,
j
n
)
=
a
+
∑
i
=
1
n
c
i
j
i
LOC(j_1,j_2,\dots, j_n) = a + \sum_{i = 1}^{n} c_ij_i
LOC(j1,j2,…,jn)=a+i=1∑nciji
二、补充知识
- 实现参数可变的函数
#include <stdio.h>
#include <stdarg.h>
//利用宏定义:va_list, va_start, va_arg, va_end
//例子:实现打印n个实数的功能,n可变
void PrintFloats(int n,...){//0个或多个固定参数+省略号表示的变参
//通常'...'表示的变参列表放在最后,其前用个固定参数n来表示变参个数,方便处理
int i; double val;
va_list vl;
va_start(vl,n);//从本函数的参数中读取变参表到vl中,va_start(vl, last_arg)
for (i=0;i<n;i++) { //用循环依次读取n个参数
val=va_arg(vl,double);//将变参表中下一个参数以double类型读取
printf ("[%.2f]",val); //打印输出
}
va_end(vl);//与va_start配对使用,相当于右括号
}
三、特殊矩阵
-
定义:指非零元素或零元素的分布有一定规律的矩阵
-
特殊矩阵的压缩存储:针对阶数很高的特殊矩阵,为节省存储空间,对可以不存储的元素,如零元素或对称元素不再存储
-
对称矩阵:
- 压缩存储:只存储对角线及对角线以上的元素。
- 映像函数:
k = { i ( i − 1 ) / 2 + j − 1 i ≥ j j ( j − 1 ) / 2 + i − 1 i < j k = \begin{cases} i(i-1)/2+j-1 & i ≥ j\\ j(j-1)/2+i-1 & i < j \end{cases} k={i(i−1)/2+j−1j(j−1)/2+i−1i≥ji<j
-
三角矩阵:
- 映像函数:
k = 2 i + j − 3 k = 2i + j - 3 k=2i+j−3
-
稀疏矩阵:
- 定义:非零元素个数远远少于矩阵元素个数
- 压缩存储:三元组表(行号小先存,行号相同,列号小先存)
- 矩阵转置:
- 一、三元组表行列互换,并交换顺序。
- 二、找每个未处理的编号最小的三元组,修改并存入b中。
-
void TransMatrix(TSMatrix a,TSMatrix &b) { int p, q, col; b.mu=a.nu; b.nu=a.mu; b.tu=a.tu; /*置三元组表b.data的行、列数和非0元素个数*/ if (b.tu==0) printf("The Matrix A=0\n"); else { q=0; for(col=1;col<=a.nu;col++)//从1开始,依次指定列号 for (p=0;p<a.tu; p++) //遍历三元组表找指定列号 if (a.data[p].col==col) { //找到了就将其复制到转置后结果b b.data[q].row=a.data[p].col; //一定是先找到行号最小的 b.data[q].col=a.data[p].row; b.data[q].value=a.data[p].value; q++; } } }
- 三、快速算法
-
Status FastTransMatrix(TSMatrix M, TSMatrix &T) { T.mu=M.nu; T.nu=M.mu; T.tu=M.tu; if (T.tu) { for(col=0;col<M.nu;++col) num[col]=0; for(t=0;t<M.tu;++t)//求M中每一列非零元个数 ++num[M.data[t].col]; cpot[0]=0; //求第col列中第一个非零元在T.data中的序号 for(col=1;col<=M.nu;++col) cpot[col]=cpot[col-1]+num[col-1]; for(p=0;p<=M.tu;++p) { col=M.data[p].j; q=cpot[col]; T.data[q].row=M.data[p].col; T.data[q].col=M.data[p].row; T.data[q].value=M.data[p].value; ++cpot[col]; }//for }//if return OK; } // 时间复杂度 O(nu + tu)
- 链式存储:十字链表
- 非零元素的节点所含的域有:行、列、值、行指针(指向同一行下个非0元)、列指针(指向同一列下一个非0元)。
- 链式存储:十字链表
四、广义表
- 定义:
- 线性表的推广,在人工智能领域中应用广泛。
- 广义表的元素可以是原子,也可以是子表,子表的元素又可以是子表,…。即广义表是一个多层次的结构。
- 广义表可以被其它广义表所共享,也可共享其它广义表。广义表共享其它广义表时通过表名引用。
- 广义表本身可以是一个递归表。
- 根据对表头、表尾的定义,任何一个非空广义表的表头可以是原子,也可以是子表,而表尾必定是广义表。
- 链式存储结构
由于广义表中的数据元素具有不同的结构,通常用链式存储结构表示,每个数据元素用一个结点表示。因此,广义表中就有两类结点:- 一类是表结点,用来表示广义表项,由标志域,表头指针域,表尾指针域组成;
- 另一类是原子结点,用来表示原子项,由标志域,原子的值域组成。
- 只要广义表非空,都是由表头和表尾组成。即一个确定的表头和表尾就唯一确定一个广义表。
-
typedef struct GLNode { int tag ; /*标志域,为1:表结点;为0 :原子结点*/ union{ elemtype value; /*原子结点的值域*/ struct GLNode *hp; }; struct GLNode *tp; } GLNode ; /* 广义表结点类型 */