数据结构(C语言版)——行逻辑连接的顺序表和三元组的快速转置

要考研了,今天刚把这两块给弄懂了。也写了一些程序,希望能帮到一些刚入门数据结构的同学吧

三元组的快速转置

我们知道对于朴素转置方法,假如是M矩阵转置为N矩阵,那么我们会对于M中的每一行,遍历M中的每个元素,按行优先的顺序进行转置

 for (int col = 0; col < M.nu; col++)
 {
 //p为M中元素的索引
 //M.tu为M中非零元素的总数
 //i为元素的行、j为元素的列
     for (int p = 0; p < M.tu; p++)
     {
         if (M.data[p].j == col)
         {
             T.data[q].i = M.data[p].j;
             T.data[q].j = M.data[p].i;
             T.data[q].e = M.data[p].e;
             q++;
         }
     }
 }

但这样做时间复杂度为 O ( n u ⋅ t u ) O(nu·tu) O(nutu),那么我们就要对其进行优化。分析上述代码发现,耗时的部分就是寻找每一个元素对应列的元素,如果我们能知道每一个元素其对应列的元素位置,我们就可以降低时间复杂度。所以我们引出了两个辅助数组
n u m [ c o l ] : 表 示 矩 阵 M 中 第 c o l 列 中 非 零 元 的 个 数 c p o t [ c o l ] : 表 示 M 中 第 c o l 列 的 第 一 个 非 零 元 在 M . d a t a 中 的 位 置 num[col]:表示矩阵M中第col列中非零元的个数 \\ cpot[col]:表示M中第col列的第一个非零元在M.data中的位置 num[col]:Mcolcpot[col]:McolM.data
并且有以下公式
c p o t [ 1 ] = 1 c p o t [ c o l ] = c p o t [ c o l − 1 ] + n u m [ c o l − 1 ] \begin{aligned} &cpot[1] = 1\\ &cpot[col] = cpot[col-1]+num[col-1] \end{aligned} cpot[1]=1cpot[col]=cpot[col1]+num[col1]
这样我们可以先求出num数组和cpot数组,先找到M的第p个元素,然后根据第p个元素的列就知道它对应元素的位置了。

void transpose(TSMatrix &M, TSMatrix &T)
{
    T.mu = M.nu;
    T.nu = M.mu;
    T.tu = M.tu;
    int num[T.mu];
    int cpot[T.mu];
    cpot[0] = 0;
    int p = 0;
    memset(num, 0, sizeof(num));
    for (p = 0; p < M.tu; p++)
    {
        num[M.data[p].j]++;
    }
    for (int col = 1; col < M.nu; col++)
    {
        cpot[col] = cpot[col - 1] + num[col - 1];
    }
    for (p = 0; p < M.tu; p++)
    {
        int acol = M.data[p].j;
        int q = cpot[acol];
        T.data[q].e = M.data[p].e;
        T.data[q].i = M.data[p].j;
        T.data[q].j = M.data[p].i;
        cpot[acol]++;
    }
}

行逻辑连接的顺序表

这个稍微有点复杂,因为稀疏矩阵有非常多的0,所以我们在计算矩阵乘法时很多含0的计算不需要计算。这样我们只需要计算M中非零元素与N中非零元素的对应乘积的累计和。
对于M中确定的p,找到N中所有满足 M . d a t a [ p ] . j = N . d a t a [ q ] . i M.data[p].j = N.data[q].i M.data[p].j=N.data[q].i式的q,然后将该对应乘积之和保存到一个ctemp累加器的数组中。ctemp保存第 M . d a t a [ p ] . i M.data[p].i M.data[p].i行对Q的每一列数值的部分和。
这里我们还用到了一个rpos数组,rpos[row]表示第row行中第一个非零元在M.data中的索引。

void get_rpos(RLSMatrix &M)
{
    int num[MAXSIZE + 1];
    if (M.tu)
    {
        for (int row = 0; row < M.mu; ++row)
            num[row] = 0; ///清零
        for (int t = 0; t < M.tu; ++t)
            num[M.data[t].i]++; ///求M中每一列含非零个数
        M.rpos[0] = 0;//默认第一行第一个非零元素的位置为0
        /// 求第col列中第一个非零元在b.data中的序号
        for (int row = 1; row < M.mu; ++row)
            M.rpos[row] = M.rpos[row - 1] + num[row - 1];
    }
}
void matrix_multiple(RLSMatrix &M, RLSMatrix &T, RLSMatrix &Q)
{
    Q.mu = M.mu;
    Q.nu = T.nu;
    Q.tu = 0;
    int ctemp[Q.nu]; //
    int arow;
    for (arow = 0; arow < M.mu; arow++)
    {
    //初始化累加器数组
        memset(ctemp, 0, sizeof(ctemp));
        //设置Q.rpos
        Q.rpos[arow] = Q.tu;
        int tp;
        //tp表示M中第arow行的非零元的位置上限
        if (arow != M.mu - 1)
            tp = M.rpos[arow + 1];
        else
            tp = M.tu;
        //根据M的每一行元素来计算乘积
        for (int p = M.rpos[arow]; p < tp; p++)
        {
        	//brow用来对应T中元素的行
            int brow = M.data[p].j;
            int t;
            //t表示T中第brow行的非零元的位置上限
            if (brow != T.mu - 1)
                t = T.rpos[brow + 1];
            else
                t = T.tu;
            //这里开始计算每一个对应的乘积
            for (int q = T.rpos[brow]; q < t; q++)
            {
                int ccol = T.data[q].j;
                ctemp[ccol] += M.data[p].e * T.data[q].e;
            }
        }
        //保存第arow对Q每一行的贡献
        for (int ccol = 0; ccol < Q.nu; ccol++)
        {
            if (ctemp[ccol] != 0)
            {
                Q.data[Q.tu].i = arow;
                Q.data[Q.tu].j = ccol;
                Q.data[Q.tu].e = ctemp[ccol];
                Q.tu++;
            }
        }
    }
}

下面给出完整代码
三元组快速转置

#include <bits/stdc++.h>
using namespace std;
#define MAXSIZE 12500
typedef struct
{
    int i, j, e;
} Triple;
typedef struct
{
    Triple data[MAXSIZE];
    int mu, nu, tu;
} TSMatrix;
void transpose(TSMatrix &M, TSMatrix &T)
{
    T.mu = M.nu;
    T.nu = M.mu;
    T.tu = M.tu;
    int num[T.mu];
    int cpot[T.mu];
    cpot[0] = 0;
    int p = 0;
    memset(num, 0, sizeof(num));
    for (p = 0; p < M.tu; p++)
    {
        num[M.data[p].j]++;
    }
    for (int col = 1; col < M.nu; col++)
    {
        cpot[col] = cpot[col - 1] + num[col - 1];
    }
    for (p = 0; p < M.tu; p++)
    {
        int acol = M.data[p].j;
        int q = cpot[acol];
        T.data[q].e = M.data[p].e;
        T.data[q].i = M.data[p].j;
        T.data[q].j = M.data[p].i;
        cpot[acol]++;
    }
}
int main()
{
    int n, m;
    cin >> n >> m;
    TSMatrix M;
    M.nu = m;
    M.mu = n;
    M.tu = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            int k;
            cin >> k;
            if (k != 0)
            {
                M.data[M.tu].e = k;
                M.data[M.tu].i = i;
                M.data[M.tu].j = j;
                M.tu++;
            }
        }
    }
    TSMatrix T;
    transpose(M, T);
    int p = 0;
    for (int i = 0; i < T.mu; i++)
    {
        for (int j = 0; j < T.nu; j++)
        {
            if (T.data[p].i == i && T.data[p].j == j)
            {
                cout << T.data[p].e << " ";
                p++;
            }
            else
                cout << 0 << " ";
        }
        cout << endl;
    }
}

行逻辑连接的矩阵乘法

#include <bits/stdc++.h>
using namespace std;
#define MAXSIZE 12500
#define MAXRS 200
typedef struct
{
    int i, j, e;
} Triple;
typedef struct
{
    Triple data[MAXSIZE + 1];
    int rpos[MAXRS + 1];
    int mu, nu, tu;
} RLSMatrix;
void get_rpos(RLSMatrix &M)
{
    int num[MAXSIZE + 1];
    if (M.tu)
    {
        for (int row = 0; row < M.mu; ++row)
            num[row] = 0; 
        for (int t = 0; t < M.tu; ++t)
            num[M.data[t].i]++; 
        M.rpos[0] = 0;
        for (int row = 1; row < M.mu; ++row)
            M.rpos[row] = M.rpos[row - 1] + num[row - 1];
    }
}
void matrix_multiple(RLSMatrix &M, RLSMatrix &T, RLSMatrix &Q)
{
    Q.mu = M.mu;
    Q.nu = T.nu;
    Q.tu = 0;
    int ctemp[Q.nu];
    int arow;
    for (arow = 0; arow < M.mu; arow++)
    {
        memset(ctemp, 0, sizeof(ctemp));
        Q.rpos[arow] = Q.tu;
        int tp;
        if (arow != M.mu - 1)
            tp = M.rpos[arow + 1];
        else
            tp = M.tu;
        for (int p = M.rpos[arow]; p < tp; p++)
        {
            int brow = M.data[p].j;
            int t;
            if (brow != T.mu - 1)
                t = T.rpos[brow + 1];
            else
                t = T.tu;
            for (int q = T.rpos[brow]; q < t; q++)
            {
                int ccol = T.data[q].j;
                ctemp[ccol] += M.data[p].e * T.data[q].e;
            }
        }
        for (int ccol = 0; ccol < Q.nu; ccol++)
        {
            if (ctemp[ccol] != 0)
            {
                Q.data[Q.tu].i = arow;
                Q.data[Q.tu].j = ccol;
                Q.data[Q.tu].e = ctemp[ccol];
                Q.tu++;
            }
        }
    }
}
int main()
{
    int n, m;
    RLSMatrix M;
    cin >> m >> n;
    M.mu = m;
    M.nu = n;
    M.tu = 0;
    for (int i = 0; i < M.mu; i++)
    {
        for (int j = 0; j < M.nu; j++)
        {
            int k = 0;
            cin >> k;
            if (k != 0)
            {
                M.data[M.tu].e = k;
                M.data[M.tu].i = i;
                M.data[M.tu].j = j;
                M.tu++;
            }
        }
    }
    RLSMatrix T;
    cin >> m >> n;
    T.mu = m;
    T.nu = n;
    T.tu = 0;
    for (int i = 0; i < T.mu; i++)
    {
        for (int j = 0; j < T.nu; j++)
        {
            int k = 0;
            cin >> k;
            if (k != 0)
            {
                T.data[T.tu].e = k;
                T.data[T.tu].i = i;
                T.data[T.tu].j = j;
                T.tu++;
            }
        }
    }
    RLSMatrix Q;
    get_rpos(M);
    get_rpos(T);
    matrix_multiple(M, T, Q);
    int p = 0;
    for (int i = 0; i < Q.mu; i++)
    {
        for (int j = 0; j < Q.nu; j++)
        {
            if (Q.data[p].i == i && Q.data[p].j == j)
            {
                cout << Q.data[p].e << " ";
                p++;
            }
            else
                cout << 0 << " ";
        }
        cout << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值