改进08年曾经编过的STL风格的十字链表程序。
二维循环式
1,每个节点有right和down指针。
2,每一行的最后一个元素的right指针指向下一个有效行(不一定是下一行)的第一个元素。
3,每一列的最后一个元素的down指针指向下一个有效列(不一定是下一列)的第一个元素。
4,注意
第一个元素不一定就是左上角,DOWN和RIGHT遍历的第一个元素也可以不同。
//矩阵:
0 1 0 0 0
0 0 0 0 0
3 0 4 0 0
0 5 0 0 0
DOWN:{3}, {1,5}, {4}
RIGHT: {1}, {3,4}, {5}
最后一个元素不一定就是右下角,按照right遍历和down遍历最后一个元素不同。
//矩阵:
0 1 0 0 0
0 0 0 0 0
0 3 4 0 0
0 5 0 0 0
所以迭代器构造的时候必须指定类型:DOWN / RIGHT
矩阵举例分析
0 1 0 0 0
0 0 0 0 0
0 3 4 0 0
0 5 0 0 0
存储结构图:
图 - 1
如图-1,黑色结点HNode为头结点,HNode的right指向第一个有效行的首元素,down指针指向第一个有效列的首元素。
两种颜色的线条,橙色线条表示right指针,蓝色线条表示down指针。
1)每一行最后一个元素的right指针指向下一个有效行第一个元素,
图-1按照right指针遍历的序列为:{1}, {3, 4}, {5} 其中大括号内为同一行元素。
一共三行,第一行最后一个结点1的right指向3结点;第二行最后一个结点4的right指向5;5结点为right遍历的最后一个元素,所以第三行最后一个结点5的right指向了HNode结点,图中有橙色的虚线表示。
STL风格的迭代器设计都是左闭右开,行遍历的伪代码如下:
Iterator<int, RIGHT> it = begin( OList::Node_1 ); it != end( OList::HNode ); ++it );
//do_some_stuff()
迭代器的第一个模板参数为OList存储的数据类型,第二个模板参数为迭代器遍历方式,缺省参数为RIGHT。
2)每一列最后一个元素的down指针指向下一个有效列第一个元素,
图-1按照down指针遍历的序列为:{1,3,5}, {4} 其中大括号内为同一列元素。
一共两列,第一列最后一个结点5的down指针指向4结点。4结点为down遍历的最后一个元素,所以第二列最后一个结点4的down指向了HNode结点。图中有蓝色的虚线表示。
STL风格的迭代器设计都是左闭右开,列遍历的伪代码如下:
Iterator<int, DOWN> it = begin( OList::Node_1 ); it != end( OList::HNode ); ++it );
//do_some_stuff()
迭代器的第一个模板参数为OList存储的数据类型,第二个模板参数为迭代器遍历方式,缺省参数为RIGHT。
总结:
这种存储方式,方便迭代器的设计但是丢失了原稀疏矩阵的行列,元素的位置信息。
行列矩阵式存储
1, 增加行列的头结点:
行头结点:Node* m_pRowHead [ m_RowSize ];
列头结点:Node* m_pColHead[ m_ColSize ];
如果row_idx行全为0,则 m_pRowHead[ row_idx ] = NULL;
2,增加两个行遍历和列遍历的尾结点:rowCapNode, colCapNode,主要是设计迭代器需要。
3,每一行的最后一个结点m_pRight为NULL,最后一行最后一个元素m_pRight指向rowCapNode。
4,每一列的最后一个结点m_pDown为NULL,最后一列最后一个元素m_pDown指向colCapNode。
//矩阵:
0 1 0 0 0
0 0 0 0 0
3 0 4 0 0
0 5 0 0 0
存储结构如图-2:
行遍历:{1}, {3, 4}, {5}, {rowCapNode}
列遍历:{1,3,5}, {4}, {colCapNode}
OrthoList<T>的实现如下:实现了两种const iterator:row, col
OrthoList<T>的实现,注意跟定义放在一个头文件中:
基于迭代器的功能函数设计:copy和print
测试:
、
输出: