Commit 3130928

mo khan <mo.khan@gmail.com>
2020-07-05 18:43:33
Convert min stack to near constant time algorithm
1 parent fb9a4af
src/01/06/min_stack.c
@@ -2,20 +2,6 @@
 #include <stdlib.h>
 #include "min_stack.h"
 
-Stack *initialize(void) {
-  Stack *self = malloc(sizeof(Stack));
-  self->head = NULL;
-  return self;
-}
-
-int size(Stack *self) {
-  Node *current = self->head;
-  int i;
-  for (i = 0; current != NULL; i++)
-    current = current->next;
-  return i;
-}
-
 static Node *new(int data) {
   Node *node = malloc(sizeof(Node));
   node->next = NULL;
@@ -23,38 +9,50 @@ static Node *new(int data) {
   return node;
 }
 
-static int compare(int x, int y) {
-  return x == y ? 0 : (x > y) ? 1 : -1;
+Stack *initialize(void) {
+  Stack *self = malloc(sizeof(Stack));
+  self->head = NULL;
+  self->min = NULL;
+  self->size = 0;
+  return self;
 }
 
-static void insert(Node **self, int data) {
-  int comparison = compare(data, (*self)->data);
-  Node *node = new(data);
-
-  switch(comparison) {
-    case 1:
-      if ((*self)->next)
-        insert(&((*self)->next), data);
-      else
-        (*self)->next = node;
-      break;
-    default:
-      node->next = *self;
-      *self = node;
-      break;
-  }
+int size(Stack *self) {
+  return self->size;
 }
 
 void push(Stack *self, int data) {
-  if (self->head)
-    insert(&self->head, data);
-  else
-    self->head = new(data);
+  if (self->min) {
+    if (data < self->min->data) {
+      Node *tmp = new(data);
+      tmp->next = self->min;
+      self->min = tmp;
+    }
+  } else {
+    self->min = new(data);
+  }
+
+  Node *node = new(data);
+  node->next = self->head;
+  self->head = node;
+  self->size++;
 }
 
 int min(Stack *self) {
-  if (self && self->head)
-    return self->head->data;
+  if(self->min)
+    return self->min->data;
+
+  if (self->head) {
+    int min = self->head->data;
+    Node *tmp = self->head->next;
+
+    while(tmp) {
+      if (tmp->data < min)
+        min = tmp->data;
+      tmp = tmp->next;
+    }
+    return min;
+  }
 
   return (int)NULL;
 }
@@ -65,7 +63,12 @@ int pop(Stack *self) {
 
   Node *current = self->head;
   int data = current->data;
+  if (data == self->min->data) {
+    self->min = self->min->next;
+  }
+
   self->head = current->next;
+  self->size--;
   current->next = NULL;
   free(current);
   return data;
src/01/06/min_stack.h
@@ -7,6 +7,8 @@ typedef struct node Node;
 
 typedef struct {
   Node *head;
+  Node *min;
+  int size;
 } Stack;
 
 Stack *initialize(void);
src/01/06/min_stack_test.c
@@ -15,6 +15,74 @@ Ensure(MinStack, when_empty) {
   free(stack);
 }
 
+Ensure(MinStack, when_empty_it_has_a_size_of_zero) {
+  Stack *stack = initialize();
+
+  assert_that(size(stack), is_equal_to(0));
+
+  free(stack);
+}
+
+Ensure(MinStack, when_empty_it_has_a_min_of_null) {
+  Stack *stack = initialize();
+
+  assert_that(min(stack), is_equal_to(NULL));
+
+  free(stack);
+}
+
+Ensure(MinStack, when_a_single_item_is_on_the_stack_it_has_a_size_of_one) {
+  Stack *stack = initialize();
+
+  push(stack, 1);
+
+  assert_that(size(stack), is_equal_to(1));
+
+  free(stack);
+}
+
+Ensure(MinStack, when_a_single_item_is_on_the_stack_it_is_the_min) {
+  Stack *stack = initialize();
+
+  push(stack, -100);
+
+  assert_that(min(stack), is_equal_to(-100));
+
+  free(stack);
+}
+
+Ensure(MinStack, when_a_single_item_is_on_the_stack_when_it_is_popped_off_it_returns_the_item) {
+  Stack *stack = initialize();
+
+  push(stack, 200);
+
+  assert_that(pop(stack), is_equal_to(200));
+
+  free(stack);
+}
+
+Ensure(MinStack, when_a_single_item_is_on_the_stack_when_it_is_popped_off_it_returns_a_size_of_zero) {
+  Stack *stack = initialize();
+
+  push(stack, 200);
+  pop(stack);
+
+  assert_that(size(stack), is_equal_to(0));
+
+  free(stack);
+}
+
+Ensure(MinStack, when_a_single_item_is_on_the_stack_when_it_is_popped_off_it_returns_a_min_of_null) {
+  Stack *stack = initialize();
+
+  push(stack, 200);
+  pop(stack);
+
+  assert_that(min(stack), is_equal_to(NULL));
+
+  free(stack);
+}
+
 Ensure(MinStack, when_pushing_a_single_integer) {
   Stack *stack = initialize();
 
@@ -33,18 +101,23 @@ Ensure(MinStack, when_pushing_multiple_integers_out_of_order) {
 
   push(stack, 2);
   push(stack, 3);
+  push(stack, 4);
   push(stack, 1);
 
-  assert_that(size(stack), is_equal_to(3));
+  assert_that(size(stack), is_equal_to(4));
   assert_that(min(stack), is_equal_to(1));
 
   assert_that(pop(stack), is_equal_to(1));
+  assert_that(size(stack), is_equal_to(3));
+  assert_that(min(stack), is_equal_to(2));
+
+  assert_that(pop(stack), is_equal_to(4));
   assert_that(size(stack), is_equal_to(2));
   assert_that(min(stack), is_equal_to(2));
 
   assert_that(pop(stack), is_equal_to(3));
   assert_that(size(stack), is_equal_to(1));
-  assert_that(min(stack), is_equal_to(3));
+  assert_that(min(stack), is_equal_to(2));
 
   assert_that(pop(stack), is_equal_to(2));
   assert_that(size(stack), is_equal_to(0));
@@ -83,7 +156,16 @@ Ensure(MinStack, when_pushing_duplicate_values_on_to_the_stack) {
 TestSuite *min_stack_tests() {
   TestSuite *suite = create_test_suite();
 
-  add_test_with_context(suite, MinStack, when_empty);
+  add_test_with_context(suite, MinStack, when_empty_it_has_a_size_of_zero);
+  add_test_with_context(suite, MinStack, when_empty_it_has_a_min_of_null);
+
+  add_test_with_context(suite, MinStack, when_a_single_item_is_on_the_stack_it_has_a_size_of_one);
+  add_test_with_context(suite, MinStack, when_a_single_item_is_on_the_stack_it_is_the_min);
+
+  add_test_with_context(suite, MinStack, when_a_single_item_is_on_the_stack_when_it_is_popped_off_it_returns_the_item);
+  add_test_with_context(suite, MinStack, when_a_single_item_is_on_the_stack_when_it_is_popped_off_it_returns_a_size_of_zero);
+  add_test_with_context(suite, MinStack, when_a_single_item_is_on_the_stack_when_it_is_popped_off_it_returns_a_min_of_null);
+
   add_test_with_context(suite, MinStack, when_pushing_a_single_integer);
   add_test_with_context(suite, MinStack, when_pushing_multiple_integers_out_of_order);
   return suite;