diff --git a/codes/ruby/chapter_stack_and_queue/array_deque.rb b/codes/ruby/chapter_stack_and_queue/array_deque.rb new file mode 100644 index 000000000..ba4b78058 --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/array_deque.rb @@ -0,0 +1,144 @@ +=begin +File: array_deque.rb +Created Time: 2024-04-05 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### 基于环形数组实现的双向队列 ### +class ArrayDeque + ### 获取双向队列的长度 ### + attr_reader :size + + ### 构造方法 ### + def initialize(capacity) + @nums = Array.new(capacity, 0) + @front = 0 + @size = 0 + end + + ### 获取双向队列的容量 ### + def capacity + @nums.length + end + + ### 判断双向队列是否为空 ### + def is_empty? + size.zero? + end + + ### 队首入队 ### + def push_first(num) + if size == capacity + puts '双向队列已满' + return + end + + # 队首指针向左移动一位 + # 通过取余操作实现 front 越过数组头部后回到尾部 + @front = index(@front - 1) + # 将 num 添加至队首 + @nums[@front] = num + @size += 1 + end + + ### 队尾入队 ### + def push_last(num) + if size == capacity + puts '双向队列已满' + return + end + + # 计算队尾指针,指向队尾索引 + 1 + rear = index(@front + size) + # 将 num 添加至队尾 + @nums[rear] = num + @size += 1 + end + + ### 队首出队 ### + def pop_first + num = peek_first + # 队首指针向后移动一位 + @front = index(@front + 1) + @size -= 1 + num + end + + ### 队尾出队 ### + def pop_last + num = peek_last + @size -= 1 + num + end + + ### 访问队首元素 ### + def peek_first + raise IndexError, '双向队列为空' if is_empty? + + @nums[@front] + end + + ### 访问队尾元素 ### + def peek_last + raise IndexError, '双向队列为空' if is_empty? + + # 计算尾元素索引 + last = index(@front + size - 1) + @nums[last] + end + + ### 返回数组用于打印 ### + def to_array + # 仅转换有效长度范围内的列表元素 + res = [] + for i in 0...size + res << @nums[index(@front + i)] + end + res + end + + private + + ### 计算环形数组索引 ### + def index(i) + # 通过取余操作实现数组首尾相连 + # 当 i 越过数组尾部后,回到头部 + # 当 i 越过数组头部后,回到尾部 + (i + capacity) % capacity + end +end + +### Driver Code ### + +# 初始化双向队列 +deque = ArrayDeque.new(10) +deque.push_last(3) +deque.push_last(2) +deque.push_last(5) +puts "双向队列 deque = #{deque.to_array}" + +# 访问元素 +peek_first = deque.peek_first +puts "队首元素 peek_first = #{peek_first}" +peek_last = deque.peek_last +puts "队尾元素 peek_last = #{peek_last}" + +# 元素入队 +deque.push_last(4) +puts "元素 4 队尾入队后 deque = #{deque.to_array}" +deque.push_first(1) +puts "元素 1 队尾入队后 deque = #{deque.to_array}" + +# 元素出队 +pop_last = deque.pop_last +puts "队尾出队元素 = #{pop_last},队尾出队后 deque = #{deque.to_array}" +pop_first = deque.pop_first +puts "队尾出队元素 = #{pop_first},队尾出队后 deque = #{deque.to_array}" + +# 获取双向队列的长度 +size = deque.size +puts "双向队列长度 size = #{size}" + +# 判断双向队列是否为空 +is_empty = deque.is_empty? +puts "双向队列是否为空 = #{is_empty}" diff --git a/codes/ruby/chapter_stack_and_queue/array_queue.rb b/codes/ruby/chapter_stack_and_queue/array_queue.rb new file mode 100644 index 000000000..28ec1f010 --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/array_queue.rb @@ -0,0 +1,106 @@ +=begin +File: array_queue.rb +Created Time: 2024-04-05 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### 基于环形数组实现的队列 ### +class ArrayQueue + ### 获取队列的长度 ### + attr_reader :size + + ### 构造方法 ### + def initialize(size) + @nums = Array.new(size, 0) # 用于存储队列元素的数组 + @front = 0 # 队首指针,指向队首元素 + @size = 0 # 队列长度 + end + + ### 获取队列的容量 ### + def capacity + @nums.length + end + + ### 判断队列是否为空 ### + def is_empty? + size.zero? + end + + ### 入队 ### + def push(num) + raise IndexError, '队列已满' if size == capacity + + # 计算队尾指针,指向队尾索引 + 1 + # 通过取余操作实现 rear 越过数组尾部后回到头部 + rear = (@front + size) % capacity + # 将 num 添加至队尾 + @nums[rear] = num + @size += 1 + end + + ### 出队 ### + def pop + num = peek + # 队首指针向后移动一位,若越过尾部,则返回到数组头部 + @front = (@front + 1) % capacity + @size -= 1 + num + end + + ### 访问队首元素 ### + def peek + raise IndexError, '队列为空' if is_empty? + + @nums[@front] + end + + ### 返回列表用于打印 ### + def to_array + res = Array.new(size, 0) + j = @front + + for i in 0...size + res[i] = @nums[j % capacity] + j += 1 + end + + res + end +end + +### Driver Code ### + +# 初始化队列 +queue = ArrayQueue.new(10) + +# 元素入队 +queue.push(1) +queue.push(3) +queue.push(2) +queue.push(5) +queue.push(4) +puts "队列 queue = #{queue.to_array}" + +# 访问队首元素 +peek = queue.peek +puts "队首元素 peek = #{peek}" + +# 元素出队 +pop = queue.pop +puts "出队元素 pop = #{pop}" +puts "出队后 queue = #{queue.to_array}" + +# 获取队列的长度 +size = queue.size +puts "队列长度 size = #{size}" + +# 判断队列是否为空 +is_empty = queue.is_empty? +puts "队列是否为空 = #{is_empty}" + +# 测试环形数组 +for i in 0...10 + queue.push(i) + queue.pop + puts "第 #{i} 轮入队 + 出队后 queue = #{queue.to_array}" +end diff --git a/codes/ruby/chapter_stack_and_queue/array_stack.rb b/codes/ruby/chapter_stack_and_queue/array_stack.rb new file mode 100644 index 000000000..b580626ac --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/array_stack.rb @@ -0,0 +1,77 @@ +=begin +File: array_stack.rb +Created Time: 2024-04-06 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### 基于数组实现的栈 ### +class ArrayStack + ### 构造方法 ### + def initialize + @stack = [] + end + + ### 获取栈的长度 ### + def size + @stack.length + end + + ### 判断栈是否为空 ### + def is_empty? + @stack.empty? + end + + ### 入栈 ### + def push(item) + @stack << item + end + + ### 出栈 ### + def pop + raise IndexError, '栈为空' if is_empty? + + @stack.pop + end + + ### 访问栈顶元素 ### + def peek + raise IndexError, '栈为空' if is_empty? + + @stack.last + end + + ### 返回列表用于打印 ### + def to_array + @stack + end +end + +### Driver Code ### + +# 初始化栈 +stack = ArrayStack.new + +# 元素入栈 +stack.push(1) +stack.push(3) +stack.push(2) +stack.push(5) +stack.push(4) +puts "栈 stack = #{stack.to_array}" + +# 访问栈顶元素 +peek = stack.peek +puts "栈顶元素 peek = #{peek}" + +# 元素出栈 +pop = stack.pop +puts "出栈元素 pop = #{pop}" +puts "出栈后 stack = #{stack.to_array}" + +# 获取栈的长度 +size = stack.size +puts "栈的长度 size = #{size}" + +# 判断是否为空 +is_empty = stack.is_empty? +puts "栈是否为空 = #{is_empty}" diff --git a/codes/ruby/chapter_stack_and_queue/deque.rb b/codes/ruby/chapter_stack_and_queue/deque.rb new file mode 100644 index 000000000..cef705e03 --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/deque.rb @@ -0,0 +1,41 @@ +=begin +File: deque.rb +Created Time: 2024-04-06 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### Driver Code ### + +# 初始化双向队列 +# Ruby 没有内直的双端队列,只能把 Array 当作双端队列来使用 +deque = [] + +# 元素如队 +deque << 2 +deque << 5 +deque << 4 +# 请注意,由于是数组,Array#unshift 方法的时间复杂度为 O(n) +deque.unshift(3) +deque.unshift(1) +puts "双向队列 deque = #{deque}" + +# 访问元素 +peek_first = deque.first +puts "队首元素 peek_first = #{peek_first}" +peek_last = deque.last +puts "队尾元素 peek_last = #{peek_last}" + +# 元素出队 +# 请注意,由于是数组, Array#shift 方法的时间复杂度为 O(n) +pop_front = deque.shift +puts "队首出队元素 pop_front = #{pop_front},队首出队后 deque = #{deque}" +pop_back = deque.pop +puts "队尾出队元素 pop_back = #{pop_back}, 队尾出队后 deque = #{deque}" + +# 获取双向队列的长度 +size = deque.length +puts "双向队列长度 size = #{size}" + +# 判断双向队列是否为空 +is_empty = size.zero? +puts "双向队列是否为空 = #{is_empty}" diff --git a/codes/ruby/chapter_stack_and_queue/linkedlist_deque.rb b/codes/ruby/chapter_stack_and_queue/linkedlist_deque.rb new file mode 100644 index 000000000..0a9ae2e59 --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/linkedlist_deque.rb @@ -0,0 +1,167 @@ +=begin +File: linkedlist_deque.rb +Created Time: 2024-04-06 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### 双向链表节点 +class ListNode + attr_accessor :val + attr_accessor :next # 后继节点引用 + attr_accessor :prev # 前躯节点引用 + + ### 构造方法 ### + def initialize(val) + @val = val + end +end + +### 基于双向链表实现的双向队列 ### +class LinkedListDeque + ### 获取双向队列的长度 ### + attr_reader :size + + ### 构造方法 ### + def initialize + @front = nil # 头节点 front + @rear = nil # 尾节点 rear + @size = 0 # 双向队列的长度 + end + + ### 判断双向队列是否为空 ### + def is_empty? + size.zero? + end + + ### 入队操作 ### + def push(num, is_front) + node = ListNode.new(num) + # 若链表为空, 则令 front 和 rear 都指向 node + if is_empty? + @front = @rear = node + # 队首入队操作 + elsif is_front + # 将 node 添加至链表头部 + @front.prev = node + node.next = @front + @front = node # 更新头节点 + # 队尾入队操作 + else + # 将 node 添加至链表尾部 + @rear.next = node + node.prev = @rear + @rear = node # 更新尾节点 + end + @size += 1 # 更新队列长度 + end + + ### 队首入队 ### + def push_first(num) + push(num, true) + end + + ### 队尾入队 ### + def push_last(num) + push(num, false) + end + + ### 出队操作 ### + def pop(is_front) + raise IndexError, '双向队列为空' if is_empty? + + # 队首出队操作 + if is_front + val = @front.val # 暂存头节点值 + # 删除头节点 + fnext = @front.next + unless fnext.nil? + fnext.prev = nil + @front.next = nil + end + @front = fnext # 更新头节点 + # 队尾出队操作 + else + val = @rear.val # 暂存尾节点值 + # 删除尾节点 + rprev = @rear.prev + unless rprev.nil? + rprev.next = nil + @rear.prev = nil + end + @rear = rprev # 更新尾节点 + end + @size -= 1 # 更新队列长度 + + val + end + + ### 队首出队 ### + def pop_first + pop(true) + end + + ### 队首出队 ### + def pop_last + pop(false) + end + + ### 访问队首元素 ### + def peek_first + raise IndexError, '双向队列为空' if is_empty? + + @front.val + end + + ### 访问队尾元素 ### + def peek_last + raise IndexError, '双向队列为空' if is_empty? + + @rear.val + end + + ### 返回数组用于打印 ### + def to_array + node = @front + res = Array.new(size, 0) + for i in 0...size + res[i] = node.val + node = node.next + end + res + end +end + +### Driver Code ### + +# 初始化双向队列 +deque = LinkedListDeque.new +deque.push_last(3) +deque.push_last(2) +deque.push_last(5) +puts "双向队列 deque = #{deque.to_array}" + +# 访问元素 +peek_first = deque.peek_first +puts "队首元素 peek_first = #{peek_first}" +peek_last = deque.peek_last +puts "队首元素 peek_last = #{peek_last}" + +# 元素入队 +deque.push_last(4) +puts "元素 4 队尾入队后 deque = #{deque.to_array}" +deque.push_first(1) +puts "元素 1 队首入队后 deque = #{deque.to_array}" + +# 元素出队 +pop_last = deque.pop_last +puts "队尾出队元素 = #{pop_last}, 队尾出队后 deque = #{deque.to_array}" +pop_first = deque.pop_first +puts "队首出队元素 = #{pop_first},队首出队后 deque = #{deque.to_array}" + +# 获取双向队列的长度 +size = deque.size +puts "双向队列长度 size = #{size}" + +# 判断双向队列是否为空 +is_empty = deque.is_empty? +puts "双向队列是否为空 = #{is_empty}" diff --git a/codes/ruby/chapter_stack_and_queue/linkedlist_queue.rb b/codes/ruby/chapter_stack_and_queue/linkedlist_queue.rb new file mode 100644 index 000000000..a21e94ab2 --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/linkedlist_queue.rb @@ -0,0 +1,100 @@ +=begin +File: linkedlist_queue.rb +Created Time: 2024-04-06 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +require_relative '../utils/list_node' + +### 基于链表头现的队列 ### +class LinkedListQueue + ### 获取队列的长度 ### + attr_reader :size + + ### 构造方法 ### + def initialize + @front = nil # 头节点 front + @rear = nil # 尾节点 rear + @size = 0 + end + + ### 判断队列是否为空 ### + def is_empty? + @front.nil? + end + + ### 入队 ### + def push(num) + # 在尾节点后添加 num + node = ListNode.new(num) + + # 如果队列为空,则令头,尾节点都指向该节点 + if @front.nil? + @front = node + @rear = node + # 如果队列不为空,则令该节点添加到尾节点后 + else + @rear.next = node + @rear = node + end + + @size += 1 + end + + ### 出队 ### + def pop + num = peek + # 删除头节点 + @front = @front.next + @size -= 1 + num + end + + ### 访问队首元素 ### + def peek + raise IndexError, '队列为空' if is_empty? + + @front.val + end + + ### 将链表为 Array 并返回 ### + def to_array + queue = [] + temp = @front + while temp + queue << temp.val + temp = temp.next + end + queue + end +end + +### Driver Code ### + +# 初始化队列 +queue = LinkedListQueue.new + +# 元素如队 +queue.push(1) +queue.push(3) +queue.push(2) +queue.push(5) +queue.push(4) +puts "队列 queue = #{queue.to_array}" + +# 访问队首元素 +peek = queue.peek +puts "队首元素 front = #{peek}" + +# 元素出队 +pop_front = queue.pop +puts "出队元素 pop = #{pop_front}" +puts "出队后 queue = #{queue.to_array}" + +# 获取队列的长度 +size = queue.size +puts "队列长度 size = #{size}" + +# 判断队列是否为空 +is_empty = queue.is_empty? +puts "队列是否为空 = #{is_empty}" diff --git a/codes/ruby/chapter_stack_and_queue/linkedlist_stack.rb b/codes/ruby/chapter_stack_and_queue/linkedlist_stack.rb new file mode 100644 index 000000000..36a04792e --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/linkedlist_stack.rb @@ -0,0 +1,86 @@ +=begin +File: linkedlist_stack.rb +Created Time: 2024-04-06 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +require_relative '../utils/list_node' + +### 基于链表实现的栈 ### +class LinkedListStack + attr_reader :size + + ### 构造方法 ### + def initialize + @size = 0 + end + + ### 判断栈是否为空 ### + def is_empty? + @peek.nil? + end + + ### 入栈 ### + def push(val) + node = ListNode.new(val) + node.next = @peek + @peek = node + @size += 1 + end + + ### 出栈 ### + def pop + num = peek + @peek = @peek.next + @size -= 1 + num + end + + ### 访问栈顶元素 ### + def peek + raise IndexError, '栈为空' if is_empty? + + @peek.val + end + + ### 将链表转化为 Array 并反回 ### + def to_array + arr = [] + node = @peek + while node + arr << node.val + node = node.next + end + arr.reverse + end +end + +### Driver Code ### + +# 初始化栈 +stack = LinkedListStack.new + +# 元素入栈 +stack.push(1) +stack.push(3) +stack.push(2) +stack.push(5) +stack.push(4) +puts "栈 stack = #{stack.to_array}" + +# 访问栈顶元素 +peek = stack.peek +puts "栈顶元素 peek = #{peek}" + +# 元素出栈 +pop = stack.pop +puts "出栈元素 pop = #{pop}" +puts "出栈后 stack = #{stack.to_array}" + +# 获取栈的长度 +size = stack.size +puts "栈的长度 size = #{size}" + +# 判断是否为空 +is_empty = stack.is_empty? +puts "栈是否为空 = #{is_empty}" diff --git a/codes/ruby/chapter_stack_and_queue/queue.rb b/codes/ruby/chapter_stack_and_queue/queue.rb new file mode 100644 index 000000000..cda1983a7 --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/queue.rb @@ -0,0 +1,37 @@ +=begin +File: queue.rb +Created Time: 2024-04-06 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### Driver Code ### + +# 初始化队列 +# Ruby 内置的队列(Thread::Queue) 没有 peek 和遍历方法,可以把 Array 当作队列来使用 +queue = [] + +# 元素入队 +queue.push(1) +queue.push(3) +queue.push(2) +queue.push(5) +queue.push(4) +puts "队列 queue = #{queue}" + +# 访问队列元素 +peek = queue.first +puts "队首元素 peek = #{peek}" + +# 元素出队 +# 清注意,由于是数组,Array#shift 方法时间复杂度为 O(n) +pop = queue.shift +puts "出队元素 pop = #{pop}" +puts "出队后 queue = #{queue}" + +# 获取队列的长度 +size = queue.length +puts "队列长度 size = #{size}" + +# 判断队列是否为空 +is_empty = queue.empty? +puts "队列是否为空 = #{is_empty}" diff --git a/codes/ruby/chapter_stack_and_queue/stack.rb b/codes/ruby/chapter_stack_and_queue/stack.rb new file mode 100644 index 000000000..333ecf1d1 --- /dev/null +++ b/codes/ruby/chapter_stack_and_queue/stack.rb @@ -0,0 +1,36 @@ +=begin +File: stack.rb +Created Time: 2024-04-06 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### Driver Code ### + +# 初始化栈 +# Ruby 没有内置的栈类,可以把 Array 当作栈来使用 +stack = [] + +# 元素入栈 +stack << 1 +stack << 3 +stack << 2 +stack << 5 +stack << 4 +puts "栈 stack = #{stack}" + +# 访问栈顶元素 +peek = stack.last +puts "栈顶元素 peek = #{peek}" + +# 元素出栈 +pop = stack.pop +puts "出栈元素 pop = #{pop}" +puts "出栈后 stack = #{stack}" + +# 获取栈的长度 +size = stack.length +puts "栈的长度 size = #{size}" + +# 判断是否为空 +is_empty = stack.empty? +puts "栈是否为空 = #{is_empty}"