Go でキューの実装は、上記事で append を使って簡単にしています。なるほどと思いました。
ふつうはこれで充分ですよね。スタックは2本のキューで実装できるので、これも簡単です。しかし、任意の型を入れられるキュー、しかもメモリを効率よく使うキューがあれば便利かと思って、遊びで実装してみました。Go は3日前にさわり始めたばかりなので、おそらくはおかしなことをしていると思います。
queue.go
package main import "fmt" import "os" const QueueMax = 100 //キューのサイズ var qfield [QueueMax]interface{} //実際に使う配列の宣言 type Queue struct { out int in int length int field []interface{} } func (q *Queue) enqueue(obj interface{}) { if q.length == QueueMax { fmt.Println("Queue Overflow") os.Exit(1) } q.field[q.in] = obj q.in++ q.length++ if q.in == QueueMax {q.in = 0} } func (q *Queue) dequeue() (obj interface{}) { if q.length == 0 {return false} obj = q.field[q.out] q.out++ q.length-- if q.out == QueueMax {q.out = 0} return obj }
どんな型でも入れられるように、空のインターフェースを使っています。
実際に使ってみます。わかりやすいように、const QueueMax = 2
(長さ 2 の配列を使う)としています。
func main() { queue := &Queue{out: 0, in: 0, length: 0, field: qfield[:]} queue.enqueue(100) queue.enqueue("二百") fmt.Println(queue.field) //=>[100 二百] fmt.Println(queue.dequeue()) //=>100 fmt.Println(queue.field) //=>[100 二百] queue.enqueue(300) fmt.Println(queue.field) //=>[300 二百] fmt.Println(queue.dequeue()) //=>二百 queue.enqueue([1]int{400}) fmt.Println(queue.field) //=>[300 [400]] fmt.Println(queue.dequeue()) //=>300 fmt.Println(queue.dequeue()) //=>[400] fmt.Println(queue.dequeue()) //=>false fmt.Println(queue.dequeue()) //=>false }
どうでしょうか。いろんな型が入り混じっていると思います。長さ 2 の配列を使っているのに、途中で dequeue しているので 4 回 enqueue できていますね。まあ遊びですが。
なお、空のキューに dequeue すると、エラーではなくて false を返します。キューが溢れるとエラー終了します。
ちなみに、上記事と同じ人の書いたこれも、ハマりやすいことをわかりやすく教えてくれるなあと思いました。
これも構造体とポインタの話でわかりやすかった。
※追記
pop() と shift() も加えて、両端キューにしてみました。
func (q *Queue) pop() (obj interface{}) { if q.length == 0 {return false} q.in-- q.length-- if q.in == -1 {q.in = QueueMax - 1} obj = q.field[q.in] return obj } func (q *Queue) shift(obj interface{}) { if q.length == QueueMax { fmt.Println("Queue Overflow") os.Exit(1) } q.out-- q.length++ if q.out == -1 {q.out = QueueMax - 1} q.field[q.out] = obj }
メソッドの名前は言語によっていろいろです。上で enqueue() というのは push() がふつうですかね。shift() ってのはどうなのか知りませんが、僕は Ruby から採りました。
しかし、こうなると out, in ではなくて head, tail とでもしておけばよかったかな。
ここまでとりあえず、図書館から借りてきた下の本と Google 先生だけでやっています。まだゴルーチンとかわからない…。
- 作者: 古川昇
- 出版社/メーカー: シーアンドアール研究所
- 発売日: 2015/07/17
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
でも素人が3日でこの程度は書けるようになるから、やはり簡単なのかなあ…。