拓扑排序算法

一,c语言的toposort

拓扑排序算法_第1张图片

拓扑排序算法_第2张图片

#include <iostream>
#include <stack>
using namespace std;


#define MAX_VERTEX_NUM    20
struct adjVertexNode //邻接表中的顶点
{
    int adjVertexPosition; //当前点在图中的相邻的位置
    adjVertexNode* next;   //邻接表的下一个位置
};
struct VertexNode
{
    char data[2];         //顶点的mark表示
    adjVertexNode* list;  //顶点构成的邻接表
    int indegree; //顶点的入度信息
}; 
struct Graph
{
    VertexNode VertexNode[MAX_VERTEX_NUM]; //顶点是用一个数组来存储的
    int vertexNum; //图中顶点的数量
    int edgeNum; //图中边的数量
};


void CreateGraph (Graph& g)
{
     int i, j, edgeStart, edgeEnd;
     adjVertexNode* adjNode;
cout<<"----------拓扑排序算法--------"<<endl;
     cout << "请输入顶点数 图中的边数:" <<endl;
     cin >> g.vertexNum >> g.edgeNum;
     cout << "输入图中每一个顶点的信息(v1)回车输入下一个" <<endl;
     for (i=0;i<g.vertexNum;i++) 
     {
         cin >> g.VertexNode[i].data;   //初始化每一个顶点的mark值(vi,A,或1),每一个顶点的邻接表初始化为NULL,顶点的入度为0;
         g.VertexNode[i].list = NULL;   
         g.VertexNode[i].indegree = 0;
     }
     cout << "输入每一条边的信息(start end):" <<endl;
     for (j=0; j<g.edgeNum; j++) 
     { 
         cin >>edgeStart >>edgeEnd; 
         adjNode = new adjVertexNode; 
         adjNode->adjVertexPosition = edgeEnd-1; // because array begin from 0, so it is j-1
         adjNode->next=g.VertexNode[edgeStart-1].list; //adjNode表示的是终止的节点,终止的节点始终指向发出线的节点
         g.VertexNode[edgeStart-1].list=adjNode; //终止节点加入图中
         //每增加一条边,则边的End顶点的入度加1
         g.VertexNode[edgeEnd-1].indegree++; 
     }
}


void PrintAdjList(const Graph& g)
{
    cout << "图的邻接表的具体表示如下:" << endl; 


//遍历图中每一个点的邻接表(因为是一个顶点对应一个邻接表list)
    for (int i=0; i < g.vertexNum; i++)
    {
        cout<< g.VertexNode[i].data << "->";
        adjVertexNode* head = g.VertexNode[i].list;
        if (head == NULL)
            cout << "NULL";
        while (head != NULL)
        {
            cout << head->adjVertexPosition + 1 <<" ";
            head = head->next;
        }
        cout << endl;
    }
}


VertexNode& FindZeroIndegree(Graph& g)
{
    for (int i=0; i<g.vertexNum; i++)
    {
        if (g.VertexNode[i].indegree==0)
            return g.VertexNode[i];
    }
    return g.VertexNode[0];
}


//toposort 算法
void TopSort(Graph& g)
{
    cout << "该图的拓扑排序是:" <<endl;
    for (int i=0; i<g.vertexNum; i++)
    {
        VertexNode& v = FindZeroIndegree(g);
        if (v.indegree!=NULL)
            cout << "该图中存在环,不能进行拓扑排序!!!"<<endl;
        cout<< v.data << " ";
        // for each vertex w adjacent to v, --indegree
        adjVertexNode* padjv = v.list;
        while (padjv!=NULL)
        {//!!这个算法这里破坏了原图中的入度信息。最后入度均为1
            g.VertexNode[padjv->adjVertexPosition].indegree--; //显然这里padjv记录的是每个顶点的位置信息
            padjv = padjv->next;
        }
        //避免入度信息均为零FindZeroIndegree找到删除的顶点,将删除的顶点入度置为1
        v.indegree++;
    }
    cout << endl;
}


/*void toppsort(Graph& g)
{
stack<VertexNode> s;
VertexNode node;
for(int i = 0;i<g.vertexNum;i++){
if(g.VertexNode[i].indegree==0)
{
s.push(g.VertexNode[i]);
}
}


while(s.empty())
{
node = s.top();
printf("%s->",node.data);
s.pop();


g.VertexNode[padjv->adjVertexPosition].indegree--;
node.list->next


}
}
*/
void DeleteGraph(Graph &g)
{
    for (int i=0; i<g.vertexNum; i++)
    {
        adjVertexNode* tmp=NULL;
        while(g.VertexNode[i].list!=NULL)
        {
            tmp = g.VertexNode[i].list;
            g.VertexNode[i].list = g.VertexNode[i].list->next;
            delete tmp;
            tmp = NULL;
        }
    }
}
int main_toop(int argc, const char** argv)
{
    Graph g;
    CreateGraph(g);
    PrintAdjList(g);
    TopSort(g);
    DeleteGraph(g);


    return 0;
}

二,java版的toposort

2-1 顶点类

package 拓扑排序;
public class Vertex {
    private String name;  
    int degree;
  
    public int getDegree() {
        return degree;
    }


    public void setDegree(int degree) {
        this.degree = degree;
    }


    public Vertex(String name) {  
        this.name = name;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
    
    @Override  
    public int hashCode() {  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + ((name == null) ? 0 : name.hashCode());  
        return result;  
    }  
  
    @Override  
    public boolean equals(Object obj) {  
        if (this == obj)  
            return true;  
        if (obj == null)  
            return false;  
        if (getClass() != obj.getClass())  
            return false;  
        Vertex other = (Vertex) obj;  
        if (name == null) {  
            if (other.name != null)  
                return false;  
        } else if (!name.equals(other.name))  
            return false;  
        return true;  
    }  
}

2-2 描述图的类

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


public class Graph {
    //用于存储顶点的集合Set
    private Set<Vertex> vertexSet = new HashSet<Vertex>();  
    // 这里的hashmap相当于一个邻接表,每一个顶点都对应这一个邻接表
    private Map<Vertex, Vertex[]> adjacencys = new HashMap<Vertex, Vertex[]>();   
    public Set<Vertex> getVertexSet() {  
        return vertexSet;  
    }  
  
    public void setVertexSet(Set<Vertex> vertexSet) {  
        this.vertexSet = vertexSet;  
    }  
  
    public Map<Vertex, Vertex[]> getAdjacencys() {  
        return this.adjacencys;  
    }  
  
    public void setAdjacencys(Map<Vertex, Vertex[]> adjacencys) {  
        this.adjacencys = adjacencys;  
    }  
}

2-3 测试类

package 拓扑排序;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;


public class test {
    public static Stack<Vertex> s;
    public static Map<Vertex, Vertex[]> edgeMap;
    public static int num = 0;
    public static List<Vertex> sortList;
    public static void main(String[] args) {


Graph graph = new Graph();
s = new Stack<Vertex>();
sortList = new ArrayList<Vertex>();

Set<Vertex> vertexSet = graph.getVertexSet();
num = vertexSet.size();
edgeMap = graph.getAdjacencys();

//用Java的map来构造邻接表分
Vertex oneVertex = new Vertex("1");
Vertex twoVertex = new Vertex("2");
Vertex threeVertex = new Vertex("3");
Vertex fourVertex = new Vertex("4");
Vertex fiveVertex = new Vertex("5");
Vertex sixVertex = new Vertex("6");


vertexSet.add(oneVertex);
vertexSet.add(twoVertex);
vertexSet.add(threeVertex);
vertexSet.add(fourVertex);
vertexSet.add(fiveVertex);
vertexSet.add(sixVertex);


edgeMap.put(oneVertex, new Vertex[] { twoVertex, threeVertex,fourVertex });
edgeMap.put(threeVertex, new Vertex[] { twoVertex, fiveVertex });
edgeMap.put(fourVertex, new Vertex[] { fiveVertex });
edgeMap.put(sixVertex, new Vertex[] { fourVertex, fiveVertex });
//edgeMap.put(fiveVertex, new Vertex[] { fourVertex });
// 统计节点的入读
for (Vertex vertex : vertexSet) {
   Vertex[] nodeList = edgeMap.get(vertex);//map遍历的时候一定要根据K获得V
   if (nodeList != null)
for (int j = 0; j < nodeList.length; j++) {
   nodeList[j].degree++;
}
}
toppSort(graph);
    }


    public static void toppSort(Graph graph) {
Set<Vertex> vertexSet = graph.getVertexSet();
for (Vertex vertex : vertexSet) {
   if (vertex.degree == 0) {
s.push(vertex);
System.out.println("入读为零的顶点:"+vertex.getName());
   }
}


Vertex temp = null;
while (!s.empty()) {
   temp = (Vertex) s.peek();
   sortList.add(temp);
   s.pop();


   Vertex vertex[] = edgeMap.get(temp);
   if (vertex != null)
for (int i = 0; i < vertex.length; i++) {
   vertex[i].degree--;
   if (vertex[i].degree == 0) {
s.push(vertex[i]);
   }
}
   vertexSet.remove(temp);
}


if (graph.getVertexSet().size() > num)
   System.out.println("该图中有环");
else{
   for(Vertex vertex:sortList){
System.out.print(vertex.getName()+"->");
   }
}
    }
}

三,用邻接矩阵作为数据结构的toposort,然后来求关键路径

拓扑排序算法_第3张图片

#include <iostream>
#include <stdio.h>
using namespace std;

const int rows=6;
//用一个邻接矩阵来表示一个DAG
int length[6][6]={
    {    0,    1,    0,    0,    2,   0},
    {    0,    0,    2,    5,    0,   0},
    {    0,    0,    0,    0,    0,   5},
    {    0,    0,    0,    0,    0,   3},
    {    0,    0,    2,    0,    0,   4},
    {    0,    0,    0,    0,    0,   0},
};

//拓扑排序选出下一个点的条件:没有入度的弧;没有被访问过;不能自己遍历自己
//其实这里得到的是一个topoSort
int getNextVertex( bool *set )
//获取下一个要加入集合S的结点:它的前驱结点都在集合S内
{
    for( int i=0; i<rows; i++ ){//论个扫描顶点
        if( set[i] ) continue;
        bool found = true;
        for( int j=0; j<rows; j++ ){
            if( set[j] ) continue;
            if( j == i ) continue;//自己访问自己没有意义(判断条件就是筛选规则)
            if( length[j][i]>0 ){//是竖着遍历一列一列的寻找,将有入度值得顶点过滤
                found = false;
            }
        }
        if( found ) {
return i;
}
    }
    return (-1);
}


int longestPath()
{
    bool inSourceSet[rows];
    for( int i=0; i<rows; i++ ){
        inSourceSet[i] = false;
    }
    inSourceSet[0] = true;
    int maxLength[rows]={0};//记录源结点到每个节点的最长路径长度
    string maxPath[rows];//记录源结点到每个节点的最长路径
    for( int j=1; j<rows; j++ ){
        int curVex = getNextVertex( inSourceSet );
        if( 0 == curVex ) continue;
        cout << "->" << curVex;
        int curMaxLen=0;
        int preVex=0;
        for( int i=0; i<rows; i++ ){//计算源结点到当前结点的最长路径长度和经过的结点并记录
            if( !inSourceSet[i] ) continue;//访问过的就不再访问
  //从某一列开始竖着找找到带权值的边,记录并检索谋一丁点到其他所有顶点的距离
            //在入度节点里面找到最大的入度边的值,覆盖原来的值。
            if( (length[i][curVex] > 0) && (curMaxLen < maxLength[i] + length[i][curVex]) ){
                curMaxLen = maxLength[i] + length[i][curVex];
                preVex = i;
            }
        }
        maxLength[curVex] = curMaxLen;
        inSourceSet[curVex] = true;
        maxPath[curVex] = maxPath[preVex];
        curMaxLen = 0;
    }
    return maxLength[rows-1];//返回到目标结点的最长路径
}


int main( int argc, char * argv[] )
{
    int length = longestPath();
    cout << "最长路径是: " << length << endl;
    return (0);
}


你可能感兴趣的:(拓扑排序算法)