You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
4.7KB

  1. /* Graph Sort
  2. * Copyleft (C) 2002 David Griffiths <dave@pawfal.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <iostream>
  19. #include "GraphSort.h"
  20. //#define GRAPHSORT_TRACE
  21. //////////////////////////////////////////////////////////
  22. GraphSort::GraphSort()
  23. {
  24. }
  25. GraphSort::~GraphSort()
  26. {
  27. }
  28. void GraphSort::Clear()
  29. {
  30. //m_Sorted.clear();
  31. m_Graph.clear();
  32. }
  33. const list<int> &GraphSort::GetSortedList()
  34. {
  35. return m_Sorted;
  36. }
  37. void GraphSort::Sort()
  38. {
  39. // walk back from all the roots
  40. m_Sorted.clear();
  41. list<int> RootNodes;
  42. bool FoundRoot=false;
  43. for (map<int,Node>::iterator i=m_Graph.begin();
  44. i!=m_Graph.end(); i++)
  45. {
  46. // if there are no outputs, this must be a root
  47. if (i->second.Outputs.empty())
  48. {
  49. FoundRoot=true;
  50. RecursiveWalk(i->first);
  51. }
  52. }
  53. // no roots found - try looking for a terminal node and recursing from
  54. // there, this makes circular graphs work.
  55. if (!FoundRoot)
  56. {
  57. for (map<int,Node>::iterator i=m_Graph.begin();
  58. i!=m_Graph.end(); i++)
  59. {
  60. // if there are no outputs, this must be a root
  61. if (i->second.IsTerminal)
  62. {
  63. RecursiveWalk(i->first);
  64. }
  65. }
  66. }
  67. #ifdef GRAPHSORT_TRACE
  68. for(list<int>::iterator i=m_Sorted.begin();
  69. i!=m_Sorted.end(); i++)
  70. {
  71. cerr<<*i<<" ";
  72. }
  73. cerr<<endl;
  74. #endif
  75. }
  76. void GraphSort::RecursiveWalk(int node)
  77. {
  78. // check it's not been logged already
  79. // (don't want to execute the node twice)
  80. if(find(m_Sorted.begin(),m_Sorted.end(),node)==m_Sorted.end())
  81. {
  82. #ifdef GRAPHSORT_TRACE
  83. //cerr<<"adding "<<node<<" to list"<<endl;
  84. #endif
  85. m_Sorted.push_back(node);
  86. }
  87. else
  88. {
  89. #ifdef GRAPHSORT_TRACE
  90. //cerr<<"Node "<<node<<" already logged, ending this path"<<endl;
  91. #endif
  92. return;
  93. }
  94. // branch back into the inputs
  95. map<int,Node>::iterator i=m_Graph.find(node);
  96. for(list<int>::iterator ii=i->second.Inputs.begin();
  97. ii!=i->second.Inputs.end(); ii++)
  98. {
  99. RecursiveWalk(*ii);
  100. }
  101. }
  102. void GraphSort::Dump()
  103. {
  104. for (map<int,Node>::iterator i=m_Graph.begin();
  105. i!=m_Graph.end(); i++)
  106. {
  107. cerr<<"Node "<<i->first<<endl;
  108. cerr<<"i=";
  109. for (list<int>::iterator ii=i->second.Inputs.begin();
  110. ii!=i->second.Inputs.end(); ii++)
  111. {
  112. cerr<<*ii<<" ";
  113. }
  114. cerr<<endl<<"o=";
  115. for (list<int>::iterator oi=i->second.Outputs.begin();
  116. oi!=i->second.Outputs.end(); oi++)
  117. {
  118. cerr<<*oi<<" ";
  119. }
  120. cerr<<endl;cerr<<endl;
  121. }
  122. }
  123. void GraphSort::AddConnection(int SID, bool STerminal, int DID, bool DTerminal)
  124. {
  125. map<int,Node>::iterator si=m_Graph.find(SID);
  126. if (si==m_Graph.end())
  127. {
  128. Node newnode;
  129. newnode.IsTerminal = STerminal;
  130. m_Graph[SID]=newnode;
  131. #ifdef GRAPHSORT_TRACE
  132. cerr<<"added "<<SID<<endl;
  133. #endif
  134. }
  135. map<int,Node>::iterator di=m_Graph.find(DID);
  136. if (di==m_Graph.end())
  137. {
  138. Node newnode;
  139. newnode.IsTerminal = DTerminal;
  140. m_Graph[DID]=newnode;
  141. #ifdef GRAPHSORT_TRACE
  142. cerr<<"added "<<DID<<endl;
  143. #endif
  144. }
  145. m_Graph[SID].Outputs.push_back(DID);
  146. m_Graph[DID].Inputs.push_back(SID);
  147. Sort();
  148. }
  149. void GraphSort::RemoveConnection(int SID, int DID)
  150. {
  151. map<int,Node>::iterator si=m_Graph.find(SID);
  152. if (si==m_Graph.end())
  153. {
  154. cerr<<"GraphSort::RemoveConnection - can't find source node"<<endl;
  155. }
  156. map<int,Node>::iterator di=m_Graph.find(DID);
  157. if (di==m_Graph.end())
  158. {
  159. cerr<<"GraphSort::RemoveConnection - can't find dest node"<<endl;
  160. }
  161. list<int>::iterator soi = find(si->second.Outputs.begin(), si->second.Outputs.end(), DID);
  162. if (soi==si->second.Outputs.end()) cerr<<"GraphSort::RemoveConnection - can't find soi"<<endl;
  163. else si->second.Outputs.erase(soi);
  164. list<int>::iterator dii = find(di->second.Inputs.begin(), di->second.Inputs.end(), SID);
  165. if (dii==di->second.Inputs.end()) cerr<<"GraphSort::RemoveConnection - can't find dii"<<endl;
  166. else di->second.Inputs.erase(dii);
  167. // check to remove the nodes
  168. if (si->second.Outputs.empty() && si->second.Inputs.empty())
  169. {
  170. m_Graph.erase(si);
  171. #ifdef GRAPHSORT_TRACE
  172. cerr<<"removed "<<SID<<endl;
  173. #endif
  174. }
  175. if (di->second.Outputs.empty() && di->second.Inputs.empty())
  176. {
  177. m_Graph.erase(di);
  178. #ifdef GRAPHSORT_TRACE
  179. cerr<<"removed "<<DID<<endl;
  180. #endif
  181. }
  182. Sort();
  183. }