图的创建与遍历

Graph定义

在这里插入图片描述
Node类

class Node{
public:
    int value; 			//顶点的值value
    int in; 			//顶点的入度in(也就是指向该顶点的边数)
    int out; 			//顶点的出度out(也就是从该顶点出发的边数)
    list<Node*> nexts;  //当前节点为from,所有to节点的集合
    list<Edge*> edges; 	//从该节点出发边的集合edges

    Node(int value){
        this->value = value;
        in = 0;
        out = 0;
    }
};

Edge类

class Edge{
public:
    int weight; 		//边的权重weight
    Node* from; 		//from节点
    Node* to; 			//to节点

    Edge(int weight, Node* from, Node* to){
        this->weight = weight;
        this->from = from;
        this->to = to;
    }
};

Graph类

class Graph{
public:
    std::unordered_map<int, Node*> nodes; 	//存储所有Node以及它的下标编号
    std::unordered_set<Edge*> edges; 		//存储所有Edge
};

创建Graph

使用邻接矩阵,只需要输入一个Edge的weight、from节点的值和to节点的值就可以创建两个Node和一条Edge,然后添加入整个图中!

建图过程中,一定要注意,当加入一条边时,我们一定要将from节点的出度+1,to节点的入度+1,然后将to节点添加到from节点的nexts中,并将这个边添加到from节点的边集edges。

class GraphGenerator{
// 三列分别是权重,from, to
public:
    Graph createGraph(vector<vector<int>>& matrix, int rows, int cols){
        Graph graph;
        for(int i=0;i < rows;i ++){ //每一行就是三个数:权重,from,to
            int weight = matrix[i][0];
            int from = matrix[i][1];
            int to = matrix[i][2];
            //看看节点是否已经添加
            if(graph.nodes.find(from) == graph.nodes.end()){
                graph.nodes[from] = new Node(from);
            }
            if(graph.nodes.find(to) == graph.nodes.end()){
                graph.nodes[to] = new Node(to);
            }
            //创建节点
            Node* fromNode = graph.nodes.find(from)->second;
            Node* toNode = graph.nodes.find(to)->second;

            Edge* newEdge = new Edge(weight, fromNode, toNode);
            // 新增一条边,则to节点的入度增加
            toNode->in++;
            // from节点的出度增加
            fromNode->out++;
            fromNode->nexts.push_back(toNode);
            fromNode->edges.push_back(newEdge);
            graph.edges.insert(newEdge);
        }
        return graph;
    }
    
private:
vector<vector<int>> matrix = {	{6, 1, 2}, {5, 1, 4}, {2, 6, 4},
                                {6, 6, 5}, {3, 2, 5}, {1, 3, 1},
                                {5, 3, 2}, {6, 3, 5}, {4, 3, 6}, {5, 3, 4},  
                                // 只到这里为一个有向图,from和to再反过来一遍就是无向的了
                                {6, 2, 1}, {5, 4, 1}, {2, 4, 6},
                                {6, 5, 6}, {3, 5, 2}, {1, 1, 3},
                                {5, 2, 3}, {6, 5, 3}, {4, 6, 3}, {5, 4, 3}};
};

BFS(广度优先遍历)

// 广度优先遍历图节点
void BFS(Node* node){
    if(node == nullptr){
        return;
    }
    std::queue<Node*> que;
    std::unordered_set<Node*> set;   // 用来标示是否访问过
    Node* help;
    que.push(node);
    set.insert(node);
    while(!que.empty()){
        help = que.front();
        que.pop();
        cout << help->value << " ";
        // 使用出队的当前节点来找
        for(auto node: help->nexts){
            if(set.find(node) == set.end()){
                que.push(node);
                set.insert(node);
            }
        }
    }
    cout << endl;
}

DFS(深度优先遍历)

##迭代
void DFS(Node* node){
    std::stack<Node*> stack;
    std::unordered_set<Node*> set;   // 用来标示是否被访问过
    Node* help;   // 辅助节点
    // 入栈的同时并打印信息
    stack.push(node);
    set.insert(node);
    cout << node->value << " ";
    while(!sta.empty()){
        help = stack.top();
        stack.pop();
        // 对出栈的元素判断,如果被打印过,则不会被压栈,说明访问过了
        for(auto node: help->nexts){
            if(set.find(node) == set.end()){
                cout << node->value << " ";
                stack.push(help);  // 将访问的节点入栈,由于当前节点可能还有的分支没有访问
                stack.push(node);   
                set.insert(node);
                break;  // 每次只访问某个节点的一个分支,一直深入下去访问
            }
        }
    }
    cout << endl;
}
##递归
std::unordered_set<Node*> set;
void DFS(Node* node) {
	if (node == nullptr) return;

	set.insert(node);
	std::cout << node->value << std::endl;

	for (auto& item : node->nexts) {
		if(set.find(item)==set.end())
			DFS(item);
	}
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值