常用图结构实现

仅个人常用结构实现-没有复杂的算法:将图问题先转换成个人熟悉的图结构

点的类结构代码:

public class Node { //点类
    public int val;     //具体值
    public int in;      //多少点连向它
    public int out;     //多少点被它连着
    public ArrayList<Node> nexts;   //它能直接到达的点
    public ArrayList<Side> sides;   //它能使用的边
    public Node(int val) {
        this.val = val;
        this.in = 0;
        this.out = 0;
        this.nexts = new ArrayList<>();
        this.sides = new ArrayList<>();
    }

    //重写equals和hashcode,使点和点的比较,只对val判定
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Node node = (Node) o;
        return val == node.val;
    }

    @Override
    public int hashCode() {
        return Objects.hash(val);
    }
}

边的类结构代码:

public class Side {
    public int weight;      //边的权重
    public Node form;       //这条边由谁连
    public Node to;         //这条边连向谁

    public Side() {
    }

    public Side(int weight, Node form, Node to) {
        this.weight = weight;
        this.form = form;
        this.to = to;
    }
}

图的结构代码:

//图
public class Picture {
    Picture p;
    public ArrayList<Node> nodes;   //点
    public ArrayList<Side> sides;   //边

    public Picture() {
    }

    public Picture(Node nodes, Side sides) {
        this.nodes = new ArrayList<>();
        this.sides = new ArrayList<>();
    }

    //初始化图-输入一个二阶矩阵,trista[a][b]中,trista[a][0]:form出发点,trista[a][1]:form到达点,trista[a][2]:权重值,
    public Picture initialization (int[][] trista){
        if(p==null){
            //图不存在就创建一个新图
            p = new Picture();
        }
        //遍历所有二阶数组矩阵
        for (int i = 0; i <trista.length; i++) {
            //先创建2个点
            Node thisform = new Node(trista[i][0]);
            Node thisto = new Node(trista[i][1]);
            //判断图中是否存在这2个点,  已重写equals、hashcode,只比node.val;
            if(!p.nodes.contains(thisform)){
                nodes.add(thisform);
            }
            if(!p.nodes.contains(thisto)){
                nodes.add(thisto);
            }
            //重新拿出该图的node集合中的对应点-可能之前图中已经存在对应点,那么就应该使用之前的点
            thisform = p.nodes.get(trista[i][0]);
            thisto = p.nodes.get(trista[i][1]);
            //创建对应的边-每条边都是新的-不需要在sides集合判断
            Side thisside = new Side(trista[i][2], thisform, thisto);
            p.sides.add(thisside);
            //同时,进行数据的更新,比如出发点的out、next、side
            thisform.out++;
            thisto.in++;
            thisform.nexts.add(thisto);
            thisform.sides.add(thisside);
        }

        return p;
    }
        
    //广度优先遍历
    public void bfs(Node node){
        //队列-实现广度优先遍历
        Queue<Node> queue = new LinkedList<>();
        HashSet<Node> set = new HashSet<>();
        queue.add(node);
        set.add(node);
        while (!queue.isEmpty()){
            //弹栈即打印
            Node cur = queue.poll();
            System.out.println(cur.val);
            //遍历当前弹栈点的所有邻点-set保证所有点不会第二次添加到队列中
            for (Node node1:cur.nexts) {
                if(!set.contains(node1)){
                    queue.add(node1);
                    set.add(node1);
                }
            }
        }
    }

    //深度优先遍历
    public void dfs(Node node){
        //同理,用栈先进后出实现深度优先,set保证点不进入第二次
        Stack<Node> stack = new Stack<>();
        HashSet<Node> set = new HashSet<>();
        stack.push(node);
        System.out.println(node.val);
        //进栈即打印
        set.add(node);
        while (!stack.isEmpty()){
            Node cur = stack.pop();
            for (Node c: cur.nexts) {
                if(!set.contains(c)){
                    /**
                     *注意,是深度优先,所以我们找到一个邻点,就先去邻点访问其nexts,所以先将cur进栈,然后再让邻点cur进栈,让邻栈先遍历
                     */
                    stack.add(cur);         //有点类似状态回溯
                    stack.add(c);
                    System.out.println(c.val);
                    set.add(c);
                    //然后先退出此次的遍历
                    break;
                }
            }
        }
    }
}

拓扑遍历

//图的拓扑结构遍历---当点与点之前存在 推论关系(必须先做A、B..才能做C),怎么遍历打印
    public void topology(Picture p){
        //记录每个点和它的入度-入度为0即可遍历(装入queue容器)
        HashMap<Node, Integer> map = new HashMap<>();
        Queue<Node> queue = new LinkedList<>();
        for (Node node:p.nodes) {
            int in = node.in;
            if(in == 0){
                queue.add(node);
            }else {
                map.put(node,in);
            }
        }
        //最终的打印容器
        ArrayList<Node> list = new ArrayList<>();
        while (!queue.isEmpty()){
            Node poll = queue.poll();
            list.add(poll);
            //对每个邻节点,入度-1
            for (Node node:poll.nexts) {
                int i = node.in - 1;
                if(i==0){
                    queue.add(node);
                }else {
                    map.put(node,i);
                }
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值