スタックの元になる実際のデータを格納する配列と、スタックの最後に入れられたデータの位置を指すポインタを用意し、スタックにデータを追加するメソッド、スタックの最後にあるデータを読み出すメソッド、スタックからデータを削除するメソッドを用意すれば、スタックの基本部分は完成。
さらに、スタックが空だったり、満杯だったりするかどうかのチェック機能があればいい。
class SampleStack
def initialize( stackMaxSize )
@stackMaxSize = stackMaxSize
@stackTop = 0
@stack = Array.new(@stackMaxSize)
end
def push( val )
if (@stackTop == @stackMaxSize)
puts "もう一杯です!"
else
@stack[@stackTop] = val
@stackTop += 1
end
end
def pop()
if (@stackTop == 0)
puts "空っぽです!"
else
@stackTop -= 1
return @stack[@stackTop]
end
end
end
stack = SampleStack.new(5)
p stack.push(1)
p stack.push(2)
p stack.push(3)
p stack.push(4)
p stack.push(5)
p stack.push(6) # これは格納されない
p stack.pop
p stack.pop
p stack.pop
p stack.pop
p stack.pop
p stack.pop # これは取り出せない
●冨倉メモ
一応、こんな感じになるのでしょうけれど、そもそも Ruby では、Array クラスに push, pop メソッドが存在する上に、配列の大きさは動的に変更できるので、あまり意味はないかも。
#! /usr/bin/env ruby
# Usage : staple.rb [target_files]
# ----- 括弧のクラス ---------------------------------------------------
# Stapleクラスは自分の出現位置と対応する括弧のタイプを知っている
# また、前後関係も知っている
# ----------------------------------------------------------------------
class Staple
attr_reader :line, :column, :type, :next, :prev
def initialize( line, column, type )
@line = line # 出現行
@column = column # 出現場所
@type = type # 自身の括弧のタイプ
@next = nil # 次のノード
@prev = nil # 前のノード
end
# 対応する括弧のタイプ
def pare
case @type
when '('
str = ')'
when '{'
str = '}'
when '['
str = ']'
when ')'
str = '('
when '}'
str = '{'
when ']'
str = '['
end
return str
end
def setNext( target )
@next = target
end
def setPrev( target )
@prev = target
end
end
# ----- スタック -------------------------------------------------------
class StackByList
attr_reader :head, :last
def initialize
@head = nil
@last = nil
end
def push( line, column, type )
newStaple = Staple.new( line, column, type )
newStaple.setNext( nil )
# リストの最後に追加する
if @last != nil
@last.setNext( newStaple )
newStaple.setPrev( @last )
@last = newStaple
else
@head = @last = newStaple
newStaple.setPrev( nil )
end
end
def pop()
if @head == nil
return nil
break
end
ret = Staple.new( @last.line, @last.column, @last.type )
if last.prev == nil
@head = nil
else
@last.prev.setNext( nil )
end
@last = @last.prev
return ret
end
def getNode()
ret = Array.new
thisNode = @head
while thisNode != nil
ret.push(thisNode)
thisNode = thisNode.next
end
return ret
end
end
# ---------- 実行部分
START_PATTERN = /¥(|¥{|¥[/
END_PATTERN = /¥)|¥}|¥]/
line = 0
stack = StackByList.new # スタック
while string = ARGF.gets
column = 1
# 一文字ずつ読み込んで、括弧の開始であれば、スタックに追加。
# 括弧の終了であれば、スタックの最後と比較して一致していれば
# スタックから取り出し、不一致であれば、スタックに追加。
string.scan(/./).each do |char|
if char.match( START_PATTERN )
stack.push( line + 1, column, char )
column += 1
elsif char.match( END_PATTERN )
if stack.last != nil
if char == stack.last.pare
stack.pop
else
stack.push( line + 1, column, char )
end
else
stack.push( line + 1, column, char )
end
column += 1
end
end
line += 1
end
# 最終的にスタックに残っているものが括弧の対応が取れていない
stack.getNode.each do |e|
puts "#{e.line}行目の#{e.column}番目の #{e.type} が対応していません"
end
書籍ではリストとの組み合わせで実装されていますが、Ruby では、配列の大きさは動的に変更できるため、ここでは素直に書いてみます。
#! /usr/bin/env ruby
# Usage : staple.rb [target_files]
# ----- 括弧のクラス ---------------------------------------------------
# Stapleクラスは自分の出現位置と対応する括弧のタイプを知っている
# ----------------------------------------------------------------------
class Staple
attr_reader :line, :column, :type
def initialize( line, column, type )
@line = line # 出現行
@column = column # 出現場所
@type = type # 自身の括弧のタイプ
end
# 対応する括弧のタイプ
def pare
case @type
when '('
str = ')'
when '{'
str = '}'
when '['
str = ']'
when ')'
str = '('
when '}'
str = '{'
when ']'
str = '['
end
return str
end
end
# ---------- 実行部分
START_PATTERN = /¥(|¥{|¥[/
END_PATTERN = /¥)|¥}|¥]/
line = 0
stack = Array.new() # スタックを配列だけで書いてみる
while string = ARGF.gets
column = 1
# 一文字ずつ読み込んで、括弧の開始であれば、スタックに追加。
# 括弧の終了であれば、スタックの最後と比較して一致していれば
# スタックから取り出し、不一致であれば、スタックに追加。
string.scan(/./).each do |char|
if char.match( START_PATTERN )
staple = Staple.new( line + 1, column, char )
stack.push( staple )
column += 1
elsif char.match( END_PATTERN )
if stack.last != nil
if char == stack.last.pare
stack.pop
else
staple = Staple.new( line + 1, column, char )
stack.push( staple )
end
else
staple = Staple.new( line + 1, column, char )
stack.push( staple )
end
column += 1
end
end
line += 1
end
# 最終的にスタックに残っているものが括弧の対応が取れていない
stack.each do |e|
puts "#{e.line}行目の#{e.column}番目の #{e.type} が対応していません"
end
スタックが、最後に入れたものから取り出すのに対して、キューは、追加データは最後に入れ、取り出すときは最初に入れたものとなる。
ただし、これでは取り出した部分が空き状態になり、無題になるので、キューの末尾が配列の最後尾に達してしまった場合は配列の先頭に戻り、そこから再びデータを格納する「リングバッファ」という方法を取る。
実装としては、キューにデータを追加する機能、キューからデータを読み出す機能、キューからデータを削除する機能を作成することになる。
加えて、キューが空の状態、満杯の状態を判別できるようにすればいい。
class Queue
def initialize( size )
@size = size + 1
@queue = Array.new( @size )
@first = 0
@last = 0
end
def enqueue( val )
if (@last + 1) % @size == @first
puts "キューが満杯です"
else
@queue[@last] = val
@last = (@last + 1) % @size
end
end
def dequeue()
ret = nil
if @first == @last
return -1
else
ret = @queue[@first]
@first = (@first + 1) % @size
return ret
end
end
def printQueue
i = @first
while i != @last
print "#{@queue[i]} "
i = (i + 1) % @size
end
end
end
class Example
def main
q = Queue.new( 5 )
i = nil
while i != 0
puts "現在のキュー :"
q.printQueue
puts ""
puts "コマンド 0:終了 1:ジョブをためる 2:ジョブを実行"
i = gets.chomp.to_i
case i
when 1
puts "ジョブの識別番号(1〜1000)を適当に入力して下さい"
j = gets.chomp.to_i
if (j >= 1 && j <= 1000)
q.enqueue(j)
end
when 2
j = q.dequeue
if j == -1
puts "ジョブがないです"
else
puts "識別番号 : #{j} のジョブを実行中……"
end
end
end
end
end
ex = Example.new
ex.main