十字链表,用于存储 稀疏矩阵 或 有向图。
在实现非二元LDPC码译码过程中,需要用十字链表存储校验矩阵H。
网上找到 博客 http://blog.youkuaiyun.com/zhuyi2654715/article/details/6729783 讲解的十分清晰
上图可以 清晰地展现十字链表的数据结构 : 整个十字链表的头指针指向横向和纵向的头指针数组,再由每个对应行和列上的头指针作为链表头,指向各个稀疏节点。
#include <stdio.h>
#include <malloc.h>
typedef struct olnode
{
int i;//表示矩阵的行号
int j;//表示矩阵的列号
int value;//或者值的类型设为element_type
struct olnode *right;//横向下一个节点的地址
struct olnode *down; //纵向下一个节点的地址
}olnode,*olist;
typedef struct crosslist
{
olist *rhead,*chead;
int rownum;//矩阵行数
int colnum;//矩阵列数
int elenum;//矩阵非零元素数
}crosslist;
void creatOList(crosslist *H);
void display(crosslist *H);
void creatOList(crosslist *H)
{
FILE *fp;
fp = fopen("Orthogonal_List_matrix.txt","r");
int i,j;
int m,n,ele;//不要直接把数据读入数据结构中,设置中间值,进行检测,确定后拷贝到数据结构中
olnode *p,*q;
int flag;
//建立稀疏矩阵,且用十字链表存储
if (H->rhead)//如果原先存在,销毁
{
//destroy();
}
do
{
flag = 1;
//printf("输入需要创建的矩阵的行数、列数以及非零元的个数\n");
fscanf(fp,"%d%d%d",&m,&n,&ele);
if (m<0||n<0||ele<0||ele>m*n)
{
flag = 0;
}
}
while (!flag);
H->rownum = m;
H->colnum = n;
H->elenum = ele;
//创建横向和纵向的 头指针数组 ,并初始化
H->rhead = (olist*)malloc(sizeof(olist)*(H->rownum+1));
//H->chead = (olnode*)malloc(sizeof(olnode)*(H->colnum+1));
H->chead = (olist*)malloc(sizeof(olist)*(H->colnum+1));
if (!H->rhead||!H->chead)
{
exit(-1);
}
for (i = 1;i<H->rownum+1 ;i++ )
{
H->rhead[i] = NULL;
}
for (i = 1;i<H->colnum+1 ;i++ )
{
H->chead[i] = NULL;
}
//输入节点并插入表中
i = 1;
while (i<=H->elenum)
{
do
{
flag = 1;
//printf("输入第%d个结点行号、列号以及值",i);
//scanf("%d%d%d",&m,&n,&ele);
fscanf(fp,"%d%d%d",&m,&n,&ele);
if (m<0||n<0)
{
flag = 0;
}
else
i++;
}
while (!flag);
p = (olnode*)malloc(sizeof(olnode));//建立新节点并存入数据
if (!p)
{
exit(-1);
}
p->i = m;
p->j = n;
p->value = ele;
//将节点插入
/*插入的两种情况:
1.这一行中没有节点=>直接插入
2.这一行中有节点=>找到正确位置插入
*/
//行
if (H->rhead[m] == NULL || H->rhead[m]->j > n)//一行为空或者为一行中下标最小的...试试把插入合在一起
{
p->right = H->rhead[m];//插入在第一个节点
H->rhead[m] = p;//头指针指向第一个节点
}
else
{
//在一行中从头寻找插入位置
for (q = H->rhead[m]; q->right && q->right->j < n ;q = q->right );
p->right = q->right;
q->right = p;
}
//列
if (H->chead[n] == NULL || H->chead[n]->j > m)
{
p->down = H->chead[n];
H->chead[n] = p;
}
else
{
for (q = H->chead[n];q->down && q->down->i < m ;q = q->down );
p->down = q->down;
q->down = p;
}
}
}
void display(crosslist *H)
{
int i;
olnode *p;
for (i = 1;i<=H->rownum ;i++ )
{
p = H->rhead[i];
while (p)
{
printf("(%d,%d)=%d\n",p->i,p->j,p->value);
p = p->right;
}
}
}
int main()
{
crosslist *H;
H = (crosslist*)malloc(sizeof(crosslist));
creatOList(H);
display(H);
return 0;
}
实现时,由于读取校验矩阵H时需要链表是双向的,才能进行双向读取,所有每个节点需要再加入两个指针,如下:
typedef struct pnode
{
int value;//a = 0 ~ q-1
int col;
int row;
pnode *right,*left,*up,*down;
//double *pmn;
}pnode,*plist;
typedef struct crosslist
{
plist* right;
plist* down;
}crosslist;