下面有个10×10的稀疏数组,使用十字链表法进行存储压缩。如果直接存储所有的元素,需要存储100个元素,但是使用十字链表存储,就可以只用存储非0的元素。
使用十字链表存储稀疏矩阵的优点:可以直接找到某一行或者某一列的非0元素。而使用三元组存储稀疏矩阵,就要通过遍历整个三元组列表判断每一个三元组里面的行值或者列值,才能直到某行有或没有非0元素。
十字链表存储的图画介绍:
压缩与解压缩结果:
C语言代码实现:
#include <cstdio>
//
// Created by wtk on 22-12-2.
//
//每一个非0元素的结点都以结点的形式存储
typedef struct Node{
//第几行
int row;
//第几列
int column;
//非0元素值
int value;
//指向该列的下一个非0元素
struct Node *down;
//指向该行下一个非0元素
struct Node *right;
}Node;
//定义行头和列的结构体
typedef struct{
//指向该行或该列的第一个非0元素值的结点
Node *next;
}Head;
/**
* 稀疏矩阵压缩-十字链表存储压缩法
* @param sparse_array 待压缩的稀疏矩阵
* @param rowHead 行头
* @param columnHead 列头
*/
void compress(int sparse_array[10][10], Head rowHead[10], Head columnHead[10]){
//初始化行头和列头
for(int i = 0; i < 10; i++){
rowHead[i].next = NULL;
columnHead[i].next = NULL;
}
/**
* 压缩
*/
for(int row = 0; row < 10; row++){
for(int column = 0; column < 10; column++){
if(sparse_array[row][column] != 0){
//非0元素,进行存储
Node *node = new Node;
node->row = row+1;
node->column = column+1;
node->value = sparse_array[row][column];
node->down = NULL;
node->right = NULL;
//将元素连接到行头
if(rowHead[row].next == NULL){
//该元素是当前行的第一个非0元素,直接插入
rowHead[row].next = node;
} else{
Node *p;
//不是当前行的第一个非0元素,先找到当前行的最后一个元素
for(p = rowHead[row].next; p->right != NULL; p = p->right);
p->right = node;
}
//将元素连接到列头的当前列
if(columnHead[column].next == NULL){
//该元素是当前列的第一个非0元素,直接插入
columnHead[column].next = node;
} else{
Node *p;
//不是当前行的第一个非0元素,先找到当前列的最后一个元素
for(p = columnHead[column].next; p->down != NULL; p = p->down);
p->down = node;
}
}
}
}
}
/**
* 稀疏数组十字链表存储压缩法的解压缩
* @param sparse_array 一个空的矩阵
* @param rowHead 经压缩后得到的行头
* @param columnHead 经压缩后得到的列头
*/
void decompress(int sparse_array[10][10],Head rowHead[10], Head columnHead[10]){
//稀疏矩阵的初始化,把所有值都初始化为0
for(int i = 0; i < 10; i++){
for(int k = 0; k < 10; k++){
sparse_array[i][k] = 0;
}
}
//从行头开始进行恢复
for(int i = 0; i < 10; i++){
if(rowHead[i].next == NULL){
//当前行没有非0元素,跳过该行的操作
continue;
}
Node *p;
//p不断指向该行的下一个非0元素,直到指向最后一个非0元素之后才结束循环
for(p = rowHead[i].next; p != NULL; p = p->right){
int value = p->value;
int row = p->row;
int column = p->column;
//恢复到稀疏矩阵中的指定位置
sparse_array[row-1][column-1] = value;
}
}
//从列头开始进行恢复
for(int i = 0; i < 10; i++){
if(columnHead[i].next == NULL){
//当前列没有非0元素,跳过后面操作
continue;
}
Node *p;
//p不断指向该列的下一个非0元素,直到指向最后一个非0元素之后才结束循环
for(p = columnHead[i].next; p != NULL; p = p->down){
int value = p->value;
int row = p->row;
int column = p->column;
//恢复到稀疏矩阵中的指定位置
sparse_array[row-1][column-1] = value;
}
}
}
//打印10x10的矩阵
void print_sparse(int sparse_array[10][10]){
for(int i = 0; i < 10; i++){
for(int k = 0; k < 10; k++){
printf("%d ", sparse_array[i][k]);
}
printf("\n");
}
}
int main(){
//定义10x10的稀疏矩阵(当然稀疏矩阵的非0元素要不多于5%,这里的非0 元素有8个)
int sparse_array[10][10] = {
{0,0,0,0,8,0,1,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,5,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,6},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,6,9,0,0,0,0,0},
{3,0,0,0,0,0,0,0,0,0}
};
printf("待压缩的矩阵:\n");
print_sparse(sparse_array);
//定义行头和列头,用来指向每行每列的非0元素
Head rowHead[10];
Head columnHead[10];
//压缩
compress(sparse_array,rowHead,columnHead);
//解压缩
//定义一个新的矩阵
int new_sparse_array[10][10];
decompress(new_sparse_array, rowHead, columnHead);
//打印new_sparse_array查看恢复结果
printf("从压缩结果恢复的矩阵:\n");
print_sparse(new_sparse_array);
return 0;
}