Skip to content

Commit

Permalink
Merge pull request #6 from krlv/stack_of_plates
Browse files Browse the repository at this point in the history
3.3 Stack of Plates
  • Loading branch information
krlv authored Apr 26, 2021
2 parents bca73c6 + 1232640 commit b62df59
Show file tree
Hide file tree
Showing 5 changed files with 640 additions and 7 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ Solving programming questions from ["Cracking the Coding Interview 6th Edition"]

[Queue implementation][37] (with Linked List as a storage); [tests][38]

[Fixed (capped) Stack implementation][39] (with Linked List as a storage); [tests][40]

| # | Problem | Tested | Solved |
|---|-------------------------------|:-------------:|:---------:|
|3.1| [Three in one][39] | [tests][40] ||
|3.2| [Stack Min][41] | [tests][42] ||
|3.3| Stack of Plates | tests | |
|3.1| [Three in one][41] | [tests][42] ||
|3.2| [Stack Min][43] | [tests][44] ||
|3.3| [Stack of Plates][45] | [tests][46] | |
|3.4| Queue via Stacks | tests | |
|3.5| Sort Stack | tests | |
|3.6| Animal Shelter | tests | |
Expand Down Expand Up @@ -83,7 +84,11 @@ Solving programming questions from ["Cracking the Coding Interview 6th Edition"]
[36]: ch03/stack_test.go
[37]: ch03/queue.go
[38]: ch03/queue_test.go
[39]: ch03/01_three_in_one.go
[40]: ch03/01_three_in_one_test.go
[41]: ch03/02_stack_min.go
[42]: ch03/02_stack_min_test.go
[39]: ch03/fixed_stack.go
[40]: ch03/fixed_stack_test.go
[41]: ch03/01_three_in_one.go
[42]: ch03/01_three_in_one_test.go
[43]: ch03/02_stack_min.go
[44]: ch03/02_stack_min_test.go
[45]: ch03/03_stack_of_plates.go
[46]: ch03/03_stack_of_plates_test.go
72 changes: 72 additions & 0 deletions ch03/03_stack_of_plates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package ch03

import (
"errors"
)

// StackSet represents set of fixed (capped) stacks
type StackSet struct {
stacks []*FixedStack
}

// Pop returns (and removes) the top item from the top stack
// If the top stack is empty, it will be removed from the set
func (set *StackSet) Pop() (int, error) {
stack, err := set.topStack()
if err != nil {
return 0, err
}

value, err := stack.Pop()
if err != nil {
return 0, err
}

if stack.IsEmpty() {
set.removeStack()
}

return value, nil
}

// Push add an item to the top stack
// If the top stack is full, new stack will be created
// and appended to the set
func (set *StackSet) Push(data int) error {
stack, err := set.topStack()
if err != nil {
stack = set.appendStack()
}

if stack.IsFull() {
stack = set.appendStack()
}

return stack.Push(data)
}

// TopStack returns the top stack from the set
func (set *StackSet) topStack() (*FixedStack, error) {
n := len(set.stacks) - 1
if n < 0 {
return nil, errors.New("set is empty")
}

return set.stacks[n], nil
}

// AppendStack adds a new stack to the set
func (set *StackSet) appendStack() *FixedStack {
stack := NewFixedStack(3)
set.stacks = append(set.stacks, stack)

return stack
}

// RemoveStack removes top stack from the set
func (set *StackSet) removeStack() {
n := len(set.stacks) - 1
if n >= 0 {
set.stacks = set.stacks[:n]
}
}
233 changes: 233 additions & 0 deletions ch03/03_stack_of_plates_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
package ch03

import (
"reflect"
"testing"
)

func TestStackSet_Pop(t *testing.T) {
stack1 := NewFixedStack(2)
stack1.Push(1)
stack1.Push(2)

stack2 := NewFixedStack(2)
stack2.Push(3)

type fields struct {
stacks []*FixedStack
}
type want struct {
pop int
len int
}
tests := []struct {
name string
fields fields
want want
wantErr bool
}{
{
name: "returns error if the set is empty",
fields: fields{stacks: []*FixedStack{}},
wantErr: true,
},
{
name: "returns error if the top stack is empty",
fields: fields{stacks: append([]*FixedStack{}, NewFixedStack(2))},
wantErr: true,
},
{
name: "returns the top value and removes empty stack from the set",
fields: fields{stacks: append([]*FixedStack{}, stack1, stack2)},
want: want{pop: 3, len: 1},
},
{
name: "returns the top value from the top stack in the set",
fields: fields{stacks: append([]*FixedStack{}, stack1)},
want: want{pop: 2, len: 1},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
set := &StackSet{
stacks: tt.fields.stacks,
}
got, err := set.Pop()
if (err != nil) != tt.wantErr {
t.Errorf("Pop() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err != nil {
return
}
if got != tt.want.pop {
t.Errorf("Pop() got = %v, want %v", got, tt.want.pop)
}
got = len(set.stacks)
if got != tt.want.len {
t.Errorf("Pop() len(set.stacks) = %v, want %v", got, tt.want.len)
}
})
}
}

func TestStackSet_Push(t *testing.T) {
stack1 := NewFixedStack(2)
stack1.Push(1)

stack2 := NewFixedStack(2)
stack2.Push(1)
stack2.Push(2)

type fields struct {
stacks []*FixedStack
}
type args struct {
data int
}
type want struct {
len int
}
tests := []struct {
name string
fields fields
args args
want want
wantErr bool
}{
{
name: "pushes a value to an empty SetStack",
fields: fields{stacks: []*FixedStack{}},
args: args{data: 1},
want: want{len: 1},
},
{
name: "pushes a value to non-full top stack",
fields: fields{stacks: append([]*FixedStack{}, stack1)},
args: args{data: 1},
want: want{len: 1},
},
{
name: "appends new stack to the set on Push() when top stack is full",
fields: fields{stacks: append([]*FixedStack{}, stack2)},
args: args{data: 1},
want: want{len: 2},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
set := &StackSet{
stacks: tt.fields.stacks,
}
if err := set.Push(tt.args.data); (err != nil) != tt.wantErr {
t.Errorf("Push() error = %v, wantErr %v", err, tt.wantErr)
}
got := len(set.stacks)
if got != tt.want.len {
t.Errorf("Pop() len(set.stacks) = %v, want %v", got, tt.want.len)
}
})
}
}

func TestStackSet_topStack(t *testing.T) {
stack := NewFixedStack(2)
stack.Push(1)
stack.Push(2)

type fields struct {
stacks []*FixedStack
}
tests := []struct {
name string
fields fields
want *FixedStack
wantErr bool
}{
{
name: "returns error on empty set",
fields: fields{},
wantErr: true,
},
{
name: "returns the top stack from the set",
fields: fields{stacks: append([]*FixedStack{}, stack)},
want: stack,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
set := &StackSet{
stacks: tt.fields.stacks,
}
got, err := set.topStack()
if (err != nil) != tt.wantErr {
t.Errorf("topStack() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("topStack() got = %v, want %v", got, tt.want)
}
})
}
}

func TestStackSet_appendStack(t *testing.T) {
type fields struct {
stacks []*FixedStack
}
tests := []struct {
name string
fields fields
want *FixedStack
}{
{
name: "appends new stack to the set",
fields: fields{},
want: NewFixedStack(3),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
set := &StackSet{
stacks: tt.fields.stacks,
}
if got := set.appendStack(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("appendStack() = %v, want %v", got, tt.want)
}
})
}
}

func TestStackSet_removeStack(t *testing.T) {
type fields struct {
stacks []*FixedStack
}
tests := []struct {
name string
fields fields
want []*FixedStack
}{
{
name: "do nothing if no stacks in the set",
fields: fields{stacks: []*FixedStack{}},
want: []*FixedStack{},
},
{
name: "removes top stack from the set",
fields: fields{stacks: append([]*FixedStack{}, NewFixedStack(1), NewFixedStack(1))},
want: append([]*FixedStack{}, NewFixedStack(1)),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
set := &StackSet{
stacks: tt.fields.stacks,
}
set.removeStack()
if !reflect.DeepEqual(set.stacks, tt.want) {
t.Errorf("appendStack() set.stacks = %v, want %v", set.stacks, tt.want)
}
})
}
}
Loading

0 comments on commit b62df59

Please sign in to comment.