/* Graph Sort * Copyleft (C) 2002 David Griffiths * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "GraphSort.h" //#define GRAPHSORT_TRACE ////////////////////////////////////////////////////////// GraphSort::GraphSort(bool UseTestSort) { m_UseTestSort=UseTestSort; } GraphSort::~GraphSort() { } void GraphSort::Clear() { //m_Sorted.clear(); m_Graph.clear(); } const list &GraphSort::GetSortedList() { return m_Sorted; } void GraphSort::Sort() { m_UseTestSort?TestSort():OrigSort(); } void GraphSort::TestSort() { m_Sorted.clear(); list Candidates; #ifdef GRAPHSORT_TRACE cerr<<"finding seed candidates"<::iterator i=m_Graph.begin(); i!=m_Graph.end(); i++) { // all nodes need these vars reset i->second.UnsatisfiedOutputs = i->second.Outputs.size(); i->second.IsSorted = false; if (i->second.Outputs.empty() || i->second.IsTerminal) { // terminals and roots are seed candidates Candidates.push_back(i->first); i->second.IsCandidate=true; #ifdef GRAPHSORT_TRACE cerr<first<<" is seed candidate"<second.IsCandidate = false; } } while (!Candidates.empty()) { int NodeToSort; bool FoundNodeToSort=false; // look for an ideal candidate for (list::iterator i = Candidates.begin(); i!=Candidates.end() && !FoundNodeToSort; i++) { if (!m_Graph[*i].UnsatisfiedOutputs) { NodeToSort=*i; FoundNodeToSort=true; #ifdef GRAPHSORT_TRACE cerr<<"sorted "<::iterator i=m_Graph[NodeToSort].Inputs.begin(); i!=m_Graph[NodeToSort].Inputs.end(); i++) { // ...have another satisfied output... m_Graph[*i].UnsatisfiedOutputs--; if(!m_Graph[*i].IsCandidate && !m_Graph[*i].IsSorted) { // ..and are promoted to candidate if they haven't been already Candidates.push_back(*i); m_Graph[*i].IsCandidate=true; #ifdef GRAPHSORT_TRACE cerr<<*i<<" is now a candidate"<::iterator i=m_Sorted.begin(); i!=m_Sorted.end(); i++) { cerr<<*i<<" "; } cerr< RootNodes; bool FoundRoot=false; for (map::iterator i=m_Graph.begin(); i!=m_Graph.end(); i++) { // if there are no outputs, this must be a root if (i->second.Outputs.empty()) { FoundRoot=true; RecursiveWalk(i->first); } } // no roots found - try looking for a terminal node and recursing from // there, this makes circular graphs work. if (!FoundRoot) { for (map::iterator i=m_Graph.begin(); i!=m_Graph.end(); i++) { // if there are no outputs, this must be a root if (i->second.IsTerminal) { RecursiveWalk(i->first); } } } #ifdef GRAPHSORT_TRACE for(list::iterator i=m_Sorted.begin(); i!=m_Sorted.end(); i++) { cerr<<*i<<" "; } cerr<::iterator i=m_Graph.find(node); for(list::iterator ii=i->second.Inputs.begin(); ii!=i->second.Inputs.end(); ii++) { RecursiveWalk(*ii); } } void GraphSort::Dump() { for (map::iterator i=m_Graph.begin(); i!=m_Graph.end(); i++) { cerr<<"Node "<first<::iterator si=m_Graph.find(SID); if (si==m_Graph.end()) { Node newnode; newnode.IsTerminal = STerminal; m_Graph[SID]=newnode; #ifdef GRAPHSORT_TRACE cerr<<"added "<::iterator di=m_Graph.find(DID); if (di==m_Graph.end()) { Node newnode; newnode.IsTerminal = DTerminal; m_Graph[DID]=newnode; #ifdef GRAPHSORT_TRACE cerr<<"added "<::iterator si=m_Graph.find(SID); if (si==m_Graph.end()) { cerr<<"GraphSort::RemoveConnection - can't find source node"<::iterator di=m_Graph.find(DID); if (di==m_Graph.end()) { cerr<<"GraphSort::RemoveConnection - can't find dest node"<::iterator soi = find(si->second.Outputs.begin(), si->second.Outputs.end(), DID); if (soi==si->second.Outputs.end()) cerr<<"GraphSort::RemoveConnection - can't find soi"<second.Outputs.erase(soi); list::iterator dii = find(di->second.Inputs.begin(), di->second.Inputs.end(), SID); if (dii==di->second.Inputs.end()) cerr<<"GraphSort::RemoveConnection - can't find dii"<second.Inputs.erase(dii); // check to remove the nodes if (si->second.Outputs.empty() && si->second.Inputs.empty()) { m_Graph.erase(si); #ifdef GRAPHSORT_TRACE cerr<<"removed "<second.Outputs.empty() && di->second.Inputs.empty()) { m_Graph.erase(di); #ifdef GRAPHSORT_TRACE cerr<<"removed "<