The Turkish (Turk) algorithm is a greedy, cost-based approach used by Push Swap to sort stacks with more than 3 elements. It works by calculating the “cost” of moving each element and always choosing the cheapest move.The algorithm is implemented in sort_big_stacks.c:53 and uses helper functions from init_a_to_b.c and init_b_to_a.c.
void sort_big_stacks(t_list **a, t_list **b){ int len_a; len_a = stack_len(*a); // Push first two elements without cost analysis if (len_a-- > 3 && !is_stack_sorted(*a)) pb(b, a, false); if (len_a-- > 3 && !is_stack_sorted(*a)) pb(b, a, false); // Push remaining elements using cost analysis while (len_a-- > 3 && !is_stack_sorted(*a)) { init_nodes_a(*a, *b); move_a_to_b(a, b); } // Sort the final 3 elements sort_three(a); // Push everything back to A while (*b) { init_nodes_b(*a, *b); move_b_to_a(a, b); } current_index(*a); min_on_top(a);}
The first two elements are pushed immediately without cost analysis to establish a reference in Stack B for subsequent cost calculations.
Before each move, init_nodes_a() prepares all nodes with necessary metadata:
void init_nodes_a(t_list *a, t_list *b){ current_index(a); // Set index and above_median for each node current_index(b); set_target_a(a, b); // Find target position in B for each node in A cost_analysis_a(a, b); // Calculate push cost set_cheapest(a); // Mark the cheapest node}
The current_index() function assigns an index to each node and determines if it’s above or below the median:
void current_index(t_list *stack){ int i; int median; i = 0; if (!stack) return; median = stack_len(stack) / 2; while (stack) { stack->index = i; if (i <= median) stack->above_median = true; else stack->above_median = false; stack = stack->next; i++; }}
The above_median flag is critical for optimization - it determines whether to use rotate (ra/rb) or reverse rotate (rra/rrb) to bring an element to the top.
For each element in Stack A, the algorithm finds its target position in Stack B:
static void set_target_a(t_list *a, t_list *b){ t_list *current_b; t_list *target_node; long best_match_index; while (a) { best_match_index = LONG_MIN; current_b = b; while (current_b) { // Find the largest number in B that's still smaller than a->nbr if (current_b->nbr < a->nbr && current_b->nbr > best_match_index) { best_match_index = current_b->nbr; target_node = current_b; } current_b = current_b->next; } // If no smaller number exists, target is the maximum if (best_match_index == LONG_MIN) a->target_node = find_max(b); else a->target_node = target_node; a = a->next; }}
The target selection strategy:
Find the largest number in B that is still smaller than the current number in A
If no such number exists, the target is the maximum element in B
The cost_analysis_a() function calculates how many operations it would take to push each element from A to B:
static void cost_analysis_a(t_list *a, t_list *b){ int len_a; int len_b; len_a = stack_len(a); len_b = stack_len(b); while (a) { // Cost to bring element to top of A a->push_cost = a->index; if (!(a->above_median)) a->push_cost = len_a - (a->index); // Add cost to bring target to top of B if (a->target_node->above_median) a->push_cost += a->target_node->index; else a->push_cost += len_b - (a->target_node->index); a = a->next; }}
Cost components:
Rotation cost in A: Number of rotations to bring element to top
If above median: use ra (cost = index)
If below median: use rra (cost = len - index)
Rotation cost in B: Number of rotations to bring target to top
Same logic as Stack A
This cost calculation doesn’t account for simultaneous rotations (rr/rrr), which are optimized later in move_a_to_b().
When moving the cheapest node from A to B, the algorithm optimizes by rotating both stacks simultaneously when possible:
static void move_a_to_b(t_list **a, t_list **b){ t_list *cheapest_node; cheapest_node = get_cheapest(*a); // Both above median: rotate both together if (cheapest_node->above_median && cheapest_node->target_node->above_median) rotate_both(a, b, cheapest_node); // Both below median: reverse rotate both together else if (!(cheapest_node->above_median) && !(cheapest_node->target_node->above_median)) rev_rotate_both(a, b, cheapest_node); // Finish positioning both nodes at the top prep_for_push(a, cheapest_node, 'a'); prep_for_push(b, cheapest_node->target_node, 'b'); // Push from A to B pb(b, a, false);}