美文网首页
Algorithms - Week 1(1), Part I,

Algorithms - Week 1(1), Part I,

作者: Sisyphus235 | 来源:发表于2020-01-28 10:48 被阅读0次

    课程地址

    引言

    算法(Algorithms)是用来解决问题,在解决问题的过程中需要处理数据,数据结构(Data Structure)就是用来存储信息的。所以,算法和数据结构是计算机科学的基础,也是诸多知名公司最看重员工的能力,尤其在谷歌尤为突出。
    算法能解决哪些问题呢?常见如网络中的搜索和分布式文件系统,罕见如生物学的人类基因组计划和蛋白质折叠凳问题。
    算法可以追踪到欧几里得的年代,从 1930s 开始系统教学,它可以被看做是计算机科学从业者的基础,更可以被视为好奇求知识的人的共识,毕竟所有学科都离不开解决问题的目标。

    “ I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships. ”
    — Linus Torvalds (creator of Linux)

    算法和数据结构是计算机科学的基石,好像再怎么强调都不为过。或者说,有没有扎实的算法和数据结构的基础是码农和工程师的分界线。

    “ Algorithms + Data Structures = Programs. ”
    — Niklaus Wirth

    “ Algorithms: a common language for nature, human, and computer. ”
    — Avi Wigderson

    Union-Find

    Dynamic Connectivity

    通过探讨一个问题来解释算法是什么,动态连接就是这个示例。

    给定 N 个对象:
    定义 Union 命令是连接两个对象;
    定义 Find/connected 命令是检查两个对象是否连接。

    动态连接问题在实际生活中有广泛应用,例如数码相片中的像素点,网络中的计算机,社交网络中的人际关系等。
    首先要定义什么是连接:

    1. Reflective:p 与 p 是连接的;
    2. Symmetic:如果 p 与 q 是连接的,则 q 与 p 是连接的;
    3. Transitive:如果 p 与 q 是连接的,q 与 r 是连接的,则 p 与 r 是连接的。

    其次定义连接组(connected components):
    最大两两相互连接的对象群组.

    image
    上例中 0, 1+4+5,2+3+6+7 分别互相两两连接,形成 3 个连接组。

    Quick Find

    数据结构

    • 使用一个容量为 N 的数组记录数字 ID;
    • 两个元素如果相连则他们的数字 ID 相同,反之亦然。
    image
    FIND:检查两个对象的数字 ID 是否相同
    UNION:union(p, q) 就将所有数字 ID 等于 p 的对象的 ID 修改为 q。
    public class QuickFindUF {
        private int[] id;
        
        // 初始化数据结构,初始值是所有数字的 ID
        public QuickFindUF(int N) {
            id = new int[N];
            for (int i = 0; i < N; i++) {
                id[i] = i;
            }
        }
        
        // FIND 命令
        pulic boolean connected(int p, int q) {
            return id[p] == id[q];
        }
        
        // UNION 命令
        public void union(int p, int q) {
            int pid = id[p];
            int qid = id[q];
            for (int i = 0; i < N; i++) {
                if (id[i] == pid) {
                    id[i] = qid;
                }
            }
        }   
    }
    

    效率分析

    初始化效率是 O(N),Union 命令效率是 O(N),Find 命令效率是 O(1)。Union 的效率太低了。

    Quick Union

    数据结构

    • 使用一个容量为 N 的数组记录数字 ID;
    • id[i] 是 i 的 parent;
    • root 是数字 ID 指向自身的对象。
    image

    FIND:检查两个对象的 root 是否相同;
    UNION: union(p, q) 就将 p 的 root 指向 q 的 root。

    public class QuickUnionUF {
        private int[] id;
        
        // 初始化
        public QuickUnionUF(int N) {
            id = new int[N];
            for (int i = 0; i < N; i++) {
                id[i] = i;
            } 
        }
        
        private int root(int i) {
            while(id[i] != i) {
                i = id[i];
            }
            return i;
        }
        
        // FIND 命令
        public boolean connected(int p, int q) {
            return root(p) == root(q);
        }
        
        // UNION 命令
        public void union(int p, int q) {
            int rootP = root(p);
            int rootQ = root(q);
            id[rootP] = rootQ;
        }
    }
    

    效率分析

    初始化效率是 O(N),Union 命令效率是 O(N),Find 命令效率是 O(N),效率太低了。

    Improvements

    Weighting

    1. 提升 quick-union,避免较高的树;
    2. 记录每颗树的对象数量;
    3. 平衡树的高度,在 union 的时候将较小的树指向较大的树的 root。
    public class WeightedUF {
        private int[] id;
        private int[] size;
        
        // 初始化
        public WeightedUF(int N) {
            id = new int[N];
            for (int i = 0; i < N; i++) {
                id[i] = i;
                size[i] = 1;
            } 
        }
        
        private int root(int i) {
            while(id[i] != i) {
                i = id[i];
            }
            return i;
        }
        
        // FIND 命令
        public boolean connected(int p, int q) {
            return root(p) == root(q);
        }
        
        // UNION 命令
        public void union(int p, int q) {
            int rootP = root(p);
            int rootQ = root(q);
            if (rootP == rootQ) {
                return;
            }
            ...
        }
    }
    

    Path Compression

    压缩路径,减少查找 root 的比对。

    public class PathCompressionUF {
        private int[] id;
        
        // 初始化
        public PathCompressionUF(int N) {
            id = new int[N];
            for (int i = 0; i < N; i++) {
                id[i] = i;
            } 
        }
        
        private int root(int i) {
            while(id[i] != i) {
                id[i] = id[id[i]];
                i = id[i];
            }
            return i;
        }
        
        // FIND 命令
        public boolean connected(int p, int q) {
            return root(p) == root(q);
        }
        
        // UNION 命令
        public void union(int p, int q) {
            int rootP = root(p);
            int rootQ = root(q);
            id[rootP] = rootQ;
        }
    }
    

    效率分析

    在 N 个对象执行 M 次 union-find 操作的情况下,改进后的算法最坏效率是 N + M * lgN 次。

    应用

    渗滤

    • N * N 的格子;
    • 每个格子的打开概率是 p,阻塞概率是 1 - p;
    • 如果从上到下有一条打开格子连通的通路,则是渗滤的。
    image

    相关文章

      网友评论

          本文标题:Algorithms - Week 1(1), Part I,

          本文链接:https://www.haomeiwen.com/subject/qqbpthtx.html