《程序员面试金典》(第六版)习题:仅为记录一下以加强印象,不为商业用途,如有侵权请联系删除。以下源码和解释参考了书中源码以及解释。
拓扑排序法首先将项目的依赖关系构建为一张有向图,如果项目
a
a
a依赖于项目
b
b
b,则有一条由节点
b
b
b指向
a
a
a的有向边。根据项目之间的依赖关系,依照以上规则建立节点之间的有向图。然后首先将图中没有入边的节点拿出来,拿出的顺序没有要求,再将以之前拿出的节点为出射节点的边拿掉。再迭代以上过程直到图中没有节点位置
//拓扑排序法
class Project
{
private:
string name;
int dependencies;
vector<Project> *children;
unordered_map<string, Project> *hashMap;
public:
Project(string str="")
{
name = str;
dependencies = 0;
children=new vector<Project>();
hashMap=new unordered_map<string, Project>();
}
void addNeighbor(Project &node)
{
if (hashMap->find(node.getName())==hashMap->end())
{
node.increDependencies();
children->push_back(node);
hashMap->emplace(node.getName(), node);
}
}
string getName()
{
return name;
}
void increDependencies()
{
dependencies++;
}
void decreDependencies()
{
dependencies--;
}
vector<Project>* getChildren()
{
return children;
}
int getDependencies()
{
return dependencies;
}
void setDependencies(int value)
{
dependencies=value;
}
void setChildren(vector<Project>* value)
{
children = value;
}
};
class Graph
{
private:
vector<Project> *nodes;
unordered_map<string, Project> *hashMap;
int nodeNum;
public:
Graph()
{
nodes=new vector<Project>();
hashMap=new unordered_map<string, Project>();
nodeNum = 0;
}
Project& getOrCreateNode(string str)
{
if (hashMap->find(str) == hashMap->end())
{
nodeNum++;
Project node(str);
nodes->push_back(node);
hashMap->emplace(node.getName(), node);
}
return hashMap->at(str);
}
void addEdge(string startname,string endname)
{
/*Project &start = getOrCreateNode(startname);
Project &end = getOrCreateNode(endname);
start.addNeighbor(end);*/
getOrCreateNode(startname).addNeighbor(getOrCreateNode(endname));
}
vector<Project>* getNodes()
{
return nodes;
}
int getNodeNum()
{
return nodeNum;
}
unordered_map<string, Project>* gethashMap()
{
return hashMap;
}
void setNodes()
{
for (int i = 0; i < nodes->size(); i++)
{
nodes->at(i).setDependencies(hashMap->at(nodes->at(i).getName()).getDependencies());
nodes->at(i).setChildren(hashMap->at(nodes->at(i).getName()).getChildren());
}
}
};
int addNonDependent(Project* order,vector<Project>& projects, int offset)
{
for (Project project : projects)
{
if (project.getDependencies() == 0)
{
order[offset] = project;
offset++;
}
}
return offset;
}
Project* orderProjects(vector<Project> &projects)
{
int size = projects.size();
Project *order=new Project[size];
int endOfList = addNonDependent(order, projects, 0);
int toBeProcessed = 0;
while (toBeProcessed<size)
{
if (endOfList == 0)
return nullptr;
Project ¤t = order[toBeProcessed];
for (Project& project : (*current.getChildren()))
{
project.decreDependencies();
}
endOfList= addNonDependent(order, (*current.getChildren()), endOfList);
toBeProcessed++;
}
return order;
}
Graph buildGraph(vector<string> projects, vector<pair<string, string>> dependencies)
{
Graph myGraph;
for (string str : projects)
{
myGraph.getOrCreateNode(str);
}
for (pair<string, string> dependency : dependencies)
{
string first = dependency.first;
string second = dependency.second;
myGraph.addEdge(first, second);
}
myGraph.setNodes();
return myGraph;
}
Project* findBuildOrder(vector<string> projects, vector<pair<string, string>> dependencies)
{
Graph graph = buildGraph(projects, dependencies);
return orderProjects(*graph.getNodes());
}
//测试程序
int main()
{
vector<pair<string, string>> dependencies;
pair<string, string> p1("f", "c");
pair<string, string> p2("f", "b");
pair<string, string> p3("f", "a");
pair<string, string> p4("c", "a");
pair<string, string> p5("b", "a");
pair<string, string> p6("a", "e");
pair<string, string> p7("b", "e");
pair<string, string> p8("d", "g");
dependencies.push_back(p1);
dependencies.push_back(p2);
dependencies.push_back(p3);
dependencies.push_back(p4);
dependencies.push_back(p5);
dependencies.push_back(p6);
dependencies.push_back(p7);
dependencies.push_back(p8);
vector<string> projects;
projects.push_back("a");
projects.push_back("b");
projects.push_back("c");
projects.push_back("d");
projects.push_back("e");
projects.push_back("f");
projects.push_back("g");
Project* p=findBuildOrder(projects,dependencies);
cout << "The true order is:"<< endl;
for (int i = 0; i < 7; i++)
{
cout << p[i].getName() << endl;
}
}
深度优先搜索方法从通过节点间的依赖关系建立起来的图中的任意一个节点开始深度优先搜索,当遇到没有孩子的节点(没有出射边)或所有孩子节点状态不为 b l a n k blank blank的节点时,将该节点入栈并将该节点状态设置为 c o m p l e t e complete complete。完成整个深度优先搜索后,从栈顶到栈顶即为项目的编译顺序。
//DFS方法
enum State { complete, partial, blank };
class Project
{
private:
string name;
State state;
vector<Project*>* children;
unordered_map<string, Project*>* hashMap;
public:
Project(string str = "")
{
name = str;
state = blank;
children = new vector<Project*>();
hashMap = new unordered_map<string, Project*>();
}
void addNeighbor(Project* node)
{
if (hashMap->find(node->getName()) == hashMap->end())
{
children->push_back(node);
hashMap->emplace(node->getName(), node);
}
}
string getName()
{
return name;
}
vector<Project*>* getChildren()
{
return children;
}
State getState()
{
return state;
}
void setState(State value)
{
state = value;
}
void setChildren(vector<Project*>* value)
{
children = value;
}
};
class Graph
{
private:
vector<Project*>* nodes;
unordered_map<string, Project*>* hashMap;
int nodeNum;
public:
Graph()
{
nodes = new vector<Project*>();
hashMap = new unordered_map<string, Project*>();
nodeNum = 0;
}
Project* getOrCreateNode(string str)
{
if (hashMap->find(str) == hashMap->end())
{
nodeNum++;
Project *node=new Project(str);
nodes->push_back(node);
hashMap->emplace(node->getName(), node);
}
return hashMap->at(str);
}
void addEdge(string startname, string endname)
{
getOrCreateNode(startname)->addNeighbor(getOrCreateNode(endname));
}
vector<Project*>* getNodes()
{
return nodes;
}
int getNodeNum()
{
return nodeNum;
}
unordered_map<string, Project*>* gethashMap()
{
return hashMap;
}
void setNodes()
{
for (int i = 0; i < nodes->size(); i++)
{
//nodes->at(i).setState(hashMap->at(nodes->at(i).getName()).getState());
nodes->at(i)->setChildren(hashMap->at(nodes->at(i)->getName())->getChildren());
}
}
};
bool doDFS(Project* project, stack<Project*>* order)
{
cout <<"Go into project: " << project->getName() <<", It has "<<project->getChildren()->size()<<" children."<<endl;
if (project->getState() == partial)
{
cout << "return2323232323" << endl;
return false;
}
if(project->getState() == blank)
{
project->setState(partial);
if (project->getChildren()->size() != 0)
{
for (Project* pro : (*project->getChildren()))
{
if (!doDFS(pro, order))
return false;
}
}
cout << "Push project: "<< project->getName() <<endl;
project->setState(complete);
order->push(project);
}
cout << "Return from project: " << project->getName() <<endl;
return true;
}
stack<Project*>* orderProjects(vector<Project*> * projects)
{
stack<Project*> *order=new stack<Project*>();
for (Project* project : *projects)
{
if (project->getState() == blank)
{
if (!doDFS(project, order))
return nullptr;
}
}
return order;
}
Graph buildGraph(vector<string> projects, vector<pair<string, string>> dependencies)
{
Graph myGraph;
for (string str : projects)
{
myGraph.getOrCreateNode(str);
}
for (pair<string, string> dependency : dependencies)
{
string first = dependency.first;
string second = dependency.second;
myGraph.addEdge(first, second);
}
myGraph.setNodes();
return myGraph;
}
stack<Project*>* findBuildOrder(vector<string> projects, vector<pair<string, string>> dependencies)
{
Graph graph = buildGraph(projects, dependencies);
return orderProjects(graph.getNodes());
}
//测试程序
int main()
{
vector<pair<string, string>> dependencies;
pair<string, string> p1("f", "c");
pair<string, string> p2("f", "b");
pair<string, string> p3("f", "a");
pair<string, string> p4("c", "a");
pair<string, string> p5("b", "a");
pair<string, string> p6("a", "e");
pair<string, string> p7("b", "e");
pair<string, string> p8("d", "g");
dependencies.push_back(p1);
dependencies.push_back(p2);
dependencies.push_back(p3);
dependencies.push_back(p4);
dependencies.push_back(p5);
dependencies.push_back(p6);
dependencies.push_back(p7);
dependencies.push_back(p8);
vector<string> projects;
projects.push_back("a");
projects.push_back("b");
projects.push_back("c");
projects.push_back("d");
projects.push_back("e");
projects.push_back("f");
projects.push_back("g");
stack<Project*>* p=findBuildOrder(projects,dependencies);
cout << "The true order is:"<< endl;
cout << "p->size()=" << p->size() << endl;
int stackSize = p->size();
for (int i = 0; i < stackSize; i++)
{
cout << p->top()->getName() << endl;
p->pop();
}
}