void loopdetect(GenericTree& twd){ vector<bool> visited(twd.num_nodes(), false); for(int i=0; i<twd.num_nodes(); i++){ if(visited[i]==true) continue; visited[i]=true; queue<pair<int, int> > q; q.push(pair<int, int>(-1,i));//first is father, second is current_node while(q.size()>0){ pair<int, int> father_current=q.front(); q.pop(); for(TreeEdgeList::iterator it=twd.get_neighbors(father_current.second).begin(); it!=twd.get_neighbors(father_current.second).end(); it++){ if(it->nodeID==father_current.first) continue; if(visited[it->nodeID]==true){ cout<<"Loop Detected at: "<<it->nodeID<<endl; exit(-1); } visited[it->nodeID]=true; q.push(pair<int, int>(father_current.second, it->nodeID)); } } } }
void buildBalancedTreeDecomposition(GenericTree& twd, GenericTree& btd, const vector<set<int> >& nodedirectory){ for(int i=0; i<twd.num_nodes(); i++){ if(twd[i].visited==true) continue; //calculate the number of vertices in the connected component (BFS) twd[i].visited=true; int CC_size=1; queue<int> q; q.push(i); while(q.size()>0){ int j=q.front(); q.pop(); for(TreeEdgeList::iterator tit=twd.get_neighbors(j).begin(); tit!=twd.get_neighbors(j).end(); tit++){ if(twd[tit->nodeID].visited==true) continue; twd[tit->nodeID].visited=true; CC_size++; q.push(tit->nodeID); } } //calculate the number of vertices in the connected component done //Fill in the neighbor size info and locate the centroid int from_vertex=-1; int centroid=-1; int centroid_weight=MAX_VAL; SubtreeMeasure(twd, centroid, centroid_weight, i, from_vertex, CC_size, nodedirectory); //Fill in the neighbor size info and locate the centroid done //Iteratively build balanced decomposition tree BalancedTreeConstr(twd, btd, centroid, 0, nodedirectory); SubtreeMeasure(btd, centroid, centroid_weight, i, from_vertex, CC_size, nodedirectory); //Iteratively build balanced decomposition tree done } }
int main(int argc, char* argv[]) { if (argc == 1) { usage(); return 1; } string query_filename, input_filename; int input_para_counter=1; // int source_vertex=-1; // int destination_vertex=-1; int rw_queryfile=-1; construction_type graph_input_format=ADJ_GRAPH; graph_type direct_info=UNDIRECT; int query_num=100000; int verify_enable=1; while (input_para_counter < argc) { if (strcmp("-h", argv[input_para_counter]) == 0) { usage(); return 1; } if (strcmp("-g", argv[input_para_counter]) == 0) { input_para_counter++; graph_input_format=static_cast<construction_type>(atoi(argv[input_para_counter++])); }else if (strcmp("-d", argv[input_para_counter]) == 0) { input_para_counter++; direct_info=static_cast<graph_type>(atoi(argv[input_para_counter++])); }else if (strcmp("-l", argv[input_para_counter]) == 0){ input_para_counter++; rw_queryfile= atoi(argv[input_para_counter++]); }else if (strcmp("-q", argv[input_para_counter]) == 0){ input_para_counter++; query_filename= argv[input_para_counter++]; }else if (strcmp("-n", argv[input_para_counter]) == 0){ input_para_counter++; query_num= atoi(argv[input_para_counter++]); }else if (strcmp("-v", argv[input_para_counter]) == 0){ input_para_counter++; verify_enable= atoi(argv[input_para_counter++]); }else{ input_filename = argv[input_para_counter++]; // source_vertex = atoi(argv[input_para_counter++]); // destination_vertex = atoi(argv[input_para_counter++]); } } ifstream infile(input_filename.c_str()); if (!infile) { cout << "Error: Cannot open " << input_filename << endl; return -1; } vector<int> src; vector<int> trg; Graph g(infile, graph_input_format, direct_info); if(direct_info==UNDIRECT) cout << "#vertex size:" << g.num_vertices() << "\t#edge size:" << g.num_edges() << endl; else cout << "#vertex size:" << g.num_vertices() << "\t#undirect edge size:" << g.num_edges() << "\t#direct edge size:"<< g.num_directed_edges() << endl; //Symmetric test is enforced right now. In the future, we can allowed directed graphs //Note the program requires that a vertex itself does not appear in its adjacent list and the adjacent list is in ascending order. if(!g.isSymmetric()){ cout<<"Internal Error: Intend to treat a directed graph as undirected."<<endl; exit(-1); } if(rw_queryfile==1){ GraphUtil::generate_queryfile(src, trg, g.num_vertices(), query_filename.c_str(), query_num); }else if(rw_queryfile==0){ GraphUtil::load_queryfile(src, trg, query_filename.c_str()); }else{//generate query without loading from or saving into files. GraphUtil::generate_query(src, trg, g.num_vertices(), query_num); } //Start index construction struct timeval after_index_const_time, before_index_const_time; gettimeofday(&before_index_const_time, NULL); GenericTree twd; vector<set<int> > nodedirectory; //middle result. Graph g1=g; int max_bag_size=buildTreeWidthDecomposition(g1, twd, nodedirectory); cout<<"max_bag_size of this decomposition: "<<max_bag_size<<endl; vector<vector<int> > node_mapping_directory(nodedirectory.size(), vector<int>()); //twd.printTree(); cout<<"Tree Width Decomposition successful. "<<endl; cout<<"twd.num_nodes(): "<<twd.num_nodes()<<endl; GenericTree btd(twd.num_nodes()); buildBalancedTreeDecomposition(twd, btd, nodedirectory); cout<<"Balanced Tree decomposition successful. "<<endl; cout<<"btd.num_nodes(): "<<btd.num_nodes()<<endl; //btd.printTree(); BinaryTree btree(btd.num_nodes()); vector<int> virtualnode_to_realnode;//The virtual node to real node mapping table. //middle result. buildBinaryTree(btd, btree, virtualnode_to_realnode); cout<<"Binary Tree construction successful. "<<endl; cout<<"btree.num_nodes(): "<<btree.num_nodes()<<endl; cout<<"btree.access_height(): "<<btree.access_height()<<endl; //btree.printTree(); if(btree.access_height()>63){ cout<<"The current program maximally supports a balanced binary tree with height no more than 63, i.e., about 2^61 vertices in the original graph."<<endl; cout<<"This number shall satisfy almost all current applications. Please verify you really need to run such a giant graph. If yes, a simple update on the Machine_WORD data structure will make it work."<<endl; cout<<"Program exit."<<endl; exit(0); } vector<MACHINE_WORD> TreeNodeBitLabel(btree.num_nodes(), 0);//middle result BitOperators::set_one(TreeNodeBitLabel[btree.access_root()], btree.access_height()); cout<<"Start building Tree Node Bit label"<<endl; BuildTreeNodeBitlabel(btree, btree.access_root(), TreeNodeBitLabel); cout<<"End building Tree Node Bit label"<<endl; //hashmap implementation hash_map<int, int> BitLabelTreeNode;//Map bit label to real tree node. Part of final label. for (int i=0; i<int(TreeNodeBitLabel.size()); i++){ if (i>=btd.num_nodes()){ BitLabelTreeNode[TreeNodeBitLabel[i]]=virtualnode_to_realnode[i-btd.num_nodes()];//virtualnode_to_realnode gets -1 if no real node can be mapped. } else BitLabelTreeNode[TreeNodeBitLabel[i]]=i; } vector<vector<VertexDistancePair> > LabelGT(g.num_vertices());//The first is vertex ID, and the second is distance. //middle result vector<vector<VertexDistancePair> > LabelGT_From(g.num_vertices());//middle result vector<vector<VertexDistancePair> > LabelGT_To(g.num_vertices());//middle result vector<vertex_mapping_info> vertex_mapping_table(g.num_vertices());//The table recording the mapping between vertex, and btree level and label offset. //Part of final label. vector<int> vertex_to_nodeID(g.num_vertices());//middle result cout<<"Start building LabelGT"<<endl; if(direct_info==DIRECT) BuildLabelGTDirect(g, btree, nodedirectory, node_mapping_directory, LabelGT_From, LabelGT_To, vertex_mapping_table, vertex_to_nodeID); else BuildLabelGT(g, btree, nodedirectory, node_mapping_directory, LabelGT, vertex_mapping_table, vertex_to_nodeID); cout<<"End building LabelGT"<<endl; for(size_t i=0; i<vertex_mapping_table.size(); i++){ vertex_mapping_table[i].NodeBitLabel=TreeNodeBitLabel[vertex_to_nodeID[i]]; } //sort and printout LabelGT or LabelGT_From, LabelGT_To if(direct_info==DIRECT){ for(size_t i=0; i<LabelGT_From.size(); i++){ sort(LabelGT_From[i].begin(), LabelGT_From[i].end(), VertexDistanceCompare); } for(size_t i=0; i<LabelGT_To.size(); i++){ sort(LabelGT_To[i].begin(), LabelGT_To[i].end(), VertexDistanceCompare); } }else{ for(size_t i=0; i<LabelGT.size(); i++){ sort(LabelGT[i].begin(), LabelGT[i].end(), VertexDistanceCompare); } } //printout LabelGT done //release memory first time g1.clear(); TreeNodeBitLabel.clear(); virtualnode_to_realnode.clear(); btd.clear(); twd.clear(); cout<<"Start prequery"<<endl; vector<vector<vector<int> > > LabelGTUpdate(g.num_vertices());//It is a partial update in this version vector<vector<vector<int> > > LabelGT_From_Update(g.num_vertices()); vector<vector<FlatVector> > LabelGT_From_Mask(g.num_vertices()); vector<vector<vector<int> > > LabelGT_To_Update(g.num_vertices()); vector<vector<FlatVector> > LabelGT_To_Mask(g.num_vertices()); for (int v=0; v<g.num_vertices(); v++){ if(v%1000==0) cout<<"prequery on "<<v<<endl; if(direct_info==DIRECT){ LabelGT_From_Update[v].resize(vertex_mapping_table[v].level+1); LabelGT_From_Mask[v].resize(vertex_mapping_table[v].level+1); LabelGT_To_Update[v].resize(vertex_mapping_table[v].level+1); LabelGT_To_Mask[v].resize(vertex_mapping_table[v].level+1); }else LabelGTUpdate[v].resize(vertex_mapping_table[v].level+1); int current_node=int(vertex_to_nodeID[v]); while(current_node!=-1){ if(current_node<int(nodedirectory.size())){ if(direct_info==DIRECT){ set<int>::iterator sit=nodedirectory[current_node].begin(); vector<int>::iterator vit=node_mapping_directory[current_node].begin(); int nodedirectory_offset=0; while(sit!=nodedirectory[current_node].end()){ int To_distance=prequeryDirect(LabelGT_From, LabelGT_To, v, *sit); int From_distance=prequeryDirect(LabelGT_From, LabelGT_To, *sit, v); if(vit!=node_mapping_directory[current_node].end()){ if(*sit==*vit){ LabelGT_To_Update[v][btree[current_node].level].push_back(To_distance); if (To_distance<MAX_VAL) LabelGT_To_Mask[v][btree[current_node].level].insert(nodedirectory_offset); LabelGT_From_Update[v][btree[current_node].level].push_back(From_distance); if (From_distance<MAX_VAL) LabelGT_From_Mask[v][btree[current_node].level].insert(nodedirectory_offset); sit++; vit++; }else if (*sit<*vit){ if (To_distance<MAX_VAL) LabelGT_To_Mask[v][btree[current_node].level].insert(nodedirectory_offset); if (From_distance<MAX_VAL) LabelGT_From_Mask[v][btree[current_node].level].insert(nodedirectory_offset); sit++; }else{ cout<<"This should not happen because one is the subset of the other."<<endl; exit(-1); } }else{ if (To_distance<MAX_VAL) LabelGT_To_Mask[v][btree[current_node].level].insert(nodedirectory_offset); if (From_distance<MAX_VAL) LabelGT_From_Mask[v][btree[current_node].level].insert(nodedirectory_offset); sit++; } nodedirectory_offset++; } }else{ for(vector<int>::iterator vit=node_mapping_directory[current_node].begin(); vit!=node_mapping_directory[current_node].end(); vit++){ LabelGTUpdate[v][btree[current_node].level].push_back(prequery(LabelGT, v, *vit)); } } } current_node=btree[current_node].parent; } } cout<<"End prequery"<<endl; //release memory second time LabelGT.clear(); LabelGT_From.clear(); LabelGT_To.clear(); vertex_to_nodeID.clear(); node_mapping_directory.clear(); int tree_height=btree.access_height(); if(int(BitLabelTreeNode.size())<btree.num_nodes()) cout<<"HashMap has compressed the index size"<<endl; else if (int(BitLabelTreeNode.size())>btree.num_nodes()) cout<<"HashMap has introduced more index size than the tree node number."<<endl; btree.clear(); vector<vector<int> > node_directory(nodedirectory.size()); vector<int> TreeNodeLevel(nodedirectory.size());//Only real node levels are necessary. int node_directory_size=0; for(size_t i=0; i<nodedirectory.size(); i++){ TreeNodeLevel[i]=btree[i].level; for(set<int>::iterator sit=nodedirectory[i].begin(); sit!=nodedirectory[i].end(); sit++){ node_directory[i].push_back(*sit); node_directory_size++; } } nodedirectory.clear(); //release memory done //End index construction gettimeofday(&after_index_const_time, NULL); double index_construct_time=(after_index_const_time.tv_sec - before_index_const_time.tv_sec)*1000.0 + (after_index_const_time.tv_usec - before_index_const_time.tv_usec)*1.0/1000.0; cout<<"Index construction completed in : "<<index_construct_time<<" (ms). This time includes outputting the running information."<<endl; //Data structure must be used for ALL query: vertex_mapping_table, BitLabelTreeNode, tree_height; //Data structure must be used for distance query on undirected graphs: LabelGTUpdate, node_directory; //Data structure must be used for distance query on directed graphs: LabelGT_From_Update, LabelGT_To_Update, node_directory; //Optional Data structure for distance query on directed graphs: LabelGT_From_Mask, LabelGT_To_Mask, TreeNodeLevel; //Calculate TC size: long int TC_size=0; if(direct_info==DIRECT){ int From_size_1=0; int From_size_2=0; for (size_t i=0; i<LabelGT_From_Update.size(); i++){ for(size_t j=0; j<LabelGT_From_Update[i].size(); j++){ From_size_1+=LabelGT_From_Update[i][j].size(); From_size_2+=LabelGT_From_Mask[i][j].size(); } } int To_size_1=0; int To_size_2=0; for (size_t i=0; i<LabelGT_To_Update.size(); i++){ for(size_t j=0; j<LabelGT_To_Update[i].size(); j++){ To_size_1+=LabelGT_To_Update[i][j].size(); To_size_2+=LabelGT_To_Mask[i][j].size(); } } if(From_size_1!=To_size_1){ cout<<"From size and To size do not match. Error in direct labeling."<<endl; exit(-1); }else{ TC_size=From_size_1+To_size_1+From_size_2+To_size_2; } }else{ for (size_t i=0; i<LabelGTUpdate.size(); i++){ for(size_t j=0; j<LabelGTUpdate[i].size(); j++){ TC_size+=LabelGTUpdate[i][j].size(); } } } if(direct_info==DIRECT) cout<<"Total indexing size: "<<TC_size+vertex_mapping_table.size()*3+BitLabelTreeNode.size()+TreeNodeLevel.size()+node_directory_size+1<<endl; else cout<<"Total indexing size: "<<TC_size+vertex_mapping_table.size()*3+BitLabelTreeNode.size()+node_directory_size+1<<endl; cout<<"Start query..."<<endl; struct timeval after_time, before_time; int twd_distance, bfs_distance; vector<int>::iterator sit, tit; if(direct_info==DIRECT){ gettimeofday(&before_time,NULL); for(sit = src.begin(), tit = trg.begin(); sit != src.end(); ++sit, ++tit) twd_distance=queryDirectMask(vertex_mapping_table, BitLabelTreeNode, TreeNodeLevel, node_directory, LabelGT_From_Update, LabelGT_To_Update, LabelGT_From_Mask, LabelGT_To_Mask, tree_height, *sit, *tit); gettimeofday(&after_time,NULL); float query_time=(after_time.tv_sec - before_time.tv_sec)*1000.0 + (after_time.tv_usec - before_time.tv_usec)*1.0/1000.0; cout<<"twd distance query time: "<<query_time<<endl; }else{ gettimeofday(&before_time,NULL); for(sit = src.begin(), tit = trg.begin(); sit != src.end(); ++sit, ++tit) twd_distance=query(vertex_mapping_table, BitLabelTreeNode, node_directory, LabelGTUpdate, tree_height, *sit, *tit); gettimeofday(&after_time,NULL); float query_time=(after_time.tv_sec - before_time.tv_sec)*1000.0 + (after_time.tv_usec - before_time.tv_usec)*1.0/1000.0; cout<<"twd distance query time: "<<query_time<<endl; } cout<<"End Query..."<<endl; if(verify_enable==1){ cout<<"Start query verification."<<endl; if(direct_info==DIRECT){ for(sit = src.begin(), tit = trg.begin(); sit != src.end(); ++sit, ++tit){ twd_distance=queryDirectMask(vertex_mapping_table, BitLabelTreeNode, TreeNodeLevel, node_directory, LabelGT_From_Update, LabelGT_To_Update, LabelGT_From_Mask, LabelGT_To_Mask, tree_height, *sit, *tit); bfs_distance=GraphUtil::BFSDistanceDirect(g, *sit, *tit); if(twd_distance!=bfs_distance){ cout<<"twd_distance direct: "<<twd_distance<<endl; cout<<"bfs_distance direct: "<<bfs_distance<<endl; } } }else{ for(sit = src.begin(), tit = trg.begin(); sit != src.end(); ++sit, ++tit){ twd_distance=query(vertex_mapping_table, BitLabelTreeNode, node_directory, LabelGTUpdate, tree_height, *sit, *tit); bfs_distance=GraphUtil::BFSDistance(g, *sit, *tit); if(twd_distance!=bfs_distance){ cout<<"twd_distance: "<<twd_distance<<endl; cout<<"bfs_distance: "<<bfs_distance<<endl; } } } cout<<"end query verification."<<endl; } else{ cout<<"verification option waived."<<endl; } //find the minimum distance cout<<"end of the program"<<endl; }
int buildTreeWidthDecomposition(Graph& g, GenericTree& twd, vector<set<int> >& nodedirectory){//return the max_bag_size of this decomposition set<VertexDegreePair,VertexDegreePairComp> DegreeRank;//first is degree; second is vertex id; vector<int> DegreeList(g.num_vertices(),0); int max_bag_size=-1; for(int i=0; i<g.num_vertices(); i++){ int current_degree=g.get_degree(i); DegreeRank.insert(VertexDegreePair(i, current_degree)); DegreeList[i]=current_degree; } while(DegreeRank.size()>0){ set<VertexDegreePair,VertexDegreePairComp>::iterator minDegreeVertex=DegreeRank.begin(); DegreeRank.erase(DegreeRank.begin()); int current_vertexID=minDegreeVertex->first; //build treenode nodedirectory.push_back(set<int>()); int current_nodeID=nodedirectory.size()-1; nodedirectory.back().insert(current_vertexID); for(EdgeList::iterator vit=g.get_neighbors(current_vertexID).begin(); vit<g.get_neighbors(current_vertexID).end(); vit++){ nodedirectory.back().insert(*vit); g[*vit].nodes.push_back(current_nodeID); //update on graph EdgeList::iterator iit=g.get_neighbors(current_vertexID).begin(); EdgeList::iterator jit=g.get_neighbors(*vit).begin(); EdgeList combined; while(iit<g.get_neighbors(current_vertexID).end() && jit<g.get_neighbors(*vit).end()){ //It is assumed that a vertex itself does not appear in its adjacent list and the adjacent list is in ascending order. if(*iit==*vit){ iit++; continue; }else if (*jit==current_vertexID){ jit++; continue; } if(*iit<*jit){ combined.push_back(*iit); iit++; }else if(*iit>*jit){ combined.push_back(*jit); jit++; }else{//implies *iit==*jit combined.push_back(*iit); iit++; jit++; } } if(iit<g.get_neighbors(current_vertexID).end() && jit<g.get_neighbors(*vit).end()){ cout<<"Internal Logic Error. Exit."<<endl; exit(-1); } for(; iit<g.get_neighbors(current_vertexID).end(); iit++){ if(*iit!=*vit) combined.push_back(*iit); } for(; jit<g.get_neighbors(*vit).end(); jit++){ if(*jit!=current_vertexID) combined.push_back(*jit); } g.get_neighbors(*vit)=combined; //update on graph done //update on nodes vector<int> reduced; vector<int>::iterator itern=g[*vit].nodes.begin(); vector<int>::iterator jtern=g[current_vertexID].nodes.begin(); while(itern<g[*vit].nodes.end() && jtern<g[current_vertexID].nodes.end()){ if(*itern<*jtern){ reduced.push_back(*itern); itern++; } else if (*itern>*jtern){ jtern++; } else{//implies *itern==*jtern itern++; jtern++; } } for(; itern<g[*vit].nodes.end(); itern++) reduced.push_back(*itern); g[*vit].nodes=reduced; //update on nodes done //other update set<VertexDegreePair,VertexDegreePairComp>::iterator fit=DegreeRank.find(VertexDegreePair(*vit, DegreeList[*vit])); DegreeRank.erase(fit); DegreeRank.insert(VertexDegreePair(*vit, g.get_degree(*vit))); DegreeList[*vit]=g.get_degree(*vit); //other update done } max_bag_size=int(nodedirectory.back().size())>max_bag_size? int(nodedirectory.back().size()) : max_bag_size; //build treenode done //build decomposition tree twd.addNode(twd.num_nodes()); for(vector<int>::iterator nit=g[current_vertexID].nodes.begin(); nit<g[current_vertexID].nodes.end(); nit++){ twd.addEdge(current_nodeID, *nit);//current_nodeID shall always be larger than *nit; twd.addEdge(*nit, current_nodeID); } //build decomposition tree done //clear deleted vertex g[current_vertexID].nodes.clear(); g.get_neighbors(current_vertexID).clear(); //clear deleted vertex } return max_bag_size; }
void buildBinaryTree(GenericTree& btd, BinaryTree& btree, vector<int>& virtualnode_to_realnode){ multimap<int, int> subsize_root;////The first int is subtree size, and the second is node ID. for(int current_node=0; current_node<btd.num_nodes(); current_node++){ int current_node_level=btd[current_node].nodelevel; multimap<int, int> subsize_node;//The first int is subtree size, and the second is node ID. int parent=-1; int total_size=0; for(TreeEdgeList::iterator tit=btd.get_neighbors(current_node).begin(); tit!=btd.get_neighbors(current_node).end(); tit++){ if(btd[tit->nodeID].nodelevel>current_node_level){ subsize_node.insert(pair<int, int>(tit->subtree_size, tit->nodeID)); total_size+=tit->subtree_size; }else if (btd[tit->nodeID].nodelevel==current_node_level){ cout<<"Internal logic error 1 ocurrs on binary tree construction."<<endl; }else{//implies btd[tit->nodeID].nodelevel<current_node_level if (parent==-1){ parent=tit->nodeID; }else{ cout<<"Internal logic error 2 (multiple parents) ocurrs on binary tree construction."<<endl; } } } if (parent==-1){//implies root node subsize_root.insert(pair<int, int>(total_size+1, current_node)); } btree[current_node].parent=parent; if(subsize_node.size()==1){ btree[current_node].left_child=(subsize_node.begin())->second; }else if (subsize_node.size()==2){ multimap<int, int>::iterator mit=subsize_node.begin(); btree[current_node].left_child=mit->second; mit++; btree[current_node].right_child=mit->second; }else if (subsize_node.size()>2){ while(subsize_node.size()>2){ int first_size=(subsize_node.begin())->first; int first_node=(subsize_node.begin())->second; subsize_node.erase(subsize_node.begin()); int second_size=(subsize_node.begin())->first; int second_node=(subsize_node.begin())->second; subsize_node.erase(subsize_node.begin()); int new_node_id=btree.num_nodes(); //add a virtual node btree.addNode(new_node_id); virtualnode_to_realnode.push_back(current_node); //add a virtual node done btree[new_node_id].left_child=first_node; btree[new_node_id].right_child=second_node; btree[first_node].parent=new_node_id; btree[second_node].parent=new_node_id; subsize_node.insert(pair<int, int>(first_size+second_size, new_node_id)); } multimap<int, int>::iterator mit=subsize_node.begin(); btree[current_node].left_child=mit->second; btree[mit->second].parent=current_node; mit++; btree[current_node].right_child=mit->second; btree[mit->second].parent=current_node; } } int root=-1; if(subsize_root.size()==1){ root=(subsize_root.begin())->second; }else if (subsize_root.size()>1){ while(subsize_root.size()>1){ int first_size=(subsize_root.begin())->first; int first_node=(subsize_root.begin())->second; subsize_root.erase(subsize_root.begin()); int second_size=(subsize_root.begin())->first; int second_node=(subsize_root.begin())->second; subsize_root.erase(subsize_root.begin()); int new_node_id=btree.num_nodes(); //add a virtual node btree.addNode(new_node_id); virtualnode_to_realnode.push_back(-1);//If the root node is a virtual node, there is no real node can be associated with it. //add a virtual node done btree[new_node_id].left_child=first_node; btree[new_node_id].right_child=second_node; btree[first_node].parent=new_node_id; btree[second_node].parent=new_node_id; subsize_root.insert(pair<int, int>(first_size+second_size, new_node_id)); root=new_node_id; } } if(root<0){ cout<<"The btree is empty. Please check input."<<endl; return; }else{ btree.access_root()=root; btree[root].level=0; int maximum_level=0; queue<int> q; q.push(root); while(q.size()>0){ int j=q.front(); q.pop(); maximum_level=maximum_level>btree[j].level?maximum_level:btree[j].level; if (btree[j].left_child>=0){ btree[btree[j].left_child].level=btree[j].level+1; q.push(btree[j].left_child); } if (btree[j].right_child>=0){ btree[btree[j].right_child].level=btree[j].level+1; q.push(btree[j].right_child); } } btree.access_height()=maximum_level; } }