zoukankan      html  css  js  c++  java
  • 《算法: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

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

  • 相关阅读:
    Javascript FP-ramdajs
    微信小程序开发
    SPA for HTML5
    One Liners to Impress Your Friends
    Sass (Syntactically Awesome StyleSheets)
    iOS App Icon Template 5.0
    React Native Life Cycle and Communication
    Meteor framework
    RESTful Mongodb
    Server-sent Events
  • 原文地址:https://www.cnblogs.com/wenruo/p/4602222.html
Copyright © 2011-2022 走看看