DS_存储 稀疏矩阵 的十字链表(C++实现)

关于稀疏矩阵,就是值为0的元素数量很多的矩阵。如果把0元素位置看成空白,非零看成黑点,稀疏矩阵就像是一张照片,广阔的天空中只有远方的几只鸟。我也不知道这么理解对不对,瞎猜的。

至于矩阵的应用,书上说计算机图形学,工程技术中会用到,但现在我没整过具体的东西,所以就关于稀疏矩阵有啥用,以后碰到了再补上。

那么现在如何存储稀疏矩阵呢?怎样才能做到存的空间小,修改起来方便,使用的时候能快速呢。目前我只知道两种书上提到的方法:
1.三元组线性表
2.十字链表OrthogonalList

现在,就十字链表,使用C++实现。先说下十字链表的数据结构,然后说下具体实现。

十字链表的数据结构
链表嘛,就是一串羊肉串,一小块羊肉就是一个结点,结点里有骨头也有肉。十字链表就是一维链表+另一维链表。

(1)这是结点:
row是行,col是列,value/next是联合(要么是一个T类型的值,要么是一个OrthogonalNode *类型的地址),down是同一列的下一个元素的地址,right是同一行的下一个元素的地址
row是行,col是列,value/next是联合(要么是一个T类型的值,要么是一个OrthogonalNode *类型的地址

(2)这是十字链表的例子:

这里是引用教科书上的例子

在这里插入图片描述
很容易看出十字链表的存储原理,本质上就是个二维的链表

十字链表的实现

// DS_OrthogonalList.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

template<class T>
struct OrthogonalNode
{
	int m, n;
	OrthogonalNode<T> *down, *right;
	union
	{
		T value;
		OrthogonalNode<T> *next;
	};
};

template<class T>
class OrthogonalList
{
public:
	OrthogonalList<T>(T *matrix, int row, int col);
	void insertE(OrthogonalNode<T> *p);
	void deleteE(OrthogonalNode<T> *p);
	OrthogonalNode<T> *Gethead(int i);
	OrthogonalNode<T> *head;
private:
	int rows, cols, numbers;
	vector<OrthogonalNode<T> *> orthogonalArray;
};

int main()
{
	int matrix[] = { 3, 0, 0, 1, 0, -4, 8, 0, 2, 0, 0, 6 };
	OrthogonalList<int> oList(matrix, 3, 4);

	//test:遍历所有结点,如果成功遍历,说明十字链表的构造成功
	OrthogonalNode<int> *me = oList.head->right, *subMe = me->down;
	while (oList.head != me)
	{
		while (me != subMe)
		{
			cout << "(" << subMe->m << "," << subMe->n << "," << subMe->value << ") ";
			subMe = subMe->down;
		}
		cout << endl;
		me = me->next;
		subMe = me->down;
	}
	system("pause");
    return 0;
}

template<class T>
OrthogonalList<T>::OrthogonalList(T * matrix, int row, int col)
{
	//初始化总链头,头结点包含非(row行,col列,非零元素个数)
	if (!orthogonalArray.empty())//如果向量不空,那么就将向量重置为临时对象
		vector<OrthogonalNode<T> *>().swap(orthogonalArray);
	rows = row;
	cols = col;
	head = new OrthogonalNode<T>;
	//head->value = ?,后面处理
	head->down = NULL;
	head->right = head;
	head->m = row;
	head->n = col;
	

	//初始化子链头,头结点对应为base行base列
	int maX = max(row, col);
	OrthogonalNode<T> *me = head;
	for (int base = 0; base <= maX - 1; ++base)
	{
		OrthogonalNode<T> *subHead = new OrthogonalNode<T>;
		subHead->next = head;
		subHead->down = NULL;
		subHead->right = NULL;
		subHead->m = 0;
		subHead->n = 0;
		
		if (head == me)
			me->right = subHead;
		else
			me->next = subHead;
		me = subHead;
		orthogonalArray.push_back(subHead);
	}

	//遍历,当base行i列为非零元素,则插入到链表中,非零元素总数numbers加一
	for (int base = 0; base <= row - 1; ++base)
		for (int i = 0; i <= col - 1; ++i)
			if (0 != matrix[base*col + i])
			{
				OrthogonalNode<T> *temp = new OrthogonalNode<T>;
				temp->m = base;
				temp->n = i;
				temp->value = matrix[base*col + i];
				insertE(temp);

				++orthogonalArray[base]->m;
				++orthogonalArray[i]->n;
				++numbers;
			}

	head->value = numbers;//终于,知道了元素的总个数
}

template<class T>
void OrthogonalList<T>::insertE(OrthogonalNode<T>* p)
{
	//将结点插入到对应p->m行的链表中
	OrthogonalNode<T> *rowHead = orthogonalArray[p->m], *colHead = orthogonalArray[p->n],
		*before = rowHead, *after = before->right;
	while (rowHead != after && NULL != after)
	{
		if (after->n > p->n)
			break;
		before = before->right;
		after = after->right;
	}
	before->right = p;
	p->right = after;
	if (NULL == after)
		p->right = rowHead;

	//将结点插入到对应p->n列的链表中
	before = colHead; after = before->down;
	while (colHead != after && NULL != after)
	{
		if (after->m > p->m)
			break;
		before = before->down;
		after = after->down;
	}
	before->down = p;
	p->down = after;
	if (NULL == after)
		p->down = colHead;
}

template<class T>
void OrthogonalList<T>::deleteE(OrthogonalNode<T>* p)
{
	//和insert同理,省略
}

template<class T>
OrthogonalNode<T>* OrthogonalList<T>::Gethead(int i)
{
	return nullptr;
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值