Cuthill-Mckee算法用于对称方矩阵的重新排序。它基于图的广度优先搜索算法,其邻接矩阵是输入方阵的稀疏版本。
当要生成矩阵的行时,经常使用该顺序,该矩阵的行和列根据节点的编号进行编号。通过对节点进行适当的重新编号,通常可以产生带宽更小的矩阵。
矩阵的稀疏形式是其中大多数元素为零的矩阵。
反向Cuthill-Mckee算法与Cuthill-Mckee算法相同,唯一的区别在于,在Cut Cut-Mckee反向算法中,使用Cuthill-Mckee算法获得的最终指标被反向。
以下是反向Cuthill-Mckee算法的步骤:
- 为对象R的排列顺序实例化一个空队列Q和一个空数组。
- S1:我们首先找到具有最小度数的对象,该对象的索引尚未添加到R中。假设与第p行相对应的对象已被识别为最小度的对象。将p加到R。
- S2:将索引添加到R ,并在索引处添加相应对象的所有邻居,
以递增的顺序,到Q。邻居是节点之间具有非零值的节点
第p行中的非对角元素。 - S3:提取Q中的第一个节点,例如C。如果尚未将C插入R中,则将其添加到R中,然后按递增顺序将Q的C邻居添加到Q中。
- S4:如果Q不为空,则重复S3 。
- S5:如果Q为空,但是矩阵中有一些对象尚未包含在R中,请再次从S1开始。 (如果存在不相交的图,则可能会发生这种情况)
- S6:一旦所有对象都包含在R中,则终止该算法。
- S7:最后,反转R中的索引,即( swap(R [i],R [P-i + 1]) )。
程度:程度的定义不是恒定的,它会根据您使用的数据集而变化。对于下面给出的示例,节点的度数定义为相应行中非对角元素的总和。
节点“ A”的程度的广义定义是连接到“ A”的节点数。
例子:
Given a symetric matrix:
| 0.0 0.78 0.79 0.8 0.23 |
| 0.9 0.0 0.43 0.771 0.752 |
| 0.82 0.0 0.0 0.79 0.34 |
| 0.8 0.8 0.8 0.0 0.8 |
| 0.54 0.97 0.12 0.78 0.0 |
Degree here is defined as sum of non-diagonal
elements in the corresponding row.
Sparsification for a matrix is defined as,
if the element of the matrix at i, j has a value
less than 0.75 its made to 0 otherwise its made to 1.
稀疏后的矩阵:
Degree of node 0 = 2.6
Degree of node 1 = 2.803
Degree of node 2 = 2.55
Degree of node 3 = 3.2
Degree of node 4 = 2.41
Permutation order of objects (R) : 0 2 1 3 4
新的排列顺序只是节点的排序,即将节点’R [i]’转换为节点’i’。
因此,将节点’R [0] = 0’转换为0;节点“ R [1] = 2”,为1;节点“ R [2] = 1”,为2;节点“ R [3] = 3”,到3;和节点“ R [4] = 4”,为4;
让我们举一个更大的例子来了解重新排序的结果:
Give a adjacency matrix :
| 0 1 0 0 0 0 1 0 1 0 |
| 1 0 0 0 1 0 1 0 0 1 |
| 0 0 0 0 1 0 1 0 0 0 |
| 0 0 0 0 1 1 0 0 1 0 |
| 0 1 1 1 0 1 0 0 0 1 |
| 0 0 0 1 1 0 0 0 0 0 |
| 1 1 1 0 0 0 0 0 0 0 |
| 0 0 0 0 0 0 0 0 1 1 |
| 1 0 0 1 0 0 0 1 0 0 |
| 0 1 0 0 1 0 0 1 0 0 |
Degree of node 'A' is defined as number of
nodes connected to 'A'
Output :
Permutation order of objects (R) :
7 8 3 5 9 0 1 4 6 2
现在将节点“ R [i]”转换为节点“ i”
因此,该图变为:
通过两个图的邻接矩阵可以看出回火的结果:
从这里我们可以清楚地看到,Cuthill-Mckee算法如何帮助将方阵重新排序为非分布式矩阵。
下面是上述算法的实现。取学位的一般定义。
CPP
// C++ program for Implementation of
// Reverse Cuthill Mckee Algorithm
#include
using namespace std;
vector globalDegree;
int findIndex(vector > a, int x)
{
for (int i = 0; i < a.size(); i++)
if (a[i].first == x)
return i;
return -1;
}
bool compareDegree(int i, int j)
{
return ::globalDegree[i] < ::globalDegree[j];
}
template
ostream& operator<<(ostream& out, vector const& v)
{
for (int i = 0; i < v.size(); i++)
out << v[i] << ' ';
return out;
}
class ReorderingSSM {
private:
vector > _matrix;
public:
// Constructor and Destructor
ReorderingSSM(vector > m)
{
_matrix = m;
}
ReorderingSSM() {}
~ReorderingSSM() {}
// class methods
// Function to generate degree of all the nodes
vector degreeGenerator()
{
vector degrees;
for (int i = 0; i < _matrix.size(); i++) {
double count = 0;
for (int j = 0; j < _matrix[0].size(); j++) {
count += _matrix[i][j];
}
degrees.push_back(count);
}
return degrees;
}
// Implementation of Cuthill-Mckee algorithm
vector CuthillMckee()
{
vector degrees = degreeGenerator();
::globalDegree = degrees;
queue Q;
vector R;
vector > notVisited;
for (int i = 0; i < degrees.size(); i++)
notVisited.push_back(make_pair(i, degrees[i]));
// Vector notVisited helps in running BFS
// even when there are dijoind graphs
while (notVisited.size()) {
int minNodeIndex = 0;
for (int i = 0; i < notVisited.size(); i++)
if (notVisited[i].second < notVisited[minNodeIndex].second)
minNodeIndex = i;
Q.push(notVisited[minNodeIndex].first);
notVisited.erase(notVisited.begin()
+ findIndex(notVisited,
notVisited[Q.front()].first));
// Simple BFS
while (!Q.empty()) {
vector toSort;
for (int i = 0; i < _matrix[0].size(); i++) {
if (i != Q.front() && _matrix[Q.front()][i] == 1
&& findIndex(notVisited, i) != -1) {
toSort.push_back(i);
notVisited.erase(notVisited.begin()
+ findIndex(notVisited, i));
}
}
sort(toSort.begin(), toSort.end(), compareDegree);
for (int i = 0; i < toSort.size(); i++)
Q.push(toSort[i]);
R.push_back(Q.front());
Q.pop();
}
}
return R;
}
// Implementation of reverse Cuthill-Mckee algorithm
vector ReverseCuthillMckee()
{
vector cuthill = CuthillMckee();
int n = cuthill.size();
if (n % 2 == 0)
n -= 1;
n = n / 2;
for (int i = 0; i <= n; i++) {
int j = cuthill[cuthill.size() - 1 - i];
cuthill[cuthill.size() - 1 - i] = cuthill[i];
cuthill[i] = j;
}
return cuthill;
}
};
// Driver Code
int main()
{
int num_rows = 10;
vector > matrix;
for (int i = 0; i < num_rows; i++) {
vector datai;
for (int j = 0; j < num_rows; j++)
datai.push_back(0.0);
matrix.push_back(datai);
}
// This is the test graph,
// check out the above graph photo
matrix[0] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0 };
matrix[1] = { 1, 0, 0, 0, 1, 0, 1, 0, 0, 1 };
matrix[2] = { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 };
matrix[3] = { 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 };
matrix[4] = { 0, 1, 1, 1, 0, 1, 0, 0, 0, 1 };
matrix[5] = { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 };
matrix[6] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
matrix[7] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
matrix[8] = { 1, 0, 0, 1, 0, 0, 0, 1, 0, 0 };
matrix[9] = { 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 };
ReorderingSSM m(matrix);
vector r = m.ReverseCuthillMckee();
cout << "Permutation order of objects: " << r << endl;
return 0;
}
Permutation order of objects: 7 8 9 3 5 1 0 4 6 2
参考:https://en.wikipedia.org/wiki/Cuthill%E2%80%93McKee_algorithm