mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-24 10:36:29 +08:00
feat: Add Ruby code - chapter "computational complexity" (#1212)
* feat: add ruby code - chapter computational complexity * feat: add ruby code blocks
This commit is contained in:
parent
df83b869eb
commit
fd580a184a
9 changed files with 581 additions and 4 deletions
78
codes/ruby/chapter_computational_complexity/iteration.rb
Normal file
78
codes/ruby/chapter_computational_complexity/iteration.rb
Normal file
|
@ -0,0 +1,78 @@
|
|||
=begin
|
||||
File: iteration.rb
|
||||
Created Time: 2024-03-30
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
### for 循环 ###
|
||||
def for_loop(n)
|
||||
res = 0
|
||||
|
||||
# 循环求和 1, 2, ..., n-1, n
|
||||
for i in 1..n
|
||||
res += i
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
### while 循环 ###
|
||||
def while_loop(n)
|
||||
res = 0
|
||||
i = 1 # 初始化条件变量
|
||||
|
||||
# 循环求和 1, 2, ..., n-1, n
|
||||
while i <= n
|
||||
res += i
|
||||
i += 1 # 更新条件变量
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
### while 循环(两次更新)###
|
||||
def while_loop_ii(n)
|
||||
res = 0
|
||||
i = 1 # 初始化条件变量
|
||||
|
||||
# 循环求和 1, 4, 10, ...
|
||||
while i <= n
|
||||
res += i
|
||||
# 更新条件变量
|
||||
i += 1
|
||||
i *= 2
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
### 双层 for 循环 ###
|
||||
def nested_for_loop(n)
|
||||
res = ""
|
||||
|
||||
# 循环 i = 1, 2, ..., n-1, n
|
||||
for i in 1..n
|
||||
# 循环 j = 1, 2, ..., n-1, n
|
||||
for j in 1..n
|
||||
res += "(#{i}, #{j}), "
|
||||
end
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
|
||||
n = 5
|
||||
|
||||
res = for_loop n
|
||||
puts "\nfor 循环的求和结果 res = #{res}"
|
||||
|
||||
res = while_loop n
|
||||
puts "\nwhile 循环的求和结果 res = #{res}"
|
||||
|
||||
res = while_loop_ii n
|
||||
puts "\nwhile 循环(两次更新)求和结果 res = #{res}"
|
||||
|
||||
res = nested_for_loop n
|
||||
puts "\n双层 for 循环的遍历结果 #{res}"
|
69
codes/ruby/chapter_computational_complexity/recursion.rb
Normal file
69
codes/ruby/chapter_computational_complexity/recursion.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
=begin
|
||||
File: recursion.rb
|
||||
Created Time: 2024-03-30
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
### 递归 ###
|
||||
def recur(n)
|
||||
# 终止条件
|
||||
return 1 if n == 1
|
||||
# 递:递归调用
|
||||
res = recur n - 1
|
||||
# 归:返回结果
|
||||
n + res
|
||||
end
|
||||
|
||||
### 使用迭代模拟递归 ###
|
||||
def for_loop_recur(n)
|
||||
# 使用一个显式的栈来模拟系统调用栈
|
||||
stack = []
|
||||
res = 0
|
||||
|
||||
# 递:递归调用
|
||||
for i in n.downto(0)
|
||||
# 通过“入栈操作”模拟“递”
|
||||
stack << i
|
||||
end
|
||||
# 归:返回结果
|
||||
while !stack.empty?
|
||||
res += stack.pop
|
||||
end
|
||||
|
||||
# res = 1+2+3+...+n
|
||||
res
|
||||
end
|
||||
|
||||
### 尾递归 ###
|
||||
def tail_recur(n, res)
|
||||
# 终止条件
|
||||
return res if n == 0
|
||||
# 尾递归调用
|
||||
tail_recur n - 1, res + n
|
||||
end
|
||||
|
||||
### 斐波那契数列:递归 ###
|
||||
def fib(n)
|
||||
# 终止条件 f(1) = 0, f(2) = 1
|
||||
return n - 1 if n == 1 || n == 2
|
||||
# 递归调用 f(n) = f(n-1) + f(n-2)
|
||||
res = fib(n - 1) + fib(n - 2)
|
||||
# 返回结果 f(n)
|
||||
res
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
|
||||
n = 5
|
||||
|
||||
res = recur n
|
||||
puts "\n递归函数的求和结果 res = #{res}"
|
||||
|
||||
res = for_loop_recur n
|
||||
puts "\n使用迭代模拟递归求和结果 res = #{res}"
|
||||
|
||||
res = tail_recur n, 0
|
||||
puts "\n尾递归函数的求和结果 res = #{res}"
|
||||
|
||||
res = fib n
|
||||
puts "\n斐波那契数列的第 #{n} 项为 #{res}"
|
|
@ -0,0 +1,91 @@
|
|||
=begin
|
||||
File: space_complexity.rb
|
||||
Created Time: 2024-03-30
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
require_relative '../utils/list_node'
|
||||
require_relative '../utils/tree_node'
|
||||
require_relative '../utils/print_util'
|
||||
|
||||
### 函数 ###
|
||||
def function
|
||||
# 执行某些操作
|
||||
0
|
||||
end
|
||||
|
||||
### 常数阶 ###
|
||||
def constant(n)
|
||||
# 常量、变量、对象占用 O(1) 空间
|
||||
a = 0
|
||||
nums = [0] * 10000
|
||||
node = ListNode.new
|
||||
|
||||
# 循环中的变量占用 O(1) 空间
|
||||
(0...n).each { c = 0 }
|
||||
# 循环中的函数占用 O(1) 空间
|
||||
(0...n).each { function }
|
||||
end
|
||||
|
||||
### 线性阶 ###
|
||||
def linear(n)
|
||||
# 长度为 n 的列表占用 O(n) 空间
|
||||
nums = Array.new n, 0
|
||||
|
||||
# 长度为 n 的哈希表占用 O(n) 空间
|
||||
hmap = {}
|
||||
for i in 0...n
|
||||
hmap[i] = i.to_s
|
||||
end
|
||||
end
|
||||
|
||||
### 线性阶(递归实现)###
|
||||
def linear_recur(n)
|
||||
puts "递归 n = #{n}"
|
||||
return if n == 1
|
||||
linear_recur n - 1
|
||||
end
|
||||
|
||||
### 平方阶 ###
|
||||
def quadratic(n)
|
||||
# 二维列表占用 O(n^2) 空间
|
||||
Array.new(n) { Array.new n, 0 }
|
||||
end
|
||||
|
||||
### 平方阶(递归实现)###
|
||||
def quadratic_recur(n)
|
||||
return 0 unless n > 0
|
||||
|
||||
# 数组 nums 长度为 n, n-1, ..., 2, 1
|
||||
nums = Array.new n, 0
|
||||
quadratic_recur n - 1
|
||||
end
|
||||
|
||||
### 指数阶(建立满二叉树)###
|
||||
def build_tree(n)
|
||||
return if n == 0
|
||||
|
||||
TreeNode.new.tap do |root|
|
||||
root.left = build_tree n - 1
|
||||
root.right = build_tree n - 1
|
||||
end
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
|
||||
n = 5
|
||||
|
||||
# 常数阶
|
||||
constant n
|
||||
|
||||
# 线性阶
|
||||
linear n
|
||||
linear_recur n
|
||||
|
||||
# 平方阶
|
||||
quadratic n
|
||||
quadratic_recur n
|
||||
|
||||
# 指数阶
|
||||
root = build_tree n
|
||||
print_tree root
|
164
codes/ruby/chapter_computational_complexity/time_complexity.rb
Normal file
164
codes/ruby/chapter_computational_complexity/time_complexity.rb
Normal file
|
@ -0,0 +1,164 @@
|
|||
=begin
|
||||
File: time_complexity.rb
|
||||
Created Time: 2024-03-30
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
### 常数阶 ###
|
||||
def constant(n)
|
||||
count = 0
|
||||
size = 100000
|
||||
|
||||
(0...size).each { count += 1 }
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
### 线性阶 ###
|
||||
def linear(n)
|
||||
count = 0
|
||||
(0...n).each { count += 1 }
|
||||
count
|
||||
end
|
||||
|
||||
### 线性阶(遍历数组)###
|
||||
def array_traversal(nums)
|
||||
count = 0
|
||||
|
||||
# 循环次数与数组长度成正比
|
||||
for num in nums
|
||||
count += 1
|
||||
end
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
### 平方阶 ###
|
||||
def quadratic(n)
|
||||
count = 0
|
||||
|
||||
# 循环次数与数据大小 n 成平方关系
|
||||
for i in 0...n
|
||||
for j in 0...n
|
||||
count += 1
|
||||
end
|
||||
end
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
### 平方阶(冒泡排序)###
|
||||
def bubble_sort(nums)
|
||||
count = 0 # 计数器
|
||||
|
||||
# 外循环:未排序区间为 [0, i]
|
||||
for i in (nums.length - 1).downto(0)
|
||||
# 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
|
||||
for j in 0...i
|
||||
if nums[j] > nums[j + 1]
|
||||
# 交换 nums[j] 与 nums[j + 1]
|
||||
tmp = nums[j]
|
||||
nums[j] = nums[j + 1]
|
||||
nums[j + 1] = tmp
|
||||
count += 3 # 元素交换包含 3 个单元操作
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
### 指数阶(循环实现)###
|
||||
def exponential(n)
|
||||
count, base = 0, 1
|
||||
|
||||
# 细胞每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1)
|
||||
(0...n).each do
|
||||
(0...base).each { count += 1 }
|
||||
base *= 2
|
||||
end
|
||||
|
||||
# count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
|
||||
count
|
||||
end
|
||||
|
||||
### 指数阶(递归实现)###
|
||||
def exp_recur(n)
|
||||
return 1 if n == 1
|
||||
exp_recur(n - 1) + exp_recur(n - 1) + 1
|
||||
end
|
||||
|
||||
### 对数阶(循环实现)###
|
||||
def logarithmic(n)
|
||||
count = 0
|
||||
|
||||
while n > 1
|
||||
n /= 2
|
||||
count += 1
|
||||
end
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
### 对数阶(递归实现)###
|
||||
def log_recur(n)
|
||||
return 0 unless n > 1
|
||||
log_recur(n / 2) + 1
|
||||
end
|
||||
|
||||
### 线性对数阶
|
||||
def linear_log_recur(n)
|
||||
return 1 unless n > 1
|
||||
|
||||
count = linear_log_recur(n / 2) + linear_log_recur(n / 2)
|
||||
(0...n).each { count += 1 }
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
### 阶乘阶(递归实现)###
|
||||
def factorial_recur(n)
|
||||
return 1 if n == 0
|
||||
|
||||
count = 0
|
||||
# 从 1 个分裂出 n 个
|
||||
(0...n).each { count += factorial_recur(n - 1) }
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
|
||||
# 可以修改 n 运行,体会一下各种复杂度的操作数量变化趋势
|
||||
n = 8
|
||||
puts "输入数据大小 n = #{n}"
|
||||
|
||||
count = constant n
|
||||
puts "常数阶的操作数量 = #{count}"
|
||||
|
||||
count = linear n
|
||||
puts "线性阶的操作数量 = #{count}"
|
||||
count = array_traversal Array.new n, 0
|
||||
puts "线性阶(遍历数组)的操作数量 = #{count}"
|
||||
|
||||
count = quadratic n
|
||||
puts "平方阶的操作数量 = #{count}"
|
||||
nums = Array.new(n) { |i| n - i } # [n, n-1, ..., 2, 1]
|
||||
count = bubble_sort nums
|
||||
puts "平方阶(冒泡排序)的操作数量 = #{count}"
|
||||
|
||||
count = exponential n
|
||||
puts "指数阶(循环实现)的操作数量 = #{count}"
|
||||
count = exp_recur n
|
||||
puts "指数阶(递归实现)的操作数量 = #{count}"
|
||||
|
||||
count = logarithmic n
|
||||
puts "对数阶(循环实现)的操作数量 = #{count}"
|
||||
count = log_recur n
|
||||
puts "对数阶(递归实现)的操作数量 = #{count}"
|
||||
|
||||
count = linear_log_recur n
|
||||
puts "线性对数阶(递归实现)的操作数量 = #{count}"
|
||||
|
||||
count = factorial_recur n
|
||||
puts "阶乘阶(递归实现)的操作数量 = #{count}"
|
|
@ -0,0 +1,34 @@
|
|||
=begin
|
||||
File: worst_best_time_complexity.rb
|
||||
Created Time: 2024-03-30
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
### 生成一个数组,元素为: 1, 2, ..., n ,顺序被打乱 ###
|
||||
def random_number(n)
|
||||
# 生成数组 nums =: 1, 2, 3, ..., n
|
||||
nums = Array.new(n) { |i| i + 1 }
|
||||
# 随机打乱数组元素
|
||||
nums.shuffle!
|
||||
end
|
||||
|
||||
### 查找数组 nums 中数字 1 所在索引 ###
|
||||
def find_one(nums)
|
||||
for i in 0...nums.length
|
||||
# 当元素 1 在数组头部时,达到最佳时间复杂度 O(1)
|
||||
# 当元素 1 在数组尾部时,达到最差时间复杂度 O(n)
|
||||
return i if nums[i] == 1
|
||||
end
|
||||
|
||||
-1
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
|
||||
for i in 0...10
|
||||
n = 100
|
||||
nums = random_number n
|
||||
index = find_one nums
|
||||
puts "\n数组 [ 1, 2, ..., n ] 被打乱后 = #{nums}"
|
||||
puts "数字 1 的索引为 #{index}"
|
||||
end
|
|
@ -13,3 +13,46 @@ def print_linked_list(head)
|
|||
end
|
||||
puts "#{list.join(" -> ")}"
|
||||
end
|
||||
|
||||
class Trunk
|
||||
attr_accessor :prev, :str
|
||||
|
||||
def initialize(prev, str)
|
||||
@prev = prev
|
||||
@str = str
|
||||
end
|
||||
end
|
||||
|
||||
def show_trunk(p)
|
||||
return if p.nil?
|
||||
|
||||
show_trunk(p.prev)
|
||||
print p.str
|
||||
end
|
||||
|
||||
### 打印二叉树 ###
|
||||
# This tree printer is borrowed from TECHIE DELIGHT
|
||||
# https://www.techiedelight.com/c-program-print-binary-tree/
|
||||
def print_tree(root, prev=nil, is_right=false)
|
||||
return if root.nil?
|
||||
|
||||
prev_str = " "
|
||||
trunk = Trunk.new prev, prev_str
|
||||
print_tree root.right, trunk, true
|
||||
|
||||
if prev.nil?
|
||||
trunk.str = "———"
|
||||
elsif is_right
|
||||
trunk.str = "/———"
|
||||
prev_str = " |"
|
||||
else
|
||||
trunk.str = "\\———"
|
||||
prev.str = prev_str
|
||||
end
|
||||
|
||||
show_trunk trunk
|
||||
puts " #{root.val}"
|
||||
prev.str = prev_str if prev
|
||||
trunk.str = " |"
|
||||
print_tree root.left, trunk, false
|
||||
end
|
||||
|
|
18
codes/ruby/utils/tree_node.rb
Normal file
18
codes/ruby/utils/tree_node.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
=begin
|
||||
File: tree_node.rb
|
||||
Created Time: 2024-03-30
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
### 二叉树节点类 ###
|
||||
class TreeNode
|
||||
attr_accessor :val # 节点值
|
||||
attr_accessor :height # 节点高度
|
||||
attr_accessor :left # 左子节点引用
|
||||
attr_accessor :right # 右子节点引用
|
||||
|
||||
def initialize(val=0)
|
||||
@val = val
|
||||
@height = 0
|
||||
end
|
||||
end
|
|
@ -335,7 +335,30 @@
|
|||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
### 类 ###
|
||||
class Node
|
||||
attr_accessor :val # 节点值
|
||||
attr_accessor :next # 指向下一节点的引用
|
||||
|
||||
def initialize(x)
|
||||
@val = x
|
||||
end
|
||||
end
|
||||
|
||||
### 函数 ###
|
||||
def function
|
||||
# 执行某些操作...
|
||||
0
|
||||
end
|
||||
|
||||
### 算法 ###
|
||||
def algorithm(n) # 输入数据
|
||||
a = 0 # 暂存数据(常量)
|
||||
b = 0 # 暂存数据(变量)
|
||||
node = Node.new 0 # 暂存数据(对象)
|
||||
c = function # 栈帧空间(调用函数)
|
||||
a + b + c # 输出数据
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -499,7 +522,11 @@
|
|||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
|
||||
def algorithm(n)
|
||||
a = 0 # O(1)
|
||||
b = Array.new 10000 # O(1)
|
||||
nums = Array.new n if n > 10 # O(n)
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -763,7 +790,21 @@
|
|||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
def function
|
||||
# 执行某些操作
|
||||
0
|
||||
end
|
||||
|
||||
### 循环的空间复杂度为 O(1) ###
|
||||
def loop(n)
|
||||
(0...n).each { function }
|
||||
end
|
||||
|
||||
### 递归的空间复杂度为 O(n) ###
|
||||
def recur(n)
|
||||
return if n == 1
|
||||
recur n - 1
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
|
|
@ -189,7 +189,16 @@
|
|||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
|
||||
# 在某运行平台下
|
||||
def algorithm(n)
|
||||
a = 2 # 1 ns
|
||||
a = a + 1 # 1 ns
|
||||
a = a * 2 # 10 ns
|
||||
# 循环 n 次
|
||||
(n...0).each do # 1 ns
|
||||
puts 0 # 5 ns
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -474,7 +483,20 @@ $$
|
|||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
# 算法 A 的时间复杂度:常数阶
|
||||
def algorithm_A(n)
|
||||
puts 0
|
||||
end
|
||||
|
||||
# 算法 B 的时间复杂度:线性阶
|
||||
def algorithm_B(n)
|
||||
(0...n).each { puts 0 }
|
||||
end
|
||||
|
||||
# 算法 C 的时间复杂度:常数阶
|
||||
def algorithm_C(n)
|
||||
(0...1_000_000).each { puts 0 }
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -688,7 +710,15 @@ $$
|
|||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
|
||||
def algorithm(n)
|
||||
a = 1 # +1
|
||||
a = a + 1 # +1
|
||||
a = a * 2 # +1
|
||||
# 循环 n 次
|
||||
(0...n).each do # +1
|
||||
puts 0 # +1
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -970,7 +1000,16 @@ $T(n)$ 是一次函数,说明其运行时间的增长趋势是线性的,因
|
|||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
|
||||
def algorithm(n)
|
||||
a = 1 # +0(技巧 1)
|
||||
a = a + n # +0(技巧 1)
|
||||
# +n(技巧 2)
|
||||
(0...(5 * n + 1)).each do { puts 0 }
|
||||
# +n*n(技巧 3)
|
||||
(0...(2 * n)).each do
|
||||
(0...(n + 1)).each do { puts 0 }
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
|
Loading…
Reference in a new issue