資料結構學習(C++)——稀疏矩陣(十字連結串列【2】) (轉)
如果你細想想,就會發現,非零元節點如果沒有指示位置的域,那麼做加法和乘法時,為了確定節點的位置,每次都要遍歷行和列的連結串列。因此,為了運算,這個域是必須的。為了看出十字連結串列和單連結串列的差異,我從單連結串列派生出十字連結串列,這需要先定義一種新的結構,如下:
class MatNode:namespace prefix = o ns = "urn:schemas--com::office" />
{
public:
int data;
int row, col;
union { Node
};
另外,由於這樣的十字連結串列是由多條單連結串列拼起來的,為了訪問每條單連結串列的保護成員,要宣告十字連結串列類為單連結串列類的友元。即在class List的宣告中新增friend class Matrix;
稀疏矩陣的定義和實現
#ifndef Matrix_H
#define Matrix_H
#include "List.h"
class MatNode
{
public:
int data;
int row, col;
union { Node
MatNode(int value = 0, Node
: data(value), down(p), row(i), col(j) {}
friend ostream & operator << (ostream & strm, MatNode &mtn)
{
st<< '(' << mtn.row << ',' << mtn.col << ')' << mtn.data;
return strm;
}
};
class Matrix : List
{
public:
Matrix() : row(0), col(0), num(0) {}
Matrix(int row, int col, int num) : row(row), col(col), num(num) {}
~Matrix() { MakeEmpty(); }
void MakeEmpty()
{
List
while (first->data.downrow != NULL)
{
q = first->data.downrow;
first->data.downrow = q->first->data.downrow;
delete q;
}
List
row = col = num = 0;
}
void Input()
{
if (!row) { cout << "輸入矩陣行數:"; cin >> row; }
if (!col) { cout << "輸入矩陣列數:"; cin >> col; }
if (!num) { cout << "輸入非零個數:"; cin >> num; }
if (!row || !col || !num) return;
cout << endl << "請按順序輸入各個非零元素,以列序為主,輸入0表示本列結束" << endl;
int i, j, k, v;//i行數 j列數 k個非零元 v非零值
Node
List
for (j = 1; j <= col; j++) LastInsert(MatNode(0, NULL, 0, j));
for (i = 1; i <= row; i++)
{
q = new List
q->first->data.row = i;
p->data.downrow = q;
p = q->first;
}
j = 1; q = first->data.downrow; First(); t = pNext();
for (k = 0; k < num; k++)
{
if (j > col) break;
cout << endl << "輸入第" << j << "列非零元素" << endl;
cout << "行數:"; cin >> i;
if (i < 1 || i > row) { j++; k--; q = first->data.downrow; t = pNext(); continue; }
cout << "非零元素值"; cin >> v;
if (!v) { k--; continue; }
MatNode matnode(v, NULL, i, j);
p = new Node
t->data.down = p; t = p;
while (q->first->data.row != i) q = q->first->data.downrow;
q->LastInsert(t);
}
}
void Print()
{
List
cout << endl;
while (q != NULL)
{
cout << *q;
q = q->first->data.downrow;
}
}
Matrix & Add(Matrix &matB)
{
//初始化賦值輔助變數
if (row != matB.row || col != matB.col || matB.num == 0) return *this;
Node
Node
Node
List
First(); matB.First();
for (int j = 1; j <= col; j++)
{
pAT[j] = pNext();
pBT[j] = matB.pNext();
}
//開始
for (int i = 1; i <= row; i++)
{
qA->First(); qB->First();
pA = qA->pNext(); pB = qB->pNext();
while (pA != NULL && pB !=NULL)
{
if (pA->data.col == pB->data.col)
{
pA->data.data += pB->data.data;
pBT[pB->data.col]->data.down = pB->data.down; qB->Remove();
if (!pA->data.data)
{
pAT[pA->data.col]->data.down = pA->data.down;
qA->Remove();
}
else
{
pAT[pA->data.col] = pA;
qA->pNext();
}
}
else
{
if (pA->data.col > pB->data.col)
{
pBT[pB->data.col]->data.down = pB->data.down;
qB->pRemove();
pB->data.down = pAT[pB->data.col]->data.down;
pAT[pB->data.col]->data.down = pB;
pAT[pB->data.col] = pB;
qA->InsertBefore(pB);
}
else if (pA->data.col < pB->data.col)
{
pAT[pA->data.col] = pA;
qA->pNext();
}
}
pA = qA->pGet();pB = qB->pGet();
}
if (pA == NULL && pB != NULL)
{
qA->pGetPrior()->link = pB;
qB->pGetPrior()->link = NULL;
while (pB != NULL)
{
pBT[pB->data.col]->data.down = pB->data.down;
pB->data.down = pAT[pB->data.col]->data.down;
pAT[pB->data.col]->data.down = pB;
pAT[pB->data.col] = pB;
pB = pB->link;
}
}
if (pA !=NULL)
{
while (qA->pGet() != NULL)
{
pAT[pA->data.col] = pA;
qA->pNext();
}
}
qA = qA->first->data.downrow; qB = qB->first->data.downrow;
}
delete []pAT; delete []pBT;
return *this;
}
private:
int row, col, num;
};
#endif
【說明】對於十字連結串列來說,只要記住對每個節點的操作,要同時考慮它的兩個指標域,那麼,各種演算法的理解都不是很難。比如說矩陣加法,“兩個矩陣相加和兩個一元多項式相加極為相似,所不同的是一元多項式只有一個變元(指數項),而矩陣中每個非零元有兩個變元(行值和列值),每個節點既在行表中又在列表中,致使插入和刪除節點時指標的修改稍為複雜,故需要更多的輔助指標。”(《資料結構(C語言版)》)其實private的row等可以放在首行的頭節點裡的,但為了清晰一點(本來就夠亂了),我把他們單立出來了。另外,很多地方考慮不是很周全,要是不按照註明的要求使用,很容易就會出錯。
【後記】按理說,十字連結串列應該不算是線性鏈式結構,按照原書的安排,放在連結串列這章不是很合適;《資料結構(C語言版)》將它和廣義表放在一章還是合理的。其實十字連結串列不是很難,就是很煩人;並且,如果不是數值運算,基本很少用到矩陣,就算是用到矩陣運算,在矩陣規模不大的時候,可以用二維陣列代替十字連結串列。從歷屆考研題來看,這部分幾乎沒有題,原因就是麻煩(你寫起來麻煩,他批起來也麻煩)、不常用、演算法固定沒新意。所以,你要是鬧心,這部分跳過去也可以。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-997964/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料結構學習(C++)——稀疏矩陣(十字連結串列【1】) (轉)資料結構C++矩陣
- 用十字連結串列表示的稀疏矩陣類矩陣
- 資料結構(一)-稀疏矩陣資料結構矩陣
- 資料結構學習(C++)——迴圈連結串列 (轉)資料結構C++
- 資料結構學習(C++)——雙向連結串列 (轉)資料結構C++
- 學習 JS 資料結構(2):連結串列JS資料結構
- 資料結構學習--連結串列資料結構
- 資料結構:陣列,稀疏矩陣,矩陣的壓縮。應用:矩陣的轉置,矩陣相乘資料結構陣列矩陣
- 資料結構學習(C++)——單連結串列(定義與實現) (轉)資料結構C++
- 學習 JavaScript 資料結構(二)——連結串列JavaScript資料結構
- 資料結構學習(C++)——單連結串列應用(一元多項式【2】) (轉)資料結構C++
- 資料結構--陣列、單向連結串列、雙向連結串列資料結構陣列
- 用三元組連結串列表示的稀疏矩陣類矩陣
- 資料結構之陣列和連結串列資料結構陣列
- 資料結構學習(C++)——遞迴【2】(2) (轉)資料結構C++遞迴
- C++資料結構連結串列的基本操作C++資料結構
- 資料結構 - 單連結串列 C++ 實現資料結構C++
- 【資料結構】實現單連結串列(c++)資料結構C++
- 【資料結構】雙迴圈連結串列(c++)資料結構C++
- 資料結構之連結串列與陣列(1):陣列和連結串列的簡介資料結構陣列
- 資料結構-連結串列資料結構
- 資料結構 - 連結串列資料結構
- 連結串列-資料結構資料結構
- 資料結構--連結串列資料結構
- 資料結構—連結串列資料結構
- 資料結構學習(C++)——單連結串列應用(一元多項式【1】) (轉)資料結構C++
- 資料結構與演算法學習-連結串列上資料結構演算法
- 資料結構與演算法學習-連結串列下資料結構演算法
- 資料結構之連結串列:206. 反轉連結串列資料結構
- 資料結構-單連結串列、雙連結串列資料結構
- 資料結構學習(C++)——遞迴【2】(1) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【2】(3) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【2】(4) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【3】(2) (轉)資料結構C++遞迴
- 資料結構之連結串列與陣列(2):單向連結串列上的簡單操作問題資料結構陣列
- 資料結構——單連結串列的C++實現資料結構C++
- 【資料結構】實現迴圈連結串列(c++)資料結構C++
- 資料結構學習(C++)——圖(總結) (轉)資料結構C++