Collat​​z链算法RUBY

时间:2017-08-16 19:38:36

标签: ruby recursion collatz

我正在尝试根据Collat​​z序列填充数组。序列的约束如下:

正整数:

n→n / 2(n是偶数)

n→3n + 1(n为奇数)

示例输出

3 - > 10 - > 5 - > 16 - > 8 - > 4 - > 2 - > 1

理想情况下,我想构建一个递归调用,根据序列的约束填充数组。但是,我相信我的递归调用逻辑是非常有缺陷的。预期的行为是迭代嵌套数组,只操纵每个子数组的最后一个元素,直到元素达到1.我试图建立我对递归的理解,并希望有关如何解决这个问题的任何建议。

def collatzSum(maxNumber)

 sequenceHash = Hash.new(0)
  i = maxNumber
  until i == 0 do 
    if i.even?
      sequenceHash[i] = [(i), (i / 2)]
    elsif i.odd? && i != 1
      sequenceHash[i] = [(i), (3 * i + 1)]
   elsif i == 1 
      sequenceHash[i] = [i]
  end 
    i -= 1
 end
 p sequenceHash

helper_method递归。方法应该接受哈希值并根据if语句进行迭代。

=begin 
    desired output
    hash = {5=>[5,16, 8, 4, 2,1],
            4=>[4,2,1],
            3=>[3,10,5,16,8,4,2,1],
            2=>[2,1],
            1=>[1]}
=end 

代码:

 collatzChain = lambda do |k|
  j = 0
  k = j[-1]
   until k == 1 do
      if k.even?
        sequenceHash[k] << (k / 2)
     elsif k.odd?
       sequenceHash[k] << (3 * k + 1)
      end 
    end
  j += 1
end 
collatzChain.call(sequenceHash.values)
sequenceHash
end 

collatzSum(5)

2 个答案:

答案 0 :(得分:2)

所以你提到你想要一个递归算法,你当前的方法看起来是迭代的。要递归,您需要调用您所处的方法,使得值越来越接近基本条件,然后,一旦达到基本条件,就会返回,在调用链上构建返回值。因此,对于Collat​​z序列,递归方法看起来像:

def build_collatz_chain(max_number)
  return_value = [max_number]
  # our base condition is when the number passed in is equal to 1, so
  # when we get 1 as the max_number, we'll return an array looking like
  # [1]
  return return_value if max_number == 1

  if max_number.even?
    # here, with an even max_number, we'll recurse and call our method
    # again, passing in the new max_number, which is the current
    # max_number / 2.
    return_value + build_collatz_chain(max_number / 2)
  else
    # same as above, but we're odd, so we'll recurse with 3 * max_number + 1
    return_value + build_collatz_chain(3 * max_number + 1)
  end
end

现在当我们使用值5来调用它时,最终会发生的事情是这样的:

call build_collatz_chain(5)
  call build_collatz_chain(16)
    call build_collatz_chain(8)
      call build_collatz_chain(4)
        call build_collatz_chain(2)
          call build_collatz_chain(1)
          We have hit the base condition! return with [1]
        return from 2 with [2, 1]
      return from 4 with [4, 2, 1]
    return from 8 with [8, 4, 2, 1]
  return from 16 with [16, 8, 4, 2, 1]
return from 5 with [5, 16, 8, 4, 2, 1]

所以,现在如果你想要一个散列的所有数字,直到传递给max_number并将其Collat​​z链作为值,你可以使用帮助器为每个值调用它,最多为max(这个帮助器是迭代的,但可以进行递归...如果你想让它递归,请为观众锻炼):

def collatz_sum(max_number)
  { }.tap do |sequence_hash|
    max_number.downto(1) do |i|
      sequence_hash[i] = build_collatz_chain(i)
    end
  end
end

然后当你致电collatz_sum(5)时,你会回来:

{5=>[5, 16, 8, 4, 2, 1], 4=>[4, 2, 1], 3=>[3, 10, 5, 16, 8, 4, 2, 1], 2=>[2, 1], 1=>[1]}

您的方法迭代的原因是在collatzChain lambda中,您设置了一个值(j),然后递增它并循环直到k等于{{ 1}}。它也是一个无限循环,因为您最初将1设置为:

k

所以j = 0 k = j[-1] ,然后你迭代到k == 0,然后再也不会更新k == 1的值。

答案 1 :(得分:1)

目前还不清楚这里是否需要递归操作,因为这似乎是值 x f(x)之间的直接映射。通过切换到简单的数组输出,您可以实现您想要的目标:

SELECT 
    c.`competition_name`, 
    MAX(r.`result`), 
    s.`sportsman_name`
FROM `competition` c
INNER JOIN `results` r ON c.`competition_id` = r.`competition_id`
INNER JOIN `sportsman` s ON s.`sportsman_id` = r.`sportsman_id` 
GROUP BY c.`competition_name`;