通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

用十字链表构成稀疏矩阵时,为什么每行\列链表为循环链表

因为每行\列链表为循环链表可以解决数组 “不利于插入和删除数据” 的特点,将所有行链表的表头存储到一个数组(rhead),将所有列链表的表头存储到另一个数组(chead)中。

一、用十字链表构成稀疏矩阵时,为什么每行\列链表为循环链表

因为每行\列链表为循环链表可以解决数组 “不利于插入和删除数据” 的特点,将所有行链表的表头存储到一个数组(rhead),将所有列链表的表头存储到另一个数组(chead)中。

两个指针域分别指向所在行的下一个元素和所在列的下一个元素。

可以用如下的结构体来表示链表中的节点:

  1. typedef struct OLNode{
  2.     int i,j;//元素的行标和列标
  3.     int data;//元素的值
  4.     struct OLNode * right,*down;//两个指针域
  5. }OLNode, *OLink;

在此基础上,表示十字链表的结构体为:

  1. typedef struct
  2. {
  3.     OLink *rhead, *chead; //行和列链表头指针
  4.     int mu, nu, tu;  //矩阵的行数,列数和非零元的个数
  5. }CrossList;

以存储图 1 所示的矩阵为例,十字链表存储该矩阵的 C 语言实现代码为:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3.  
  4. typedef struct OLNode
  5. {
  6.     int i, j, e; //矩阵三元组i代表行 j代表列 e代表当前位置的数据
  7.     struct OLNode* right, * down; //指针域 右指针 下指针
  8. }OLNode, * OLink;
  9.  
  10. typedef struct
  11. {
  12.     OLink* rhead, * chead; //行和列链表头指针
  13.     int mu, nu, tu;  //矩阵的行数,列数和非零元的个数
  14. }CrossList;
  15.  
  16. void CreateMatrix_OL(CrossList* M);
  17. void display(CrossList M);
  18.  
  19. int main()
  20. {
  21.     CrossList M;
  22.     M.rhead = NULL;
  23.     M.chead = NULL;
  24.     CreateMatrix_OL(&M);
  25.  
  26.     printf(“输出矩阵M:\n”);
  27.     display(M);
  28.     return 0;
  29. }
  30.  
  31. void CreateMatrix_OL(CrossList* M)
  32. {
  33.     int m, n, t;
  34.     int num = 0;
  35.     int i, j, e;
  36.     OLNode* p = NULL, * q = NULL;
  37.     printf(“输入矩阵的行数、列数和非0元素个数:”);
  38.     scanf(“%d%d%d”, &m, &n, &t);
  39.     (*M).mu = m;
  40.     (*M).nu = n;
  41.     (*M).tu = t;
  42.  
  43.     if (!((*M).rhead = (OLink*)malloc((m + 1) * sizeof(OLink))) || !((*M).chead = (OLink*)malloc((n + 1) * sizeof(OLink))))
  44.     {
  45.         printf(“初始化矩阵失败”);
  46.         exit(0);
  47.     }
  48.   
  49.     for (i = 0; i <= m; i++)
  50.     {
  51.         (*M).rhead[i] = NULL;
  52.     }
  53.     for (j = 0; j <= n; j++)
  54.     {
  55.         (*M).chead[j] = NULL;
  56.     }
  57.  
  58.     while (num < t) {
  59.         scanf(“%d%d%d”, &i, &j, &e);
  60.         num++;
  61.         if (!(p = (OLNode*)malloc(sizeof(OLNode))))
  62.         {
  63.             printf(“初始化三元组失败”);
  64.             exit(0);
  65.         }
  66.         p->i = i;
  67.         p->j = j;
  68.         p->e = e;
  69.  
  70.         //链接到行的指定位置
  71.         //如果第 i 行没有非 0 元素,或者第 i 行为数不多的非 0 元素位于当前元素的右侧,直接将该元素放置到第 i 行的开头
  72.         if (NULL == (*M).rhead[i] || (*M).rhead[i]->j > j)
  73.         {
  74.             p->right = (*M).rhead[i];
  75.             (*M).rhead[i] = p;
  76.         }
  77.         else
  78.         {
  79.             //找到当前元素的位置
  80.             for (q = (*M).rhead[i]; (q->right) && q->right->j < j; q = q->right);
  81.             //将新非 0 元素插入 q 之后
  82.             p->right = q->right;
  83.             q->right = p;
  84.         }
  85.  
  86.         //链接到列的指定位置
  87.         //如果第 j 列没有非 0 元素,或者第 j 列为数不多的非 0 元素位于当前元素的下方,直接将该元素放置到第 j 列的开头
  88.         if (NULL == (*M).chead[j] || (*M).chead[j]->i > i)
  89.         {
  90.             p->down = (*M).chead[j];
  91.             (*M).chead[j] = p;
  92.         }
  93.         else
  94.         {
  95.             //找到当前元素要插入的位置
  96.             for (q = (*M).chead[j]; (q->down) && q->down->i < i; q = q->down);
  97.             //将当前元素插入到 q 指针下方
  98.             p->down = q->down;
  99.             q->down = p;
  100.         }
  101.     }
  102. }
  103.  
  104. void display(CrossList M) {
  105.     int i,j;
  106.     //一行一行的输出
  107.     for (i = 1; i <= M.mu; i++) {
  108.         //如果当前行没有非 0 元素,直接输出 0
  109.         if (NULL == M.rhead[i]) {
  110.             for (j = 1; j <= M.nu; j++) {
  111.                 printf(“0 “);
  112.             }
  113.             putchar(‘\n’);
  114.         }
  115.         else
  116.         {
  117.             int n = 1;
  118.             OLink p = M.rhead[i];
  119.             //依次输出每一列的元素
  120.             while (n <= M.nu) {
  121.                 if (!p || (n < p->j) ) {
  122.                     printf(“0 “);
  123.                 }
  124.                 else
  125.                 {
  126.                     printf(“%d “, p->e);
  127.                     p = p->right;
  128.                 }
  129.                 n++;
  130.             }
  131.             putchar(‘\n’);
  132.         }
  133.     }
  134. }

运行结果:

输入矩阵的行数、列数和非0元素个数:3 4 4

1 1 3

1 4 5

2 2 -1

3 1 2

输出矩阵M:

3 0 0 5

0 -1 0 0

2 0 0 0

延伸阅读:

二、稀疏矩阵的十字链表存储

当矩阵的非零元个数和位置在操作过程中变化较大时,就不宜采用顺序存储结构来表示三元组的线性表。对这种类型的矩阵,采用链式存储结构表示三元组的线性表更为恰当。

在链表中,每个非零元可用一个含 5 个域的结点表示,其中 i , j , e 这 3 个域分别表示该非零元所在的行、列和非零元的值,向右域 right 用以链接同一行中下一个非零元,向下域 down 用以链接同一列中下一个非零元。

同一行的非零元通过 right 域链接成一个线性链表,同一列的非零元通过 down 域链接成一个线性链表,每个非零元既是某个行链表中的一个结点,又是某个列链表中的一个结点,整个矩阵构成了一个十字交叉的链表,故称这样的存储结构为十字链表。

可用两个分别存储行链表的头指针和列链表的头指针的一维数组表示。

相关文章