1. 程式人生 > >看資料結構寫程式碼(20)稀疏矩陣(順序儲存方式)

看資料結構寫程式碼(20)稀疏矩陣(順序儲存方式)

雜談:昨天辭職了,告別了繁重又無意義的工作。準備在家專心學習資料結構,好好磨練自己的基本功。

在寫這個小例子的時候遇到了 stack overflow(棧溢位)的問題,是 自己 分配了 過大的 棧變數,導致棧溢位。說實話,這還是 第一次 遇到,呵呵,別笑話我。看到網上的部落格在 說這個問題,還提起一些 作業系統術語,自己還真是 一知半解。好好努力,打好基本功吧。騷年。

進入正題:

當矩陣 的 有用資訊非常少時,我們考慮將矩陣壓縮儲存。這就涉及到 特殊矩陣 和 稀疏矩陣。

特殊矩陣 指的是 有一定規律的 矩陣,這個矩陣 我們 只儲存 部分 有用資訊,其餘的資訊 可以通過 公式 轉換 求得。例如 對稱矩陣,我們按行儲存主對角線以下(包括主對角線)的元素,其餘元素 我們可以通過 下面的公式求得。


稀疏矩陣,指的事沒有一定規律的矩陣,並且  有用資訊總數/矩陣總數 小於等於 0.05 的時候,我們稱之為 稀疏矩陣。

稀疏矩陣的表示方式有三種:1.三元組 2. 行邏輯連結順序表 3 .十字連結串列 

前兩種 是 順序的儲存方式,第三種 是連結串列的儲存方式。 

下面程式碼給出的 是行邏輯連結順序表的方式,這種方式 只是 比 三元組的 方式 多 了 一個存放 每行首元素位置的陣列,這樣使矩陣在矩陣乘法 和 矩陣 加減法 帶來了 很大的便利。

歡迎指出 程式碼 bug,下面上程式碼

// Sparse Matrix.cpp : 定義控制檯應用程式的入口點。
//
//稀疏矩陣的順序儲存方式實現(行邏輯連結資料表)

#include "stdafx.h"

//#define MATRIX_MAX_SIZE	10000
//#define MATRIX_MAX_ROW	500
#define MATRIX_MAX_SIZE	100
#define MATRIX_MAX_ROW	50
enum E_State
{
	E_State_Error = 0,
	E_State_Ok = 1,
};
typedef int ElementType;

//矩陣元素結構
struct MatrixData
{
	int row;//行
	int col;//列
	ElementType data;//資料
};

struct SMatrix
{
	MatrixData base[MATRIX_MAX_SIZE];
	int rPos[MATRIX_MAX_ROW];//儲存每行第一個元素在陣列中的位置,並且保留了 最後一行的 邊界值
	int rowNum;//行數
	int colNum;//列數
	int totalNum;//總數
};

void SMatrixInit(SMatrix * matrix,int * base,int row,int col){
	matrix->rowNum = row;
	matrix->colNum = col;
	int totalNum = 0;
	for (int i = 0; i < row; i++)
	{
		int lastRowTotal = totalNum;//記錄從第一行到 上一行的總數
		for (int j = 0; j < col; j++)
		{
			ElementType data = base[i*col+j];
			if (data != 0)
			{
				matrix->base[totalNum].row = i;
				matrix->base[totalNum].col = j;
				matrix->base[totalNum].data = data;
				totalNum++;
			}
		}
		matrix->rPos[i] = lastRowTotal;
	}
	matrix->rPos[row] = totalNum;//為了 矩陣相乘,新增 邊界條件
	matrix->totalNum = totalNum;
}

//普通轉置 時間複雜度 O(m.colNum * m.totalNum)
//遍歷矩陣m,將第一列到 最後 一列 的矩陣元素加入到 t矩陣中

void SMatrixTranspose(SMatrix m,SMatrix * t){
	t->totalNum = m.totalNum;
	t->rowNum = m.colNum;
	t->colNum = m.rowNum;
	int total = 0;
	for (int i = 0; i < m.colNum; i++)
	{
		for (int j = 0; j < m.totalNum; j++)
		{
			MatrixData data = m.base[j];
			if (data.col == i)
			{
				t->base[total].row = data.col;
				t->base[total].col = data.row;
				t->base[total].data = data.data;
				total++;
			}
		}
	}

}


//快速轉置 時間複雜度為 O(m.totalNum + m.colNum)
void SMatrixQuickTranspose(SMatrix m,SMatrix * t){
	t->totalNum = m.totalNum;
	t->rowNum = m.colNum;
	t->colNum = m.rowNum;
	if (m.totalNum == 0)
	{
		return;
	}
	int col[MATRIX_MAX_ROW] = {0};
	for (int i = 0; i < m.totalNum; i++)//計算矩陣m 每一列 的 元素個數
	{
		MatrixData data = m.base[i];
		col[data.col+1]++;
	}
	//計算 矩陣M 每一列 起始元素 在陣列中的位置
	for (int i = 1; i < m.colNum; i++)
	{
		col[i] = col[i-1] + col[i];
	}
	for (int i = 0; i < m.totalNum; i++)
	{
		MatrixData data = m.base[i];
		int colBase = col[data.col];
		t->base[colBase].col = data.row;
		t->base[colBase].row = data.col;
		t->base[colBase].data = data.data;
		col[data.col]++;
	}
	//最後設定 每行 首元素地址
	t->rPos[0] = 0;
	for (int i = 1; i < t->rowNum; i++)
	{
		t->rPos[i] = col[i-1];
	}

}

//矩陣相加
E_State SMatrixAdd(SMatrix m1,SMatrix m2,SMatrix * sum){
	if (m1.rowNum != m2.rowNum || m1.colNum != m2.colNum)
	{
		return E_State_Error;
	}
	int totalNum = 0;
	sum->rowNum = m1.rowNum;
	sum->colNum = m1.colNum;
	for (int i = 0; i < m1.rowNum; i++)
	{
		int m1Start = m1.rPos[i];
		int m1End = m1.rPos[i+1];
		int m2Start = m2.rPos[i];
		int m2End = m2.rPos[i+1];
		sum->rPos[i] = totalNum;
		while (m1Start < m1End && m2Start < m2End)
		{
			MatrixData m1Data = m1.base[m1Start];
			MatrixData m2Data = m2.base[m2Start];
			int m1Col = m1Data.col;
			int m2Col = m2Data.col;
			if (m1Col == m2Col)//相等
			{
				int sumData =m1Data.data + m2Data.data;
				if (sumData != 0)
				{
					sum->base[totalNum].row = i;
					sum->base[totalNum].col = m1Col;
					sum->base[totalNum].data = sumData;
					totalNum++;
				}
				m1Start++;
				m2Start++;
			}
			else if (m1Col < m2Col)//m2 的列 大
			{
				sum->base[totalNum].row = i;
				sum->base[totalNum].col = m1Col;
				sum->base[totalNum].data = m1Data.data;
				totalNum++;
				m1Start++;
			}
			else//m1的列大
			{
				sum->base[totalNum].row = i;
				sum->base[totalNum].col = m2Col;
				sum->base[totalNum].data = m2Data.data;
				totalNum++;
				m2Start++;
			}
		}
		while (m1Start < m1End)
		{
			MatrixData m1Data = m1.base[m1Start];
			int m1Col = m1Data.col;
			sum->base[totalNum].row = i;
			sum->base[totalNum].col = m1Col;
			sum->base[totalNum].data = m1Data.data;
			totalNum++;
			m1Start++;
		}
		while (m2Start < m2End)
		{
			MatrixData m2Data = m2.base[m2Start];
			int m2Col = m2Data.col;
			sum->base[totalNum].row = i;
			sum->base[totalNum].col = m2Col;
			sum->base[totalNum].data = m2Data.data;
			totalNum++;
			m2Start++;
		}
	}
	sum->rPos[sum->rowNum] = totalNum;
	sum->totalNum = totalNum;
	return E_State_Ok;
}

//矩陣相減

E_State SMatrixSub(SMatrix m1,SMatrix m2,SMatrix * sub){
	if (m1.rowNum != m2.rowNum || m1.colNum != m2.colNum)
	{
		return E_State_Error;
	}
	for (int i = 0; i < m2.totalNum; i++)
	{
		m2.base[i].data = -m2.base[i].data;
	}
	E_State state = SMatrixAdd(m1,m2,sub);
	return state;

}

//矩陣相乘
E_State SMatrixMult(SMatrix  m1,SMatrix  m2,SMatrix * result){
	if (m1.colNum != m2.rowNum)//排除不合法的情況..
	{
		return E_State_Error;
	}
	result->rowNum = m1.rowNum;
	result->colNum = m2.colNum;
	result->totalNum = 0;
	if (m1.totalNum * m2.totalNum != 0)
	{
		for (int m1Row = 0; m1Row < m1.rowNum; m1Row++)
		{
			int m1End = m1.rPos[m1Row+1];
			int colCount[MATRIX_MAX_ROW] = {0};
			for (int m1Start = m1.rPos[m1Row]; m1Start < m1End; m1Start++)
			{
				MatrixData m1Data = m1.base[m1Start];
				int col = m1Data.col;
				for (int m2start = m2.rPos[col]; m2start < m2.rPos[col+1]; m2start++)
				{
					MatrixData m2Data = m2.base[m2start];
					colCount[m2Data.col] += m1Data.data * m2Data.data;
				}
			}
			result->rPos[m1Row] = result->totalNum;
			for (int col = 0; col < m2.colNum; col++)
			{
				if (colCount[col] != 0)
				{
					result->base[result->totalNum].col = col;
					result->base[result->totalNum].row = m1Row;
					result->base[result->totalNum].data = colCount[col];
					result->totalNum ++;
				}
			}
		}
		result->rPos[result->rowNum] = result->totalNum;
	}
	return E_State_Ok;
}

//遍歷矩陣
void SMatricTraverse(SMatrix matrix){
	int rowNum = 0;
	printf("--------------遍歷開始------------------------\n");
	for (int i = 0; i < matrix.totalNum; i++)
	{
		MatrixData data = matrix.base[i];
		printf("%d行  %d列 : %d\n",data.row+1,data.col+1,data.data);
	}
	printf("--------------遍歷結束------------------------\n");
}


int initData[5][10] = {
	{1,0,0,0,0,0,0,0,0,0},
	{0,0,2,0,0,0,0,0,5,0},
	{0,0,0,3,0,0,0,0,0,0},
	{0,2,0,0,0,0,0,0,0,0},
	{1,0,0,0,0,0,0,0,0,9},
};

int initAddData[5][10]= {
	{1,0,0,0,3,0,0,0,0,0},
	{0,0,2,0,4,0,0,0,5,0},
	{0,0,0,3,0,0,0,0,0,0},
	{0,2,0,0,2,0,0,0,0,0},
	{1,0,0,0,1,0,0,0,0,9},
};

int initData2 [10][2] = {
	{1,0},
	{0,0},
	{0,0},
	{0,0},
	{0,0},
	{0,6},
	{0,0},
	{0,0},
	{5,0},
	{0,0},
};

int _tmain(int argc, _TCHAR* argv[])
{
	SMatrix matrix;
	SMatrixInit(&matrix,(int *)initData,5,10);
	SMatricTraverse(matrix);
	printf("--------------普通轉置-----------------------\n");
	SMatrix tMatrix;
	SMatrixTranspose(matrix,&tMatrix);
	SMatricTraverse(tMatrix);
	printf("--------------快速轉置-----------------------\n");
	SMatrix qtMatrix;
	SMatrixQuickTranspose(matrix,&qtMatrix);
	SMatricTraverse(qtMatrix);
	printf("--------------矩陣相乘-----------------------\n");
	SMatrix m2;
	SMatrixInit(&m2,(int *)initData2,10,2);
	SMatrix mul;
	SMatrixMult(matrix,m2,&mul);
	SMatricTraverse(mul);
	printf("--------------矩陣相加-----------------------\n");
	SMatrix mAdd;
	SMatrixInit(&mAdd,(int *)initAddData,5,10);
	SMatrix mSum;
	SMatrixAdd(matrix,mAdd,&mSum);
	SMatricTraverse(mSum);
	printf("--------------矩陣相減-----------------------\n");
	SMatrix mSub;
	SMatrixSub(matrix,mAdd,&mSub);
	SMatricTraverse(mSub);
	return 0;
}

執行程式碼,截圖