• 《算法:C语言实现》阅读笔记


    //从今天起准备认真看完这本书。本渣虽然笨,但是窝懒啊。。。。

    //今天开始看第一章。希望坚持下去。

    第一章 引言

    通过讨论连通问题的几种算法,来引出算法的重要性。 

    1.1 连通问题的快速查找算法

    感觉就是把每个点染色,每个颜色代表一堆,互相连通。每次输入两个点,把两个点所属那个颜色改为相同,这样他们代表就都互相连通。

    时间复杂度:O(MN), M是输入指令次数,N是点个数

    //1.1 连通问题的快速查找算法
    #include <stdio.h>
     
    #define N 10
     
    int id[N];                          // 表示每个点的色
     
    int main()
    {
        //freopen("in.txt", "r", stdin);
        int i, t, p, q;
     
        for (i = 0; i < N; ++i)
            id[i] = i;                  // 开始每两个点都不连通,所以每个点一个颜色
        while (scanf("%d%d", &p, &q) == 2) {
            if (id[p] != id[q]) {
                for (t = id[p], i = 0; i < N; ++i)
                    if (id[i] == t)     // 把所有和p一个颜色的点染成q的颜色
                        id[i] = id[q];
            }
            for (i = 0; i < N; ++i)
                printf("%d ", id[i]);
            printf("
    ");
        }
        return 0;
    }

    1.2 连通问题的快速合并解法

    就是两个点相同就把两个点放到同一棵树上,这样两个点根相同代表他们连通。每次找到两个点的根,如果不相同,就把一个跟连到另一个根上。

    时间复杂度:O(MN),M是输入指令次数,N是点个数。当M>N时,执行次数为MN/2

    //1.2 连通问题的快速合并算法
    
    #include <stdio.h>
     
    #define N 10
     
    int main()
    {
        //freopen("in.txt", "r", stdin);
        int i, j, p, q;
        int id[N];                      // 表示每个点的父节点
        for (i = 0; i < N; ++i)
            id[i] = i;                  // 开始每两个点都不连通,所以每个点的父节点是自己
        while (scanf("%d%d", &p, &q) == 2) {
            for (i = p; i != id[i]; i = id[i])
                /*nothing*/ ;           // 当该节点的父节点与该节点相等时,证明该节点是根
            for (j = q; j != id[j]; j = id[j])
                /*nothing*/ ;
            if (i != j)                 //此时i为p的根,j为q的根
                id[i] = j;
            for (i = 0; i < N; ++i)
                printf("%d ", id[i]);
            printf("
    ");
        }
        return 0;
    }
    

    1.3 加权快速合并算法

    记录每棵树的节点个数,把节点少的根连到节点多的根。

    时间复杂度:lgN。每次找一个节点的根只需要lgN,因为1+lgi=lg2+lgi=lg(2i)=lg(i+i)<=lg(i+j)

    //1.3 加权快速合并算法
    #include <stdio.h>
    
    #define N 10
    
    int main()
    {
        freopen("in.txt", "r", stdin);
        int i, j, p, q;
        int id[N];                      // 表示每个点的父节点
        int sz[N];                      // 每棵树的节点个数
        for (i = 0; i < N; ++i) {
            id[i] = i;                  // 开始每两个点都不连通,所以每个点的父节点是自己
            sz[i] = 1;                  // 开始每个节点一棵树
        }
        while (scanf("%d%d", &p, &q) == 2) {
            for (i = p; i != id[i]; i = id[i])
                /*nothing*/ ;           // 当该节点的父节点与该节点相等时,证明该节点是根
            for (j = q; j != id[j]; j = id[j])
                /*nothing*/ ;           //此时i为p的根,j为q的根
            if (i != j && sz[i] < sz[j]) {
                //当j所在树节点多,就把i连j上
                id[i] = j;
                sz[j] += sz[i];
            } else if (i != j) {
                id[j] = i;
                sz[i] += sz[j];
            }
            for (i = 0; i < N; ++i)
                printf("%d ", id[i]);
            printf("
    ");
    
        }
        return 0;
    }
    

    1.4 等分路径压缩

    在查找根的过程中,使沿路每个节点的id指向根。 

     时间复杂度:接近O(n)?

    //1.4 等分路径压缩
    #include <stdio.h>
    
    #define N 10
    int main()
    {
        //freopen("in.txt", "r", stdin);
        int i, j, p, q;
        int id[N];                      // 表示每个点的父节点
        int sz[N];                      // 每棵树的节点个数
        for (i = 0; i < N; ++i) {
            id[i] = i;                  // 开始每两个点都不连通,所以每个点的父节点是自己
            sz[i] = 1;                  // 开始每个节点一棵树
        }
        while (scanf("%d%d", &p, &q) == 2) {
            for (i = p; i != id[i]; i = id[i]) {
                //printf("id[%d]=%d, id[id[%d]]=%d
    ", i, id[i], i, id[id[i]]);
                id[i] = id[id[i]];      // --------①--------
            }
            for (j = q; j != id[j]; j = id[j])
                id[j] = id[id[j]];
            if (i != j && sz[i] < sz[j]) {
                id[i] = j;
                sz[j] += sz[i];
            } else if (i != j) {
                id[j] = i;
                sz[i] += sz[j];
            }
            for (i = 0; i < N; ++i)
                printf("%d ", id[i]);
            printf("
    ");
    
        }
        return 0;
    }
    

    说一下窝对①处的理解。

    如果该节点为根节点或深度为2,即

    则不改变。

    如果深度为3,则

    ->

    深度为4

    ->

    深度为5

    深度为6

    这样每个节点的深度小了。搜索根节点的复杂度变小。(然而我觉得并没有什么卵用。。。。)

  • 相关阅读:
    技术部新年开工第一场会议
    mockjs学习总结(方便前端模拟数据,加快开发效率)
    vue开发后台管理系统小结
    网站代码、图片优化汇总
    前端seo小结,网页代码优化
    Java 并发编程之锁的实现
    python之格式化输出
    python七类之列表元组
    python七类之集合
    函数风云序列之函数初现
  • 原文地址:https://www.cnblogs.com/wenruo/p/4602222.html
Copyright © 2020-2023  润新知