行逻辑链接的顺序表
使用三元组顺序表存储矩阵后,当需要提取矩阵某一行的非0元素时,需要遍历整个顺序表。
为了提高效率,可以在三元组的基础上,增加一个数组用于记录每一行第一个非0元素的存储位置(如果该行没有非0元素,记为-1)
- 注意:本类在实现时去掉了三元组中的行坐标,改为二元组,只记录了元素的纵坐标与值
二元组
每个二元组只记录非0元素的列号和元素值
#ifndef TWELEMNODE_H
#define TWELEMNODE_H
// 二元组类
template<class ElemType>
struct TwElemNode
{
// 数据成员:
int col; // 非零元素的列下标
ElemType item; // 非零元素的值
// 构造函数:
TwElemNode(); // 无参数的构造函数
TwElemNode(int c, ElemType v); // 已知数据域建立三元组
};
// 三元组类的实现部分
template<class ElemType>
TwElemNode<ElemType>::TwElemNode()
// 操作结果:构造空三元组
{
}
template<class ElemType>
TwElemNode<ElemType>::TwElemNode(int c, ElemType v)
// 操作结果:由已知数数据域构造三元组
{
col = c; // 列号
item = v; // 非零元素值
}
#endif
二元组表
#ifndef TWELEMMATRIX_H
#define TWELEMMATRIX_H
#include <stdlib.h>
#include <time.h>
#include "Assistance.h" // 辅助文件
#include "TwElemNode.h" // 二元组类
const int MAXN = 1000;
// 稀疏矩阵二元组顺序表类
template<class ElemType>
class TwElemMatrix
{
protected:
// 稀疏矩阵二元组顺序表的数据成员:
TwElemNode<ElemType> *TwElems; // 存储稀疏矩阵的二元组表
int* RowIndex; // 行指针数组
int maxSize; // 非零元素最大个数
int rows, cols, num; // 稀疏矩阵的行数,列数及非零元个数
void Add(int x, int r, int c, int value);//从x开始全部后移,x在第r行
void Delete(int x, int r);//将r行的x删除
public:
// 稀疏矩阵二元组顺序表的函数成员:
TwElemMatrix(int rs = DEFAULT_SIZE, int cs = DEFAULT_SIZE);
// 构造一个rs行cs列非零元素最大个数为size的空稀疏矩阵
~TwElemMatrix(); // 析构函数
int GetRows() const; // 返回稀疏矩阵行数
int GetCols() const; // 返回稀疏矩阵列数
int GetNum() const; // 返回稀疏矩阵非零元个数
Status SetElem(int r, int c, const ElemType &v); // 设置指定位置的元素值
Status GetElem(int r, int c, ElemType &v); // 求指定位置的元素值
TwElemMatrix(const TwElemMatrix<ElemType> ©); // 复制构造函数
TwElemMatrix<ElemType>& operator=(const TwElemMatrix<ElemType> ©);
// 赋值运算符重载
void Transpose();// 稀疏矩阵的转置算法
void Resize(int r, int c);//重新设置大小
void Show(); //显示矩阵
template <class ElemType> friend TwElemMatrix<ElemType> operator*(const TwElemMatrix<ElemType> &a, const TwElemMatrix<ElemType> &b);
};
// 稀疏矩阵二元组顺序表类的实现部分
template <class ElemType>
TwElemMatrix<ElemType>::TwElemMatrix(int r, int c)
// 操作结果: 构造一个r行c列非零元素最大个数为size的空稀疏矩阵
{
if (r < 1 || c < 1)
throw Error("行数或列数无效!"); // 抛出异常
maxSize = r * c; // 非零元素最大个数
rows = r; // 行数
cols = c; // 列数
num = 0; // 非零元素个数
TwElems = new TwElemNode<ElemType>[maxSize]; // 分配存储空间
RowIndex = new int[rows]; // 分配行储存空间
for (int i = 0; i < rows; i++)
{
RowIndex[i] = -1;
}
}
template <class ElemType>
TwElemMatrix<ElemType>::~TwElemMatrix()
// 操作结果:稀疏矩阵所占用空间
{
if (TwElems != NULL) delete[]TwElems; // 释放存储空间
}
template <class ElemType>
int TwElemMatrix<ElemType>::GetRows() const
// 操作结果:返回稀疏矩阵行数
{
return rows; // 返回行数
}
template <class ElemType>
int TwElemMatrix<ElemType>::GetCols() const
// 操作结果:返回稀疏矩阵列数
{
return cols; // 返回列数
}
template <class ElemType>
int TwElemMatrix<ElemType>::GetNum() const
// 操作结果:返回稀疏矩阵非零元个数
{
return num; // 返回非零元个数
}
template <class ElemType>
Status TwElemMatrix<ElemType>::SetElem(int r, int c, const ElemType &v)
// 操作结果:如果下标范围错,则返回RANGE_ERROR,如果溢出,则返回OVER_FLOW,否则返
// 回SUCCESS
{
if (r >= rows || c >= cols || r < 0 || c < 0)
return RANGE_ERROR; // 下标范围错
int pos;//待修改元素在数组中的位置
int line;//r行之后第一个有非0元的行
//确定待修改元素的位置
for (line = r + 1; line < rows && RowIndex[line] == -1; line++);//找到r行后第一个有非0元素的行
//r行后没有非零元素
if (line >= rows) {
if (RowIndex[r] == -1) {//本行元素为空,所以是最后一个元素
RowIndex[r] = num;
TwElems[num].col = c;
TwElems[num].item = v;
num++;
}
else {
for (pos = RowIndex[r]; pos <= num; pos++) {//在本行中找到插入位置
if (pos == num) {//该行中没找到
Add(pos, r, c, v);
break;
}
if (TwElems[pos].col == c) {//该位置已经有元素
if (v != 0) {//直接替换
TwElems[pos].item = v;
}
else {//需要删除该元素
Delete(pos, r);
}
break;
}
else if (TwElems[pos].col > c) {//该位置还没有元素
if (v != 0) {//插入该元素
Add(pos, r, c, v);
}
break;
}
}
}
}
else {//r行后有非零元素
if (RowIndex[r] == -1) {
if (v != 0) {//插入元素
Add(RowIndex[line], r, c, v);
}
}
else {
for (pos = RowIndex[r]; pos <= RowIndex[line]; pos++) {
if (pos == RowIndex[line]) {//该行中没找到
Add(pos, r, c, v);
break;
}
if (TwElems[pos].col == c) { //该位置有元素
if (v != 0) {
TwElems[pos].item = v;
}
else {
Delete(pos, r);
}
break;
}
else if (TwElems[pos].col > c && v != 0) {
Add(pos, r, c, v);
break;
}
}
}
}
return SUCCESS; // 成功
}
template <class ElemType>
Status TwElemMatrix<ElemType>::GetElem(int r, int c, ElemType &v)
// 操作结果:如果下标范围错,则返回RANGE_ERROR,否则返回SUCCESS,并用v返回指定位置元素值
{
if (r >= rows || c >= cols || r < 0 || c < 0)
return RANGE_ERROR; // 下标范围错
int i, j; // 工作变量
for (j = r + 1; j < rows && RowIndex[j] == -1; j++); // 第r行后第一个有非0元素的行
if (j >= rows) // r行后没有非零元素
{
for (i = RowIndex[r]; i >= 0 && i <= num - 1 && TwElems[i].col != c; i++);// 查找二元组位置
}
else
{
for (i = RowIndex[r]; i >= 0 && i <= RowIndex[j] - 1 && TwElems[i].col != c; i++);// 查找二元组位置
}
if (i >= 0 && TwElems[i].col == c) // 找到二元组
if ((j < rows && i < RowIndex[j]) || (j >= rows))
{
v = TwElems[i].item; // 用v返回指定位置元素值
return SUCCESS;
}
// 未找到二元组
v = 0; // 未找到二元组,表示0元素值
return SUCCESS; // 成功
}
template <class ElemType>
TwElemMatrix<ElemType>::TwElemMatrix(const TwElemMatrix<ElemType> ©)
// 操作结果:由稀疏矩阵copy构造新稀疏矩阵——复制构造函数
{
maxSize = copy.maxSize; // 最大非零元素个数
rows = copy.rows; // 复制行数
cols = copy.cols; // 复制列数
num = copy.num; // 复制非零元素个数
TwElems = new TwElemNode<ElemType>[maxSize]; // 为二元组分配存储空间
RowIndex = new int[rows]; // 为行指针数组分配储存空间
for (int i = 0; i < num; i++) // 复制二元组
TwElems[i] = copy.TwElems[i];
for (int i = 0; i < rows; i++) // 复制行指针数组
RowIndex[i] = copy.RowIndex[i];
}
template <class ElemType>
TwElemMatrix<ElemType>& TwElemMatrix<ElemType>::operator =(const TwElemMatrix<ElemType> ©)
// 操作结果:将稀疏矩阵copy赋值给当前稀疏矩阵——赋值运算符重载
{
if (© != this) {
maxSize = copy.maxSize; // 最大非零元素个数
if (TwElems != NULL) delete[]TwElems; // 释放存储空间
TwElems = new TwElemNode<ElemType>[maxSize]; // 分配存储空间
rows = copy.rows; // 复制行数
cols = copy.cols; // 复制列数
num = copy.num; // 复制非零元素个数
for (int i = 0; i < num; i++) // 复制二元组
TwElems[i] = copy.TwElems[i];
}
for (int i = 0; i < rows; i++)
{
RowIndex[i] = copy.RowIndex[i];
}
return *this;
}
template<class ElemType>
void TwElemMatrix<ElemType>::Transpose()
// 操作结果:稀疏矩阵的简单转置算法,结果放在二元组顺序表b中
{
TwElemMatrix<ElemType> b(cols, rows);
if (num > 0)
{
int i, j = 0, k;
for (i = 0; i < num; i++)
{
for (; j < rows && i >= RowIndex[j]; j++); // 确定元素行数
for (k = j - 1; k >= 0 && RowIndex[k] == -1; k--); // 向前寻找到第一个有非零元素的行,即为所求元素行
b.SetElem(TwElems[i].col, k, TwElems[i].item);
}
}
*this = b;
}
template<class ElemType>
void TwElemMatrix<ElemType>::Resize(int r, int c)
{
if (r < 1 || c < 1) {
throw Error("行数或列数无效!"); //抛出异常
}
if (TwElems != NULL) delete[]TwElems;
if (RowIndex != NULL) delete[]RowIndex;
maxSize = r * c;
rows = r;
cols = c;
num = 0;
TwElems = new TwElemNode<ElemType>[maxSize];
RowIndex = new int[rows];
for (int i = 0; i < rows; i++) {
RowIndex[i] = -1;
}
}
template<class ElemType>
void TwElemMatrix<ElemType>::Show()
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
ElemType temp; // 求元素值
this->GetElem(i, j, temp);
cout << temp << "\t"; // 显示元素值
}
cout << endl;
}
}
template<class ElemType>
void TwElemMatrix<ElemType>::Add(int x, int r, int c, int value)
//将x之后的所有元素后移
{
for (int i = num - 1; i >= x; i--) { //后移元素
TwElems[i + 1] = TwElems[i];
}
TwElems[x].col = c;
TwElems[x].item = value;
for (int i = r + 1; i < rows; i++) {//更新行指针
if (RowIndex[i] != -1) {
RowIndex[i]++;
}
}
if (RowIndex[r] == -1) { //更新本行的行指针
RowIndex[r] = x;
}
num++;
}
template<class ElemType>
void TwElemMatrix<ElemType>::Delete(int x, int r)
//删除r行的x
{
for (int i = x; i < num - 1; i++) { //前移元素
TwElems[i] = TwElems[i + 1];
}
for (int i = r + 1; i < rows; i++) { //更新行指针
if (RowIndex[i] != -1) {
RowIndex[i]--;
}
}
if (RowIndex[r] - 1 == 0) {
RowIndex[r] = -1;
}
num--;
}
template<class T>
TwElemMatrix<T> operator*(const TwElemMatrix<T> &a, const TwElemMatrix<T> &b)
{
TwElemMatrix<T> c(a.GetRows(), b.GetCols());
if (a.num*b.num != 0) {
int arow;//当前处理的a的行标,同时还是矩阵c的行号
int ccol;
for (arow = 0; arow < a.rows; arow++) {//遍历矩阵A的每一行
if (a.RowIndex[arow] == -1) {
continue;
}
int ctemp[MAXN] = { 0 }; //行累加器
c.RowIndex[arow] = c.num; //设置当前行的行指针
int tp; //矩阵a当前行的下一行第一个非0元素的位置
int line;
for (line = arow + 1; line < a.rows && a.RowIndex[line] == -1; line++);
if (line >= a.rows) {
tp = a.num;
}
else {
tp = a.RowIndex[line];
}
//对当前行的每一个非0元素进行处理
int brow = 0;
for (int p = a.RowIndex[arow]; p < tp; p++) {
brow = a.TwElems[p].col; //b中对应元素的行号
if (b.RowIndex[brow] == -1) {
continue;
}
int t;//矩阵b的当前行的下一行第一个非0元素的位置
int line;
for (line = brow + 1; line < b.rows && b.RowIndex[line] == -1; line++);
if (line >= b.rows) {
t = b.num;
}
else {
t = b.RowIndex[line];
}
//b对应位置上的元素与a当前位置元素相乘
for (int q = b.RowIndex[brow]; q < t; q++) {
ccol = b.TwElems[q].col;
ctemp[ccol] += a.TwElems[p].item*b.TwElems[q].item;
}
}
//释放累加器
for (ccol = 0; ccol < c.cols; ccol++) {
if (ctemp[ccol]) {
c.TwElems[c.num].col = ccol;
c.TwElems[c.num].item = ctemp[ccol];
c.num++;
}
}
}
}
return c;
}
#endif
辅助文件
#ifndef __ASSISTANCE_H__ // 如果没有定义__ASSISTANCE_H__
#define __ASSISTANCE_H__ // 那么定义__ASSISTANCE_H__
// 辅助软件包
// ANSI C++标准库头文件
#include <cstring> // 标准串操作
#include <iostream> // 标准流操作
#include <limits> // 极限
#include <cmath> // 数据函数
#include <fstream> // 文件输入输出
#include <cctype> // 字符处理
#include <ctime> // 日期和时间函数
#include <cstdlib> // 标准库
#include <cstdio> // 标准输入输出
#include <iomanip> // 输入输出流格式设置
#include <cstdarg> // 支持变长函数参数
#include <cassert> // 支持断言
using namespace std; // 标准库包含在命名空间std中
// 自定义类型
enum Status {SUCCESS, FAIL, UNDER_FLOW, OVER_FLOW,RANGE_ERROR, DUPLICATE_ERROR,
NOT_PRESENT, ENTRY_INSERTED, ENTRY_FOUND, VISITED, UNVISITED};
// 宏定义
#define DEFAULT_SIZE 1000 // 缺省元素个数
#define DEFAULT_INFINITY 1000000 // 缺省无穷大
// 辅助函数声明
char GetChar(istream &inStream = cin); // 从输入流inStream中跳过空格及制表符获取一字符
template <class ElemType >
void Swap(ElemType &e1, ElemType &e2); // 交换e1, e2之值
template<class ElemType>
void Display(ElemType elem[], int n); // 显示数组elem的各数据元素值
template <class ElemType>
void Write(const ElemType &e); // 显示数据元素
// 辅助类
class Error; // 通用异常类
char GetChar(istream &inStream)
// 操作结果:从输入流inStream中跳过空格及制表符获取一字符
{
char ch; // 临时变量
while ((ch = (inStream).peek()) != EOF // 文件结束符(peek()函数从输入流中接受1
// 字符,流的当前位置不变)
&& ((ch = (inStream).get()) == ' ' // 空格(get()函数从输入流中接受1字符,流
// 的当前位置向后移1个位置)
|| ch == '\t')); // 制表符
return ch; // 返回字符
}
// 通用异常类
#define MAX_ERROR_MESSAGE_LEN 100
class Error
{
private:
// 数据成员
char message[MAX_ERROR_MESSAGE_LEN];// 异常信息
public:
// 方法声明
Error(const char *mes = "一般性异常!"); // 构造函数
~Error(void) {}; // 析构函数
void Show() const; // 显示异常信息
};
// 通用异常类的实现部分
Error::Error(const char *mes)
// 操作结果:由mes构构通用异常对象
{
strcpy(message, mes); // 复制异常信息
}
void Error::Show()const
// 操作结果:显示异常信息
{
cout << message << endl; // 显示异常信息
}
template <class ElemType >
void Swap(ElemType &e1, ElemType &e2)
// 操作结果: 交换e1, e2之值
{
ElemType temp; // 临时变量
// 循环赋值实现交换e1, e2
temp = e1; e1 = e2; e2 = temp;
}
template<class ElemType>
void Display(ElemType elem[], int n)
// 操作结果: 显示数组elem的各数据元素值
{
for (int i = 0; i < n; i++)
{ // 显示数组elem
cout << elem[i] << " ";
}
cout << endl;
}
template <class ElemType>
void Write(const ElemType &e)
// 操作结果: 显示数据元素
{
cout << e << " ";
}
#endif
测试文件
#include "TwElemMatrix.h" // 稀疏矩阵的三元组顺序表
#include<Windows.h>
#include<vector>
int main()
{
char c = '1';
vector<TwElemMatrix<int>>a;
vector<TwElemMatrix<int>>::iterator it;
TwElemMatrix<int> b;
int n, m,p,value,i,j;
bool flag,statue=false;
while (c != '0') {
system("cls");
if (!a.empty()) {
for (int i = 0; i < a.size(); i++) {
cout << i << endl;
a[i].Show();
cout << endl;
}
}
cout << endl << "1.生成矩阵";
cout << endl << "2.删除矩阵";
cout << endl << "3.设置指定位置元素值";
cout << endl << "4.矩阵转置";
cout << endl << "5.矩阵乘法";
cout << endl << "选择功能(0~5):";
cin >> c;
switch (c)
{
case '1':
cout << endl << "请输入矩阵大小(如:4 5)" << endl;
cin >> n >> m;
while (n < 1 || m < 1) {
cout << "行数或列数无效!" << endl;
cin >> n >> m;
}
b.Resize(n, m);
cout << endl << "请输入矩阵" << endl;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> value;
b.SetElem(i, j, value);
}
}
a.push_back(b);
statue = true;
break;
case '2':
cout << endl << "请输入删除矩阵标号:" << endl;
while (cin >> i) {
if (i >= 0 && i < a.size()) {
break;
}
else {
cout << "标号范围超限,请重新输入" << endl;
}
}
it = a.begin() + i;
a.erase(it);
break;
case '3':
cout << endl << "请输入操作矩阵标号:" << endl;
while (cin >> i) {
if (i >= 0 && i < a.size()) {
break;
}
else {
cout << "标号范围超限,请重新输入" << endl;
}
}
cout << endl << "请输入坐标与元素值(-1 -1 -1结束):" << endl;
flag = true;
while(cin >> n >> m >> value){
if (n == -1 && m == -1 && value == -1) {
break;
}
while (a[i].SetElem(n, m, value) == 4) {
if (n == -1 && m == -1 && value == -1) {
flag = false;
break;
}
cout << "下标范围超限,请重新输入" << endl;
cin >> n >> m >> value;
}
if (!flag) {
break;
}
}
break;
case '4':
cout << endl << "请输入操作矩阵标号" << endl;
while (cin >> n) {
if (n >= 0 && n < a.size()) {
break;
}
else {
cout << "标号范围超限,请重新输入" << endl;
}
}
a[n].Transpose();
break;
case '5':
cout << endl << "请输入操作矩阵标号" << endl;
while (cin >> i >> j) {
if (i >= 0 && i < a.size() && j>=0 && j<a.size()) {
if (a[i].GetCols() != a[j].GetRows()) {
cout << "不满足相乘条件,请重新输入" << endl;
}
else {
break;
}
}
else {
cout << "标号范围超限,请重新输入" << endl;
}
}
b.Resize(a[i].GetRows(), a[j].GetCols());
b = a[i] * a[j];
a.push_back(b);
break;
default:
break;
}
}
system("PAUSE"); // 调用库函数system()
return 0; // 返回值0, 返回操作系统
}