数据结构期末复习(三)

数据结构期末复习(三)

数组的存储结构

二维数组的顺序存储结构分为以行序为主序的存储方式和以列序为主序的存储方式。

以行序为主的存储方式就是常规的先存第0行的每列,再存第一行的每列,以此类推。以列为主的存储方式同理。

对于三维数组来说,按下标从左到右的顺序存储。例如,设a[0][0][0]的地址为p,则对于数组a[m][n][r],a[i][j][k] = p + (i*n*r + j*r + k)*l;

稀疏矩阵

三元组顺序表

转置函数最简单的方法就是row和col对应的值交换,并且row和col顺序交换,然后按照行从小到大排序。

O(col*num)的转置算法:

把M矩阵的第0列的所有元素找出来,转置,放到N矩阵的第0行,把M矩阵的第1列所有元素找出来,转置,放到N矩阵的第1行,以此类推。每次照完所有第n列元素需要扫描col次,转置num个元素,时间复杂度O(col*num)。

int i=0;
for(int col=0;col<cols;col++){//找每一列的所有元素
    for(int j=0;j<num;j++){
        if(triElems[j].col == col){//找到了之后存到N的第j行
            N.triElems[i].row = triElems[j].col;
            N.triElems[i].col = triElems[j].col;
            N.triElems[i].val = triElems[j].val;
            i++;
        }
    }
}

O(num)算法:

空间换时间,申请两个数组,一个用来记录每一列的第一个非0元存储的起始位置,另一个用来存储这一列有多少个非0元。因为在原矩阵的三元组表示种,存储是连续的,一旦我们知道了某一列存储的非0元起始地址和长度(相当于知道了终止地址),我们就能确定整个一列,进而转置整个一行。下面简要写一下。

int *cNum = new int[col+1];//存储每一列非0元个数
int *cPos = new int[col+1];//存储每一列第一个非0元起始位置
for(int col=0;col<cols;col++) cNum[col] = 0;
for(int i=0;i<nums;i++) cNum[triElems[i].col]++;
cPos[0] = 0;
for(int col=1;col<cols;col++){//下一列第一个非0元的起始位置=上一列非0元的起始位置 + 上一列非0元个数
    cPos[col] = cPos[col-1] + cNum[col-1];
    //我觉得这里很巧妙
}
//由于是从小列到大列求的非0元起始位置,所以的时候的存储顺序就是M矩阵按列从小到大存储的
//上面就都求完了,直接开始转置
for(int i=0;i<nums;i++){
    int j=cPos[triElems[i].col];//得到的是M矩阵存储的第i个元素的col列的起始非0元位置
    N.triElems[j].row = triElems[i].col;
    N.triElems[j].col = triElems[i].row;
    N.triElems[j].row = triElems[i].val;
    cPos[triElems[i].col]++;
    //注意这里是重点,非常巧妙的++,这样下一次循环进来找到的非0元起始位置就是之前位置+1,不用再写个循环了
}

广义表

定义相关

LS=(a1,a2,...,an)

LS是表名,表的长度为n,长度为0的广义表为空表。如果n>=1,则a1是表头,(a2,a3,...,an)是表尾。(注意表头没有加括号表示是原子,而表尾加括号了表示子表)

广义表种括号的重数代表广义表的深度。递归表的深度为无穷大。

表头、表尾

一个例子足以

A = ((),(a,b,c),d,e)
head(A) = ()
tail(A) = ((a,b,c),d,e)
取到c的操作是head(tail(tail(head(tail(A)))))

画存储结构

广义表的存储结构为:
tag- data/slink-link
tag=1,为原子; tag =0, 为子表.
data--为原子数据,slink---为子表地址
link---为本元素的同层下一个元素的地址

A = ((),a,(b,(c,d)),(e,f))

猜你喜欢

转载自www.cnblogs.com/aoru45/p/10463727.html