From e0df3df127bef09890d832b7fbabe02b3075e6af Mon Sep 17 00:00:00 2001 From: Andrew Gillis Date: Sat, 28 Apr 2018 20:16:21 -0400 Subject: [PATCH] Add Insert and Remove. No negative indexing. --- deque.go | 98 +++++++++++++++++++++++++++++---- deque_test.go | 146 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 185 insertions(+), 59 deletions(-) diff --git a/deque.go b/deque.go index fb61e38..1f8fdeb 100644 --- a/deque.go +++ b/deque.go @@ -123,23 +123,99 @@ func (q *Deque) Back() interface{} { return q.buf[(q.tail-1)&(len(q.buf)-1)] } -// PeekAt returns the element at index i in the queue. This method accepts -// both positive and negative index values. PeekAt(0) refers to the first -// (earliest added) element and is the same as Front(). PeekAt(-1) refers to -// the last (latest added) element and is the same as Back(). If the index -// is invalid, the call panics. -func (q *Deque) PeekAt(i int) interface{} { - // If indexing backwards, convert to positive index. - if i < 0 { - i += q.count - } +// Peek returns the element at index i in the queue. This method accepts only +// non-negative index values. Peek(0) refers to the first element and is the +// same as Front(). q.Peek(Len()-1) refers to the last element and is the same +// as Back(). If the index is invalid, the call panics. +func (q *Deque) Peek(i int) interface{} { if i < 0 || i >= q.count { - panic("deque: PeekAt() called with index out of range") + panic("deque: Peek() called with index out of range") } // bitwise modulus return q.buf[(q.head+i)&(len(q.buf)-1)] } +// Insert is used to insert an element into the queue at a location other than +// one of the ends. Insert(0,e) is the same as PushFront(e) and +// Insert(Len(),e) is the same as PushBack(e). Accepts only non-negative index +// values, and panics if index is out of range. +func (q *Deque) Insert(i int, elem interface{}) { + if i < 0 || i > q.count { + panic("deque: Insert() called with index out of range") + } + if i == 0 { + q.PushFront(elem) + return + } + if i == q.count { + q.PushBack(elem) + return + } + if i <= q.count/2 { + // If inserting closer to front, rotate front to back i places, put + // element at front, then rotate back to front i places. + for j := 0; j < i; j++ { + q.PushBack(q.PopFront()) + } + q.PushFront(elem) + for j := 0; j < i; j++ { + q.PushFront(q.PopBack()) + } + } else { + // If inserting closer to back, rotate back to font Len() - i places, + // put element at back, then rotate front to back same amount. + rots := q.count - i + for j := 0; j < rots; j++ { + q.PushFront(q.PopBack()) + } + q.PushBack(elem) + for j := 0; j < rots; j++ { + q.PushBack(q.PopFront()) + } + } +} + +// Remove removes and returns an element from the queue, from a location other +// than one of the ends. Remove(0) is the same as PopFront() and +// Remove(Len()-1) is the same as PopBack(). Accepts only non-negative index +// values, and panics if index is out of range. +func (q *Deque) Remove(i int) interface{} { + if i < 0 || i >= q.count { + panic("deque: Remove() called with index out of range") + } + if i == 0 { + return q.PopFront() + } + if i == q.count-1 { + return q.PopBack() + } + var elem interface{} + if i <= q.count/2 { + // If removing closer to front, rotate front to back i places, remove + // element at front, then rotate back to front i places. + for j := 0; j < i; j++ { + q.PushBack(q.PopFront()) + } + elem = q.PopFront() + for j := 0; j < i; j++ { + q.PushFront(q.PopBack()) + } + } else { + // If removing closer to back, rotate back to font Len() - 1 - i + // places, remove element at back, then rotate front to back same + // amount. + rots := (q.count - 1) - i + for j := 0; j < rots; j++ { + q.PushFront(q.PopBack()) + } + elem = q.PopBack() + for j := 0; j < rots; j++ { + q.PushBack(q.PopFront()) + } + } + return elem +} + // Clear removes all elements from the queue, but retains the current capacity. // The queue will not be resized smaller as long as items are only added. // Only when items are removed is the queue subject to getting resized smaller. diff --git a/deque_test.go b/deque_test.go index 83216cc..b2f9a4f 100644 --- a/deque_test.go +++ b/deque_test.go @@ -52,8 +52,8 @@ func TestGrowShrink(t *testing.T) { } // Check that all values are as expected. for i := 0; i < minCapacity*2; i++ { - if q.PeekAt(i) != i { - t.Errorf("q.PeekAt(%d) = %d, expected %d", i, q.PeekAt(i), i) + if q.Peek(i) != i { + t.Errorf("q.Peek(%d) = %d, expected %d", i, q.Peek(i), i) } } bufLen := len(q.buf) @@ -102,8 +102,8 @@ func TestGrowShrink(t *testing.T) { } } -func TestDequeSimple(t *testing.T) { - q := new(Deque) +func TestSimple(t *testing.T) { + var q Deque for i := 0; i < minCapacity; i++ { q.PushBack(i) @@ -130,8 +130,8 @@ func TestDequeSimple(t *testing.T) { } } -func TestDequeWrap(t *testing.T) { - q := new(Deque) +func TestBufferWrap(t *testing.T) { + var q Deque for i := 0; i < minCapacity; i++ { q.PushBack(i) @@ -150,8 +150,8 @@ func TestDequeWrap(t *testing.T) { } } -func TestDequeWrapReverse(t *testing.T) { - q := new(Deque) +func TestBufferWrapReverse(t *testing.T) { + var q Deque for i := 0; i < minCapacity; i++ { q.PushFront(i) @@ -169,8 +169,8 @@ func TestDequeWrapReverse(t *testing.T) { } } -func TestDequeLen(t *testing.T) { - q := new(Deque) +func TestLen(t *testing.T) { + var q Deque if q.Len() != 0 { t.Error("empty queue length not 0") @@ -190,34 +190,30 @@ func TestDequeLen(t *testing.T) { } } -func TestDequePeekAt(t *testing.T) { - q := new(Deque) +func TestPeek(t *testing.T) { + var q Deque for i := 0; i < 1000; i++ { q.PushBack(i) - for j := 0; j < q.Len(); j++ { - if q.PeekAt(j).(int) != j { - t.Errorf("index %d doesn't contain %d", j, j) - } + } + + // Front to back. + for j := 0; j < q.Len(); j++ { + if q.Peek(j).(int) != j { + t.Errorf("index %d doesn't contain %d", j, j) + } + } + + // Back to front + for j := 1; j <= q.Len(); j++ { + if q.Peek(q.Len()-j).(int) != q.Len()-j { + t.Errorf("index %d doesn't contain %d", q.Len()-j, q.Len()-j) } } } -func TestDequePeekAtNegative(t *testing.T) { - q := new(Deque) - - for i := 0; i < 1000; i++ { - q.PushBack(i) - for j := 1; j <= q.Len(); j++ { - if q.PeekAt(-j).(int) != q.Len()-j { - t.Errorf("index %d doesn't contain %d", -j, q.Len()-j) - } - } - } -} - -func TestDequeBack(t *testing.T) { - q := new(Deque) +func TestBack(t *testing.T) { + var q Deque for i := 0; i < minCapacity+5; i++ { q.PushBack(i) @@ -228,7 +224,7 @@ func TestDequeBack(t *testing.T) { } func TestCopy(t *testing.T) { - q := new(Deque) + var q Deque a := make([]interface{}, minCapacity) if q.Copy(a) != 0 { t.Error("Copied wrong size, expected 0") @@ -265,7 +261,7 @@ func TestCopy(t *testing.T) { } func TestRotate(t *testing.T) { - q := new(Deque) + var q Deque for i := 0; i < 10; i++ { q.PushBack(i) } @@ -300,8 +296,8 @@ func TestRotate(t *testing.T) { } } -func TestDequeClear(t *testing.T) { - q := new(Deque) +func TestClear(t *testing.T) { + var q Deque for i := 0; i < 100; i++ { q.PushBack(i) @@ -327,25 +323,79 @@ func TestDequeClear(t *testing.T) { } } -func TestPeekAtOutOfRangePanics(t *testing.T) { - q := new(Deque) +func TestInsert(t *testing.T) { + var q Deque + q.PushBack("A") + q.PushBack("B") + q.PushBack("C") + q.PushBack("D") + q.PushBack("E") + q.PushBack("F") + q.PushBack("G") + + q.Insert(4, "x") + if q.Peek(4) != "x" { + t.Error("expected x at position 4") + } + + q.Insert(2, "y") + if q.Peek(2) != "y" { + t.Error("expected y at position 2") + } + + if q.Peek(5) != "x" { + t.Error("expected x at position 5") + } +} + +func TestRemove(t *testing.T) { + var q Deque + q.PushBack("A") + q.PushBack("B") + q.PushBack("C") + q.PushBack("D") + q.PushBack("E") + q.PushBack("F") + q.PushBack("G") + + if q.Remove(4) != "E" { + t.Error("expected E from position 4") + } + if q.Peek(4) != "F" { + t.Error("expected F at position 4") + } + + if q.Remove(2) != "C" { + t.Error("expected C at position 2") + } + if q.Peek(2) != "D" { + t.Error("expected D at position 4") + } + + if q.Peek(4) != "G" { + t.Error("expected G at position 4") + } +} + +func TestPeekOutOfRangePanics(t *testing.T) { + var q Deque q.PushBack(1) q.PushBack(2) q.PushBack(3) assertPanics(t, "should panic when negative index", func() { - q.PeekAt(-4) + q.Peek(-4) }) assertPanics(t, "should panic when index greater than length", func() { - q.PeekAt(4) + q.Peek(4) }) } func TestFrontBackOutOfRangePanics(t *testing.T) { const msg = "should panic when peeking empty queue" - q := new(Deque) + var q Deque assertPanics(t, msg, func() { q.Front() }) @@ -365,7 +415,7 @@ func TestFrontBackOutOfRangePanics(t *testing.T) { } func TestPopFrontOutOfRangePanics(t *testing.T) { - q := new(Deque) + var q Deque assertPanics(t, "should panic when removing empty queue", func() { q.PopFront() @@ -380,7 +430,7 @@ func TestPopFrontOutOfRangePanics(t *testing.T) { } func TestPopBackOutOfRangePanics(t *testing.T) { - q := new(Deque) + var q Deque assertPanics(t, "should panic when removing empty queue", func() { q.PopBack() @@ -456,7 +506,7 @@ func BenchmarkSerialReverse(b *testing.B) { } func BenchmarkRotate(b *testing.B) { - q := new(Deque) + var q Deque for i := 0; i < size; i++ { q.PushBack(i) } @@ -470,7 +520,7 @@ func BenchmarkRotate(b *testing.B) { } func BenchmarkRotateReverse(b *testing.B) { - q := new(Deque) + var q Deque for i := 0; i < size; i++ { q.PushBack(i) } @@ -483,21 +533,21 @@ func BenchmarkRotateReverse(b *testing.B) { } } -func BenchmarkDequePeekAt(b *testing.B) { - q := new(Deque) +func BenchmarkDequePeek(b *testing.B) { + var q Deque for i := 0; i < size; i++ { q.PushBack(i) } b.ResetTimer() for i := 0; i < b.N; i++ { for j := 0; j < size; j++ { - q.PeekAt(j) + q.Peek(j) } } } func BenchmarkDequePushPop(b *testing.B) { - q := new(Deque) + var q Deque for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { q.PushBack(nil)