返回

优化递归:高效生成特定和的数字列表

python

优化数值生成函数中的递归循环

在编写涉及数值生成的程序时,经常会遇到递归函数效率低下,甚至达到递归限制的问题。本文探讨如何有效优化这类函数,尤其针对需要生成满足特定和的数字列表的情况,并提供了具体的解决策略。

问题分析:递归限制与效率瓶颈

上述问题集中在 rand_num_gen 函数。该函数通过随机生成数字并递归调用自身来尝试达到目标和。主要问题在于:

  1. 递归深度 : 当随机生成的数字和不等于目标值时,函数会不断递归调用自身。在某些情况下,很难通过随机的方式恰好生成满足条件的数字列表。这可能导致无限递归,最终触发 Python 的最大递归深度限制。
  2. 效率低下 : 反复的随机生成和求和过程效率低下,尤其在递归层级加深时,大量无意义的计算会被执行,造成性能损耗。

问题的本质在于,使用递归来寻找一个随机结果是不适合的,因为随机过程本身就带有不确定性,使用递归来控制不确定性效率低下。

解决方案一:迭代 + 逐步调整

一个更为有效的方案是采用迭代方法,配合数字的逐步调整。该方法避免了递归调用的限制,同时更加高效。具体来说,可以按以下步骤执行:

  1. 初始生成 : 先生成一个包含所需数量的随机数列表,范围是基于平均值加上或减去某个随机值。
  2. 计算和 : 计算生成列表的总和,并与目标值进行比较。
  3. 调整策略 :
    • 如果和小于目标值,从随机位置增加一个或者多个数字,反之,减小
    • 调整的量应当适当,不应造成太大的变化
    • 可以循环调整直至目标达成,或者在达到一定次数后结束并提示失败。

代码示例:

import random
import sys
from js import document, alert

def display_output(text):
    output_div = document.getElementById("output")
    output_div.innerHTML += text + "<br>"

def display_list_item(text):
    list_div = document.getElementById("list")
    new_item = document.createElement("div")
    new_item.textContent = text
    list_div.appendChild(new_item)

def get_inputx(x):
    while True:
       try:
            x = int(input(""))
            return x
       except ValueError:
            display_output("invalid, try again")
                         
def get_inputy(y):
    while True:
        try:
            y = int(input(""))
            return y 
        except ValueError:
            display_output("invalid, try again")
def rand_num_gen(average, num_count, target_sum):
    max_iterations = 1000  # 设置最大迭代次数
    numbers = [average + random.randrange(-101, 101) for _ in range(num_count)]  # 初始化列表
    for _ in range(max_iterations):
         current_sum = sum(numbers)
         if current_sum == target_sum:
             for num in numbers:
                  display_list_item(str(num))
             display_output(f"These numbers add up to: {current_sum}g")
             return
         elif current_sum < target_sum:
              index = random.randint(0, num_count - 1)
              numbers[index] +=1  #可以根据需求调整幅度
         else:
              index = random.randint(0, num_count-1)
              numbers[index] -= 1 
    display_output(f"无法找到符合条件的列表在{max_iterations} 次迭代之后")  # 若超时未找到答案,输出错误信息


def main():
    x = get_inputx(alert(f"enter total weight of plants in kg"))
    y = get_inputy(alert(f"enter total number of plants"))
    v = (x * 1000)
    z = (v / y)  # Average weight per plant
    display_output(f"Your average weight = {z}g"+"-----")
    display_output(f"Total weight = {v}g"+"-----")
    rand_num_gen(z, y, v)

main()

操作步骤:

  1. 将以上代码替换原有的函数实现。
  2. 执行 main 函数并输入参数即可观察改进后的运行效果。
  3. 若指定次数内找不到答案,函数会显示错误信息。

该方法采用循环而不是递归,可以避免 RecursionError 。通过逐步调整数字,算法可以更快速有效地收敛于目标和,效率远高于递归方式。可以调整max_iterations变量来控制运行时间,以及增加更精确的数字调整策略来满足不同的需求。

安全建议

  • 输入验证 : 始终对用户输入执行验证,确保数据类型正确、取值合理。避免将未验证的输入直接用于计算,可能造成不可预测的行为或者程序异常。
  • 明确边界 : 应当对可能出现极端情况提前做好规划,确保函数鲁棒性。比如对于找不到答案的情况,给出明确的错误提示。
  • 资源管理 : 当生成大量数据时,注意避免占用过多的内存。

结论

通过从递归方式转换为迭代配合逐步调整,数值生成函数的效率和可靠性得到显著提升。开发者应该时刻关注程序效率,避免使用低效的算法,例如不加限制的递归。通过理解问题的本质,选择合适的算法才是关键所在。