Implement detection of largest increasing subsequence
authorLukas Jiriste <ljiriste@student.42prague.com>
Thu, 29 Feb 2024 16:25:47 +0000 (17:25 +0100)
committerLukas Jiriste <ljiriste@student.42prague.com>
Thu, 29 Feb 2024 16:25:47 +0000 (17:25 +0100)
This lowers the number of operations needed for sorting.
We can leave an increasing subsequence inside A because
the sorting algorithm before this commit just builded
incresing sequence anyway.
Leaving a number in stack A costs just one rotate, while
pushing it to B costs at least an additional
push back to A plus probably a bunch of rotates over it
while trying to push other entries back to A.

Makefile
src/checker.h
src/circular_lis.c [new file with mode: 0644]
src/helpers.c
src/push.c
src/stacks_mem.c

index 554bc7d346621e7e6a139a5b337ecefbd39afc92..a1c984c024d1550fad9e6287200b1f5a217c9edb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -34,6 +34,7 @@ PUSHSOURCES :=        push.c                                  \
                                helpers.c                               \
                                prepare.c                               \
                                find.c                                  \
+                               circular_lis.c                  \
 
 PUSHSOURCES := $(addprefix $(PUSHSRCDIR)/, $(PUSHSOURCES))
 
index 2288d796bb133fbe8b618ea84d9bc64f324f0dae..d9aeec0e236f98ae777893e25951e0315aeab4bb 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   Created: 2024/01/24 12:13:51 by ljiriste          #+#    #+#             */
-/*   Updated: 2024/02/29 10:27:01 by ljiriste         ###   ########.fr       */
+/*   Updated: 2024/02/29 16:27:28 by ljiriste         ###   ########.fr       */
 /*                                                                            */
 /* ************************************************************************** */
 
@@ -42,6 +42,7 @@ typedef struct s_command
        t_target        target;
 }                              t_command;
 
+void           free_stack(t_stack *s);
 void           init_stack(t_stack *s);
 void           clean_up(t_stacks *s);
 /*
@@ -67,10 +68,12 @@ void                stack_rotate(t_stack *s, int amount);
 void           stack_pop(t_stack *s);
 int                    stack_top(t_stack *s);
 
+t_arr_stat     get_circular_lis(t_stack *lis, t_stack *stack);
 int                    is_sorted(t_stack *s);
 int                    parse(int argc, char **argv, t_stack *s);
 void           prepare_stacks(t_stacks *s, size_t ind_a, size_t ind_b);
 size_t         cost(t_stacks *s, const size_t b_plus, const size_t a_plus);
+size_t         binary_search(t_vec *sorted, t_stack *stack, size_t val_ind);
 size_t         find_best(t_stacks *s, t_vec *target_a_indeces);
 size_t         find_target_ind(t_stack *stack, int val);
 size_t         find_minind(t_stack *s);
diff --git a/src/circular_lis.c b/src/circular_lis.c
new file mode 100644 (file)
index 0000000..b1ccd9b
--- /dev/null
@@ -0,0 +1,123 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   circular_lis.c                                     :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2024/02/27 15:18:21 by ljiriste          #+#    #+#             */
+/*   Updated: 2024/02/29 16:59:55 by ljiriste         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+#include "checker.h"
+#include "libft.h"
+
+static t_arr_stat reconstruct_lis(t_stack *lis, t_stack *stack, t_vec *lowest, t_vec *predecessors)
+{
+       size_t          i;
+       size_t          j;
+       size_t          rotation;
+       t_arr_stat      res;
+
+       i = lowest->size - 1;
+       j = *(size_t *)ft_vec_access(lowest, i);
+       rotation = -j;
+       while (i > 0 && j != SIZE_MAX)
+       {
+               stack_rotate(stack, -(int)rotation);
+               res = stack_push(lis, stack_top(stack));
+               if (res != success)
+                       return (res);
+               rotation = j;
+               j = *(size_t *)ft_vec_access(predecessors, j);
+               rotation -= j;
+       }
+       return (success);
+}
+
+static t_arr_stat get_lis_loop(t_stack *stack, t_vec *inds_of_lowest, t_vec *inds_of_predecessor)
+{
+       size_t                          i;
+       size_t                          new_ind;
+       t_arr_stat                      res;
+       static const size_t     invalid = SIZE_MAX;
+
+       i = 0;
+       while (i < stack->stack.size)
+       {
+               new_ind = binary_search(inds_of_lowest, stack, i);
+               if (new_ind == inds_of_lowest->size)
+                       res = ft_vec_append(inds_of_lowest, &i);
+               else
+                       *(size_t *)ft_vec_access(inds_of_lowest, new_ind) = i;
+               if (res != success)
+                       break;
+               if (new_ind == 0)
+                       res = ft_vec_append(inds_of_predecessor, &invalid);
+               else
+                       res = ft_vec_append(inds_of_predecessor, ft_vec_access(inds_of_lowest, new_ind - 1));
+               if (res != success)
+                       break;
+               ++i;
+       }
+       return (res);
+}
+
+/*     This is the algorithm for finding the longest increasing subsequence
+       found on wikipedia adjusted for circular sequences (stack).*/
+static t_arr_stat get_lis(t_stack *lis, t_stack *stack, size_t ind)
+{
+       t_vec                   inds_of_lowest;
+       t_vec                   inds_of_predecessor;
+       const size_t    stack_init_ind = stack->ind;
+       t_arr_stat              res;
+
+       ft_vec_init(&inds_of_lowest, sizeof(size_t));
+       ft_vec_init(&inds_of_predecessor, sizeof(size_t));
+       stack_rotate(stack, ind);
+       res = get_lis_loop(stack, &inds_of_lowest, &inds_of_predecessor);
+       if (res == success)
+               reconstruct_lis(lis, stack, &inds_of_lowest, &inds_of_predecessor);
+       ft_vec_free(&inds_of_lowest, NULL);
+       ft_vec_free(&inds_of_predecessor, NULL);
+       stack->ind = stack_init_ind;
+       return (res);
+}
+
+static size_t  lis_length(t_stack *stack)
+{
+       t_stack lis;
+       size_t  res;
+
+       init_stack(&lis);
+       if (get_lis(&lis, stack, 0) == success)
+               res = lis.stack.size;
+       else
+               res = 0;
+       free_stack(&lis);
+       return (res);
+}
+
+t_arr_stat     get_circular_lis(t_stack *lis, t_stack *stack)
+{
+       size_t  max;
+       size_t  max_ind;
+       size_t  i;
+       size_t  len_i;
+
+       max = 0;
+       i = 0;
+       while (i < stack->stack.size)
+       {
+               len_i = lis_length(stack);
+               if (len_i > max)
+               {
+                       max = len_i;
+                       max_ind = i;
+               }
+               ++i;
+               stack_rotate(stack, 1);
+       }
+       return (get_lis(lis, stack, max_ind));
+}
index ef0a1c3b864ef65b7c260bdaf9ce5126852592ce..ee17362638a6a1673df568e9963547f85e3c3926 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   Created: 2024/02/22 14:22:08 by ljiriste          #+#    #+#             */
-/*   Updated: 2024/02/24 14:09:17 by ljiriste         ###   ########.fr       */
+/*   Updated: 2024/02/29 16:20:32 by ljiriste         ###   ########.fr       */
 /*                                                                            */
 /* ************************************************************************** */
 
@@ -72,3 +72,41 @@ size_t       cost(t_stacks *s, const size_t b_plus, const size_t a_plus)
        res = ft_mins(res, a_minus + b_plus);
        return (res);
 }
+
+static int     unrolled_stack_access(t_stack *stack, size_t ind)
+{
+       int     res;
+
+       if (ind > SIZE_MAX - stack->ind)
+               ind -= SIZE_MAX;
+       ind += stack->ind;
+       ind %= stack->stack.size;
+       res = *(int *)ft_vec_access(&stack->stack, ind);
+       return (res);
+}
+
+size_t binary_search(t_vec *sorted, t_stack *stack, size_t val_ind)
+{
+       const int       val = unrolled_stack_access(stack, val_ind);
+       size_t          hi;
+       size_t          lo;
+       size_t          mid;
+
+       lo = 0;
+       hi = sorted->size;
+       mid = lo + (hi - lo) / 2;
+       while (lo != hi)
+       {
+               if (val > unrolled_stack_access(stack, *(size_t *)ft_vec_access(sorted, mid)))
+               {
+                       lo = mid + 1;
+               }
+               else
+               {
+                       hi = mid;
+               }
+               mid = lo + (hi - lo) / 2;
+       }
+       return (mid);
+}
+
index fcf5b9d6ca9f50edb4e0860bef50861656dc0b83..8bc0fb5014cf307e7d7ebe9d9adbae5644280519 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   Created: 2024/01/24 13:17:32 by ljiriste          #+#    #+#             */
-/*   Updated: 2024/02/24 14:10:54 by ljiriste         ###   ########.fr       */
+/*   Updated: 2024/02/29 14:41:41 by ljiriste         ###   ########.fr       */
 /*                                                                            */
 /* ************************************************************************** */
 
@@ -91,14 +91,25 @@ void        rotate_a_to_sort(t_stacks *s)
 
 void   sort(t_stacks *s)
 {
-       int     ind_a;
-       int     ind_b;
+       int             ind_a;
+       int             ind_b;
+       t_stack lis;
 
-       while (s->a.stack.size > 3)
+       init_stack(&lis);
+       get_circular_lis(&lis, &s->a);
+       while (s->a.stack.size > lis.stack.size && s->a.stack.size > 3)
        {
-               print_push(s, b);
+               if (stack_top(&lis) == stack_top(&s->a))
+               {
+                       stack_rotate(&lis, 1);
+                       print_rotate(s, a);
+               }
+               else
+                       print_push(s, b);
        }
-       a_sort_three_or_less(s);
+       free_stack(&lis);
+       if (lis.stack.size < 3)
+               a_sort_three_or_less(s);
        while (s->b.stack.size > 0)
        {
                get_push_indeces(s, &ind_a, &ind_b);
index dac4dc1496f23847bd93f158bff1aea3f490ec6f..fe68df3241697a816c403f7c369d7ebcf1afe640 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   Created: 2024/02/06 14:20:04 by ljiriste          #+#    #+#             */
-/*   Updated: 2024/02/06 14:22:06 by ljiriste         ###   ########.fr       */
+/*   Updated: 2024/02/29 11:10:56 by ljiriste         ###   ########.fr       */
 /*                                                                            */
 /* ************************************************************************** */
 
@@ -20,7 +20,7 @@ void  init_stack(t_stack *s)
        return ;
 }
 
-static void    free_stack(t_stack *s)
+void   free_stack(t_stack *s)
 {
        ft_vec_free(&s->stack, NULL);
        s->ind = 0;