算法——图的排序

引言

本文整理了常见的图排序相关算法,方便以后查阅。更多相关文章和其他文章均收录于贝贝猫的文章目录

BFS

package bbm.graph;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

import static bbm.graph.BFS.Color.BLACK;
import static bbm.graph.BFS.Color.GRAY;
import static bbm.graph.BFS.Color.WHITE;

/**
 * 图的广度优先搜索,以链表的形式表述邻接关系, 这里我们利用队列来实现 BFS
 *
 * BFS 可以用来计算最短路径
 *
 * @author bbm
 */
public class BFS {

    public static class Node {
        String name;
        Color color = WHITE;
        int d = Integer.MAX_VALUE;
        Node pre = null;
        List<Node> neighbors = new LinkedList<>();

        public Node(String name) {
            this.name = name;
        }
    }

    public static enum Color {
        WHITE,
        GRAY,
        BLACK
    }

    public static void bfs(Node node) {
        LinkedBlockingQueue<Node> queue = new LinkedBlockingQueue<>();
        node.color = GRAY;
        node.d = 0;
        node.pre = null;
        queue.offer(node);
        while (!queue.isEmpty()) {
            Node current = queue.poll();
            current.neighbors.forEach(neighbor -> {
                if (neighbor.color.equals(WHITE)) {
                    neighbor.color = GRAY;
                    neighbor.d = current.d + 1;
                    neighbor.pre = current;
                    queue.offer(neighbor);
                }
            });
            current.color = BLACK;
            System.out.println("Node " + current.name + ", d: " + current.d);
        }
    }

    public static void main(String[] args) {
        Node s = new Node("s");
        Node r = new Node("r");
        Node v = new Node("v");
        Node w = new Node("w");
        Node t = new Node("t");
        Node x = new Node("x");
        Node y = new Node("y");
        Node u = new Node("u");
        s.neighbors.add(w);
        s.neighbors.add(r);

        r.neighbors.add(s);
        r.neighbors.add(v);

        v.neighbors.add(r);

        w.neighbors.add(s);
        w.neighbors.add(t);
        w.neighbors.add(x);

        t.neighbors.add(u);
        t.neighbors.add(x);
        t.neighbors.add(w);

        x.neighbors.add(w);
        x.neighbors.add(t);
        x.neighbors.add(y);
        x.neighbors.add(u);

        y.neighbors.add(x);
        y.neighbors.add(u);

        u.neighbors.add(t);
        u.neighbors.add(x);
        u.neighbors.add(y);
        bfs(s);
        System.out.println("Path from s to y:");
        printPath(s, y);
        System.out.println();
    }

    private static void printPath(Node s, Node y) {
        if (s == y) {
            System.out.print(s.name + " ");
        } else {
            if (y.pre == null) {
                System.out.println("No path from " + s.name + " to " + y.name);
            } else {
                printPath(s, y.pre);
                System.out.print(y.name + " ");
            }
        }
    }
}

DFS

package bbm.graph;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import static bbm.graph.DFS.Color.BLACK;
import static bbm.graph.DFS.Color.GRAY;
import static bbm.graph.DFS.Color.WHITE;

/**
 * 图的广度优先搜索,用颜色来表示是否已经开始处理某一个节点,白色:未处理,灰色:处理中,黑色:处理完
 *
 * 如果我们将每个节点的开始处理时间记为 startTime 处理完成时间记录为 endTime 那么我们可以通过 startTime 和 endTime 够成一个括号化结构
 * Node x, start:4 end:5 被包含在 Node y, start:3 end:6 之中,这实际上就是一个树形结构, 当 x 节点的 start 和 end 在 y 节点的
 * start end 范围内时,x 节点就是 y 节点的子节点
 *     y(3, 6)
 *     /
 *  x(4,5)
 *
 * 通过这个深度优先树,我们可以简单的通过检查是否有由子节点到父节点的边来判断图中是否有环
 * @author bbm
 */
public class DFS {
    public static class Node {
        String name;
        Color color = WHITE;
        int startTime;
        int endTime;
        Node pre = null;
        List<Node> neighbors = new LinkedList<>();

        public Node(String name) {
            this.name = name;
        }
    }

    public static enum Color {
        WHITE,
        GRAY,
        BLACK
    }

    public static int time = 0;

    public static void dfs(List<Node> graph) {
        graph.forEach(node -> {
            if (node.color.equals(WHITE)) {
                visit(node);
            }
        });
    }

    private static void visit(Node node) {
        time += 1;
        node.startTime = time;
        node.color = GRAY;
        node.neighbors.forEach(neighbor -> {
            if (neighbor.color.equals(WHITE)) {
                neighbor.pre = node;
                visit(neighbor);
            }
        });
        node.color = BLACK;
        time += 1;
        node.endTime = time;
        System.out.println("Node " + node.name + ", start:" + node.startTime + " end:" + node.endTime);
    }

    public static void main(String[] args) {
        Node u = new Node("u");
        Node v = new Node("v");
        Node w = new Node("w");
        Node x = new Node("x");
        Node y = new Node("y");
        Node z = new Node("z");
        u.neighbors.add(v);
        u.neighbors.add(x);

        v.neighbors.add(y);

        w.neighbors.add(y);
        w.neighbors.add(z);

        x.neighbors.add(v);

        y.neighbors.add(x);

        z.neighbors.add(z);
        List<Node> graph = Arrays.asList(u, v, w, x, y, z);
        dfs(graph);
    }
}

拓扑排序

package bbm.graph;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import static bbm.graph.TopologicalOrder.Color.GRAY;
import static bbm.graph.TopologicalOrder.Color.WHITE;

/**
 * 当且仅当图中没有定向环时(即有向无环图),才有可能进行拓扑排序。
 *
 * 在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,才能称为该图的一个拓扑排序(英语:Topological sorting):
 * 1. 序列中包含每个顶点,且每个顶点只出现一次;
 * 2. 若A在序列中排在B的前面,则在图中不存在从B到A的路径。
 *
 *
 * @author bbm
 */
public class TopologicalOrder {
    public static class Node {
        String name;
        Color color = WHITE;
        int startTime;
        int endTime;
        Node pre = null;
        List<Node> next = new LinkedList<>();

        public Node(String name) {
            this.name = name;
        }
    }

    public static enum Color {
        WHITE,
        GRAY,
        BLACK
    }

    public static int time = 0;

    public static void dfs(List<Node> graph) {
        graph.forEach(node -> {
            if (node.color.equals(WHITE)) {
                visit(node);
            }
        });
    }

    private static void visit(Node node) {
        time += 1;
        node.startTime = time;
        node.color = GRAY;
        node.next.forEach(neighbor -> {
            if (neighbor.color.equals(WHITE)) {
                neighbor.pre = node;
                visit(neighbor);
            }
        });
        node.color = Color.BLACK;
        time += 1;
        node.endTime = time;
    }

    public static void topologicalSort(List<Node> nodes) {
        dfs(nodes);
        nodes.sort((o1, o2) -> o2.endTime - o1.endTime);
        for (Node node : nodes) {
            System.out.print(node.name + " ");
        }
    }

    public static void main(String[] args) {
        Node w = new Node("袜子");
        Node n = new Node("内裤");
        Node k = new Node("裤子");
        Node x = new Node("鞋子");
        Node s = new Node("手表");
        Node c = new Node("衬衣");
        Node y = new Node("腰带");
        Node l = new Node("领带");
        Node j = new Node("夹克");
        w.next.add(x);
        n.next.addAll(Arrays.asList(k, x));
        k.next.addAll(Arrays.asList(x, y));
        c.next.addAll(Arrays.asList(y, l));
        y.next.add(j);
        l.next.add(j);
        List<Node> nodes = Arrays.asList(w, n, k, x, s, c, y, l, j);
        topologicalSort(nodes);
    }
}

参考内容

[1] 《算法导论》

stun

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
冒泡排序是一种简单的排序算法,它重复地遍历待排序的元素,比较相邻元素的大小,如果顺序错误就交换它们,直到没有需要交换的元素为止。下面是冒泡排序的C语言实现: ```c void bubbleSort(int arr[], int n) { for(int i = 0; i < n-1; i++) { int flag = 0; //是否冒泡 for(int j = 0; j < n-1; j++) { if(arr[j > arr[j+1]) { swap(&arr[j], &arr[j+1]); flag = 1; } } if(flag == 0) { //如果没有发生交换,说明数组已经有序,可以提前结束循环 break; } } } ``` 在这个实现中,冒泡排序函数`bubbleSort`接受一个整型数组`arr`和数组长度`n`作为参数。它使用两层循环来遍历数组,并通过比较相邻元素的大小来进行交换。内层循环每次将最大的元素冒泡到数组的末尾。外层循环控制了冒泡的轮数,每一轮都会将当前未排序的最大元素放在正确的位置上。如果在某一轮的冒泡过程中没有发生交换,说明数组已经有序,可以提前结束循环,从而提高算法的效率。 需要注意的是,上述代码中使用了一个`swap`函数来交换两个元素的值,你可以根据需要自行实现该函数。此外,为了减少冒泡排序的时间复杂度,可以在内层循环中添加一个标志位`flag`,用于标记是否发生了交换。如果某一轮的冒泡过程中没有发生交换,说明数组已经有序,可以提前结束循环。这样可以避免不必要的比较和交换操作,提高排序的效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝克街的流浪猫

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值