Add Insert and Remove. No negative indexing.

This commit is contained in:
Andrew Gillis 2018-04-28 20:16:21 -04:00
parent 61131f5ce5
commit e0df3df127
2 changed files with 185 additions and 59 deletions

View file

@ -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.

View file

@ -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)