利用三元组表表示稀疏矩阵时,若矩阵的运算使非零元素的个数发生变化,就必须对三元组表进行插入、删除,也就是说必须移动三元组表中的元素,由于三元组表是顺序存储结构,所以这些操作将花费大量的时间,十字链表可以克服三元组表的上述缺点。
在十字链表中,数组的每一行的非零元素结点构成一个带头结点的循环链表,每一列的非零元素结点也构成一个带头结点的循环链表,这种组织方法使同一非零元素结点既处在某一行的链表中,又处在某一列的链表中。因此非零元素结点中设有两个指针域:指针域down指向其同列的下一个非零元素的结点,right域指向其同行的下一个非零元素结点。除这两个域外,结点中还应设有存放该非零元素的行值、列值、元素值的域,设他们分别为row、col和e。十字链表中非零元素结点的结构如下所示:
为了使整个链表中的结点结构一致,我们规定行(列)循环链表的表头结点和表中非零元素的结点一样,也设5个域,并且均置表头结点的行域和列域为零。
由于行表头结点不使用down域,而列表头结点不使用right域,因此,第i行的行表头结点和第i列的列表头结点可以合用一个结点,称为行列表头结点。
由于行表头结点的数据域没有意义的,而且我们希望将行列表头结点组织在一个循环链表中,因此,使用C语言中共用体的概念,将这个域作为指针域,将各行列表头链接起来。
我门为整个十字链表再设一个总表头结点,其row域和col域的值分别是稀疏矩阵的行数和列数,行列指针无意义,用指针域(非零元素结点的元素值域,行列表头结点相链的指针域)指向第一个列表头结点。设head为指向总表头结点的指针,因此,只要给定head指针值,便可取得稀疏矩阵的全部信息了。
十字链表的结构类型说明:
typedef int ElemType;typedef struct OLNode{ int row, col; union { struct OLNode *next; //表头结点使用next域 ElemType e; //表中元素结点使用e域 }uval; struct OLNode *down, *right;}OLNode,*OLink;建立十字链表的算法分为两步:(1)建立表头结点的循环链表。读入矩阵的行数、列数和非零元素的个数。因为行、列链表共享同一组表头结点,所以表头结点的个数应是行数、列数中的较大者。建立整个十字链表的头结点*head以及所有行、列链表的头结点,将头结点通过next域链接成循环链表。初始时每一行、列链表都是空的循环链表。
(2)依次读入非零元素的三元组表(row,col,e),生成一个结点*p,然后将其插入到第row行的行链表的正确位置上,以及第col列的列链表的正确位置上。*p的正确位置应为:在行链表上,首先查找到第row行的头结点,然后沿着结点的right域找到第一个列号大于col的结点*(q->right),而*(q->right)即为*p及结点的后继,*q即为*p结点的前驱,*p应插入到*q结点之后。如果行链表上所有结点的列号均小于col,则*p应插入到行链表的表尾。查找第col列的列链表的正确插入位置与此类似。
完整代码如下:
#include<iostream>using namespace std;#define max 100typedef int ElemType;typedef struct OLNode{ int row, col; union { struct OLNode *next; //表头结点使用next域 ElemType e; //表中元素结点使用e域 }uval; struct OLNode *down, *right;}OLNode,*OLink;OLink CreateCrossList() { //建立十字链表 int m, n, t,row,col,e, maxmn; OLink h[max],p,q; cout << "请输入行数、列数以及非零元素的个数" << endl; cin >> m >> n >> t; if (m > n) maxmn = m; else maxmn = n; OLink head = (OLNode*)malloc(sizeof(OLNode)); head->row = m; head->col = n; h[maxmn] = head; //h[maxmn+1]为一组指示行列表头结点的指针 for (int i = 0; i < maxmn;i++) { //建立表头结点的循环链表 p= (OLNode*)malloc(sizeof(OLNode)); p->row = 0; p->col = 0; p->down = p; p->right = p; h[i] = p; if (i == 0) head->uval.next = p; else h[i - 1]->uval.next = p; } p->uval.next = head; //最后一个结点指向表头结点*head for (int num = 1; num <= t;num++) { cout << "请输入一个非零元素的三元组" << endl; cin >> row >> col >> e; p= (OLNode*)malloc(sizeof(OLNode)); //生成结点 p->row = row; p->col = col; p->uval.e = e; q = h[row]; while (q->right!=h[row] && q->right->col<col) { //查*p在第row行的插入位置 q = q->right; } p->right = q->right; q->right = p; //将*p插入到第row行的循环链表中 q = h[col]; while (q->down != h[col] && q->down->row < row) {//查*p在第col列的插入位置 q = q->down; } p->down = q->down; q->down = p; //将*p插入到第col列的循环链表中 } return head;}void PRint(OLink head) { OLink p = head->uval.next; int m = 0,n = 0; while (m != head->row) { p = p->right; while (n != head->col) { if (m == p->row && n == p->col && p->uval.e!=NULL) { cout << p->uval.e << " "; p = p->right; } else { cout << "0 "; } n++; } n = 0; m++; p = p->uval.next; cout << endl; }}void main() { OLink list; list = CreateCrossList(); cout << "链表内容为:" << endl; print(list); system("pause");}
新闻热点
疑难解答