数据结构笔记浅记(一)

 

 

 

迭代:是一种重复执行某个任务的控制结构。在迭代中,程序会在满足一定的条件下重复执行某 段代码,直到这个条件不再满足。

    以 for、while 为代表

        总的来说,for 循环的代码更加紧凑,while 循环更加灵活,两者都可以实现迭代结构。选择使用哪一个应该 根据特定问题的需求来决定。

 

递归:是一种算法策略,通过函数调用自身来解决问题。

        它主要包含两个阶段。

                1. 递:程序不断深入地调用自身,通常传入更小或更简化的参数,直到达到“终止条件”。

                 2. 归:触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。

        而从实现的角度看,递归代码主要包含三个要素。

                1. 终止条件:用于决定什么时候由“递”转“归”。

                2. 递归调用:对应“递”,函数调用自身,通常输入更小或更简化的参数。

                3. 返回结果:对应“归”,将当前递归层级的结果返回至上一层。

以求和为例对比:对比普通递归和尾递归,两者的求和操作的执行点是不同的。 ‧

普通递归:当函数返回到上一层级的函数后,需要继续执行代码,因此系统需要保存上一层调用的上下 文。 ‧

            求和操作是在“归”的过程中执行的,每层返回后都要再执行一次求和操作。 ‧

尾递归:递归调用是函数返回前的最后一个操作,这意味着函数返回到上一层级后,无须继续执行其他 操作,因此系统无须保存上一层函数的上下文。

            求和操作是在“递”的过程中执行的,“归”的过程只需层层返回。

 

小结:从计算角度看,迭代与递归可以得到相同的结果,但它们代表了两种完全不同的思考和解决问题的范 式。 ‧ 迭代:“自下而上”地解决问题。从最基础的步骤开始,然后不断重复或累加这些步骤,直到任务完成。 ‧ 递归:“自上而下”地解决问题。将原问题分解为更小的子问题,这些子问题和原问题具有相同的形式。

        1. 调用栈

                递归函数每次调用自身时,系统都会为新开启的函数分配内存,以存储局部变量、调用地址和其他信息等。 这将导致两方面的结果。 ‧ 函数的上下文数据都存储在称为“栈帧空间”的内存区域中,直至函数返回后才会被释放。因此,递归 通常比迭代更加耗费内存空间。 ‧ 递归调用函数会产生额外的开销。因此递归通常比循环的时间效率更低。

***:在实际中,编程语言允许的递归深度通常是有限的,过深的递归可能导致栈溢出错误。***

 

递归树:以“斐波那契数列” 为例。  给定一个斐波那契数列 0, 1, 1, 2, 3, 5, 8, 13, … ,求该数列的第 𝑛 个数字。 设斐波那契数列的第 𝑛 个数字为 𝑓(𝑛) ,

即 𝑓(𝑛) = 𝑓(𝑛 − 1) + 𝑓(𝑛 − 2) 。

在函数内递归调用了两个函数,这意味着从一个调用产生了两个调用分支。最终将产生一棵层数为 𝑛 的  递归树。

        从本质上看,递归体现了“将问题分解为更小子问题”的思维范式,这种分治策略至关重要。

                ‧ 从算法角度看,搜索、排序、回溯、分治、动态规划等许多重要算法策略直接或间接地应用了这种思维 方式。

                ‧ 从数据结构角度看,递归天然适合处理链表、树和图的相关问题,因为它们非常适合用分治思想进行分析。

 

迭代和递归使用场景:

    迭代:适用于简单循环任务,代码直观、可读性好

    递归:适用于子问题分解,如树、图、分治、回溯等,代码结构简洁、清晰

 

应该如何准确预估一段代码的运行时间?

1. 确定运行平台,包括硬件配置、编程语言、系统环境等,这些因素都会影响代码的运行效率。

2. 评估各种计算操作所需的运行时间,例如加法操作 + 需要 1 ns ,乘法操作 * 需要 10 ns ,打印操作 print() 需要 5 ns 等。

3. 统计代码中所有的计算操作,并将所有操作的执行时间求和,从而得到运行时间。    

 

时间复杂度分析统计的不是算法运行时间,而是算法运行时间随着数据量变大时的增长趋势。

 

相较于直接统计算法的运行时间,时间复杂度分析有哪些特点呢?

‧ 时间复杂度能够有效评估算法效率。例如,算法 B 的运行时间呈线性增长,在 𝑛 > 1 时比算法 A 更慢, 在 𝑛 > 1000000 时比算法 C 更慢。事实上,只要输入数据大小 𝑛 足够大,复杂度为“常数阶”的算法 一定优于“线性阶”的算法,这正是时间增长趋势的含义。

‧ 时间复杂度的推算方法更简便。显然,运行平台和计算操作类型都与算法运行时间的增长趋势无关。因 此在时间复杂度分析中,我们可以简单地将所有计算操作的执行时间视为相同的“单位时间”,从而将 “计算操作运行时间统计”简化为“计算操作数量统计”,这样一来估算难度就大大降低了。

‧ 时间复杂度也存在一定的局限性。例如,尽管算法 A 和 C 的时间复杂度相同,但实际运行时间差别很 大。同样,尽管算法 B 的时间复杂度比 C 高,但在输入数据大小 𝑛 较小时,算法 B 明显优于算法 C 。在 这些情况下,我们很难仅凭时间复杂度判断算法效率的高低。当然,尽管存在上述问题,复杂度分析仍 然是评判算法效率最有效且常用的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章