数据结构从小白到小小白——绪论

绪论


首先,分大类:有四个!集合、线性、树、图


然后,明确基本概念和术语……

数据:什么都可以作为数据,在计算机科学中可以是输入,也可以是输出。
数据元素:是数据的基本单位。例如:图中的一个圆圈即是一个数据元素。有时,一个数据元素可由若干个数据项组成,例如,一本书书目信息为一个数据元素,而书目信息中的每一项 (如:书名、作者名等)为一个数据项。数据项是数据的不可分割的最小单位。
数据对象同一类数据可以认为是数据对象,是数据的一个子集。


再看存储结构……有顺序存储结构链式存储结构,顺序即可理解为数组,意思就是编号即顺序,元素之间有一定的顺序和逻辑联系。链式存储结构可以理解为指针的思想,例如:前驱带着后继的指针,如果不是C语言,可以理解为静态链表的形式。


抽象模型在编程时是常规操作了,抽象模型的模型又可以抽象为一个三元组(D,S,P),即数据类型和变量要定义,关系要明确,操作写清楚。

ADT 抽象数据类型名{
        数据对象
        数据关系
        基本操作
}ADT 抽象数据类型名

typedef ElemType * Triplet; //由InitTriplet分配3个元素存储空间
//基本操作的函数原型------------------------------------------
Status InitTriplet(Triplet &T,ElemType v1,ElemType v2,ElemType v3)
//构造了三元组T,元素e1,e2,e3分别被赋以参数v1,v2,v3的值

最后说一下算法……好的数据结构能够大大提升算法的效率,学会计算算法的效率至关重要,接下来就来看看怎么计算代码的时间复杂度和空间复杂度

  • 时间复杂度

我们假设计算机运行一行基础代码需要执行一次运算。

int aFunc(void) {
    printf("Hello, World!\n");      //  需要执行 1 次
    return 0;       // 需要执行 1 次
}

那么上面这个方法需要执行 2 次运算

int aFunc(int n) {
    for(int i = 0; i<n; i++) {         // 需要执行 (n + 1) 次
        printf("Hello, World!\n");      // 需要执行 n 次
    }
    return 0;       // 需要执行 1 次
}

这个方法需要 (n + 1 + n + 1) = 2n + 2 次运算。

我们有规定:如果一个算法的执行次数是 T(n),那么只保留最高次项,同时忽略最高项的系数后得到函数 f(n),此时算法的时间复杂度就是 O(f(n))。

由此可见,由执行次数 T(n) 得到时间复杂度并不困难,很多时候困难的是从算法通过分析和数学运算得到 T(n)。对此,提供下列四个便利的法则,这些法则都是可以简单推导出来的,总结出来以便提高效率:

  • 对于一个循环,假设循环体的时间复杂度为 O(n),循环次数为 m,则这个
    循环的时间复杂度为 O(n×m)。
void aFunc(int n) {
    for(int i = 0; i < n; i++) {         // 循环次数为 n
        printf("Hello, World!\n");      // 循环体时间复杂度为 O(1)
    }
}

此时时间复杂度为 O(n × 1),即 O(n)。

  • 对于多个循环,假设循环体的时间复杂度为 O(n),各个循环的循环次数分别是a, b, c…,则这个循环的时间复杂度为 O(n×a×b×c…)。分析的时候应该由里向外分析这些循环。
void aFunc(int n) {
    for(int i = 0; i < n; i++) {         // 循环次数为 n
        for(int j = 0; j < n; j++) {       // 循环次数为 n
            printf("Hello, World!\n");      // 循环体时间复杂度为 O(1)
        }
    }
}

此时时间复杂度为 O(n × n × 1),即 O(n^2)。

  • 对于顺序执行的语句或者算法,总的时间复杂度等于其中最大的时间复杂度。
void aFunc(int n) {
    // 第一部分时间复杂度为 O(n^2)
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            printf("Hello, World!\n");
        }
    }
    // 第二部分时间复杂度为 O(n)
    for(int j = 0; j < n; j++) {
        printf("Hello, World!\n");
    }
}

此时时间复杂度为 max(O(n^2), O(n)),即 O(n^2)。

  • 对于条件判断语句,总的时间复杂度等于其中 时间复杂度最大的路径 的时间复杂度。
void aFunc(int n) {
    if (n >= 0) {
        // 第一条路径时间复杂度为 O(n^2)
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                printf("输入数据大于等于零\n");
            }
        }
    } else {
        // 第二条路径时间复杂度为 O(n)
        for(int j = 0; j < n; j++) {
            printf("输入数据小于零\n");
        }
    }
}

此时时间复杂度为 max(O(n^2), O(n)),即 O(n^2)。


总结一下:时间复杂度分析的基本策略是:从内向外分析,从最深层开始分析。如果遇到函数调用,要深入函数进行分析。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值