Snap算法学习01-01关于节点及边的操作

海阔凭鱼跃越 / 2023-05-31 / 原文

 

 

 

  //alg.h
 
 1 // 对图中节点进行遍历,找出入度数与指定值相等的节点个数
 2 // Returns the number of nodes with in-degree NodeInDeg
 3 template <class PGraph>
 4 int CntInDegNodes(const PGraph& Graph, const int& NodeInDeg) {
 5   int Cnt = 0;
 6   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
 7     if (NI.GetInDeg() == NodeInDeg) Cnt++;
 8   }
 9   return Cnt;
10 }

(1)掌握遍历全部节点的方法

(2)获取当前节点的入度    NI.GetInDeg()

(3)获取当前节点的出度    NI.GetOutDeg();  获取当前节点的度 NI.GetDeg();

 
 1 // 指定节点NId与节点集合NodeSet中各点之间的存在边的数量
 2 // Returns the number of nodes in NodeSet that have an edge to the node NId.
 3 template <class PGraph>
 4 int CntEdgesToSet(const PGraph& Graph, const int& NId, const TIntSet& NodeSet) {
 5   if (! Graph->IsNode(NId)) { return 0; }
 6   const bool IsDir = Graph->HasFlag(gfDirected);
 7   const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId);
 8   if (! IsDir) {
 9     int EdgesToSet = 0;
10     for (int e = 0; e < NI.GetOutDeg(); e++) {
11       if (NodeSet.IsKey(NI.GetOutNId(e))) { EdgesToSet++; } }
12     return EdgesToSet;
13   } else {
14     TIntSet Set(NI.GetDeg());
15     for (int e = 0; e < NI.GetOutDeg(); e++) {
16       if (NodeSet.IsKey(NI.GetOutNId(e))) { Set.AddKey(NI.GetOutNId(e)); } }
17     for (int e = 0; e < NI.GetInDeg(); e++) {
18       if (NodeSet.IsKey(NI.GetInNId(e))) { Set.AddKey(NI.GetInNId(e)); } }
19     return Set.Len();
20   }
21 }

(1)整形节点号NId构造为特定节点数据结构量NI:

const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId);
反过来,已知NI获取对应的整形量: NI.GetId();
 

(2)与节点NI有连线的节点共NI.GetDeg()个;依次列出对应节点对应节点号:

for (int e = 0; e < NI.GetOutDeg(); e++) {NI.GetOutNId(e)}

(3)节点集合:

声明 TIntSet Set(预留元素数量);//元素是字典key-value对

增加元素:Set.AddKey(节点号);

判断节点NId是否再集合中: Set.IsKey(NId);

节点集合的大小(包含元素的个数):Set.Len();

   
 1 // 找出拥有最大度数的若干节点,并从中随机选取一个节点作为返回值。
 2 // Returns a randomly chosen node from all the nodes with the maximum degree.
 3 template <class PGraph>
 4 int GetMxDegNId(const PGraph& Graph) {
 5   TIntV MxDegV;
 6   int MxDeg=-1;
 7   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
 8     if (MxDeg < NI.GetDeg()) { MxDegV.Clr(); MxDeg = NI.GetDeg(); }
 9     if (MxDeg == NI.GetDeg()) { MxDegV.Add(NI.GetId()); }
10   }
11   EAssertR(! MxDegV.Empty(), "Input graph is empty!");
12   return MxDegV[TInt::Rnd.GetUniDevInt(MxDegV.Len())];
13 }

(1)声明整型向量并添加元素:

TIntV MxDegV;
MxDegV.Add(NI.GetId());

(2)从向量MxDegV中任选一个元素:

MxDegV[TInt::Rnd.GetUniDevInt(MxDegV.Len())];
   
1 // 获取每个节点及其度数
2 // Returns a vector of pairs :(node id, node in-degree)
3 template <class PGraph>
4 void GetNodeInDegV(const PGraph& Graph, TIntPrV& NIdInDegV) {
5   NIdInDegV.Reserve(Graph->GetNodes(), 0);
6   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
7     NIdInDegV.Add(TIntPr(NI.GetId(), NI.GetInDeg()));
8   }
9 }
1 template <class PGraph>
2 void GetNodeOutDegV(const PGraph& Graph, TIntPrV& NIdOutDegV) {
3   NIdOutDegV.Reserve(Graph->GetNodes(), 0);
4   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
5     NIdOutDegV.Add(TIntPr(NI.GetId(), NI.GetOutDeg()));
6   }
7 }

注意:

NIdOutDegV、NIdInDegV是TIntPrV类型的向量,元素为TPair结构体类型(见ds.h文件)。元素对象Pair拥有两个数据成员Pair.Val1,Pair.Val2
从向量中获取TPair元素对应属性的操作:NIdOutDegV[i].Val1,NIdOutDegV[i].Val1
   
   // 关于边的访问
 1 // 图中无向边计数
 2 // Counts unique undirected edges in the graph  //不考虑多重边
 3 template <class PGraph>
 4 int CntUniqUndirEdges(const PGraph& Graph) {
 5   TIntSet NbrSet;
 6   TIntSet SelfNbrSet;
 7   int Cnt = 0;
 8   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
 9     NbrSet.Clr(false);
10     for (int e = 0; e < NI.GetDeg(); e++) { // unique neighbors of a node
11       const int NbrId = NI.GetNbrNId(e);
12       if (NbrId == NI.GetId()) { // remember self-edges
13         SelfNbrSet.AddKey(NbrId);
14       } else {
15         NbrSet.AddKey(NbrId);
16       }
17     }
18     Cnt += NbrSet.Len();
19   }
20   // OP RS 2014/06/11 self-edges are currently not used 
21   //return Cnt / 2 + SelfNbrSet.Len();
22   return Cnt / 2;
23 }

 

 1 //图中有向边计数
 2 template <class PGraph>
 3 int CntUniqDirEdges(const PGraph& Graph) {
 4   TIntSet NbrSet;
 5   int Cnt = 0;
 6   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
 7     NbrSet.Clr(false);
 8     for (int e = 0; e < NI.GetOutDeg(); e++) { // unique out-neighbors of a node
 9       if (NI.GetOutNId(e) != NI.GetId()) { // skip self-edges
10         NbrSet.AddKey(NI.GetOutNId(e)); }
11     }
12     Cnt += NbrSet.Len();
13   }
14   return Cnt;
15 }

 

//图中双向边计数

 1 template <class PGraph>
 2 int CntUniqBiDirEdges(const PGraph& Graph) {
 3   if (! Graph->HasFlag(gfDirected)) { // graph is undirected
 4     return CntUniqUndirEdges(Graph);  // then every edge is bi-directional
 5   }
 6   TIntSet NbrSet;
 7   int Cnt = 0;
 8   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
 9     const int SrcId = NI.GetId();
10     for (int e = 0; e < NI.GetOutDeg(); e++) {
11       const int DstId = NI.GetOutNId(e);
12       if (DstId <= SrcId) { continue; } // count each un-dir edge only once
13       if (Graph->IsEdge(DstId, SrcId)) { Cnt++; }
14     }
15   }
16   return Cnt;
17 }