From 13e812c7f82fc77d0627a4b946187175ddb5d2ff Mon Sep 17 00:00:00 2001 From: Brijesh03032001 Date: Sat, 25 Oct 2025 22:08:25 -0700 Subject: [PATCH 1/2] Add comprehensive Stack data structure implementation Features: - Complete Stack class with LIFO operations (push, pop, peek, search) - Expression evaluator for infix to postfix conversion and evaluation - Balanced parentheses checker for multiple bracket types - Function call stack simulator - Next Greater Element problem solver using stack - Stock span problem and largest rectangle in histogram algorithms - Circular array next greater element finder - Comprehensive test cases and step-by-step demonstrations Files added: - data_structures/Stack/stack_operations.r (400+ lines) - data_structures/Stack/next_greater_element.r (300+ lines) - Updated DIRECTORY.md with Stack section --- DIRECTORY.md | 3 + data_structures/Stack/next_greater_element.r | 363 +++++++++++++++ data_structures/Stack/stack_operations.r | 450 +++++++++++++++++++ 3 files changed, 816 insertions(+) create mode 100644 data_structures/Stack/next_greater_element.r create mode 100644 data_structures/Stack/stack_operations.r diff --git a/DIRECTORY.md b/DIRECTORY.md index a7a1e1b5..ce29f2af 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -41,6 +41,9 @@ ## Data Structures * [Binary Search Tree](https://github.com/TheAlgorithms/R/blob/HEAD/data_structures/binary_search_tree.r) + * Stack + * [Next Greater Element](https://github.com/TheAlgorithms/R/blob/HEAD/data_structures/Stack/next_greater_element.r) + * [Stack Operations](https://github.com/TheAlgorithms/R/blob/HEAD/data_structures/Stack/stack_operations.r) ## Dynamic Programming * 0 diff --git a/data_structures/Stack/next_greater_element.r b/data_structures/Stack/next_greater_element.r new file mode 100644 index 00000000..0a569eff --- /dev/null +++ b/data_structures/Stack/next_greater_element.r @@ -0,0 +1,363 @@ +# Next Greater Element Problem - Stack Implementation +# +# Problem Statement: +# Given an array of integers, for each element find the next greater element to its right. +# The next greater element for an element x is the first greater element on the right side of x. +# If no greater element exists, return -1 for that element. +# +# Examples: +# Input: [4, 5, 2, 25] +# Output: [5, 25, 25, -1] +# Explanation: +# - For 4, next greater is 5 +# - For 5, next greater is 25 +# - For 2, next greater is 25 +# - For 25, no greater element exists +# +# Input: [13, 7, 6, 12] +# Output: [-1, 12, 12, -1] +# +# Input: [1, 3, 2, 4] +# Output: [3, 4, 4, -1] +# +# Algorithm: Stack-based O(n) solution +# Time Complexity: O(n) - each element is pushed and popped at most once +# Space Complexity: O(n) - for the stack in worst case (decreasing sequence) + +# Simple Stack implementation for algorithm use +AlgorithmStack <- setRefClass("AlgorithmStack", + fields = list( + items = "list", + top_idx = "numeric" + ), + methods = list( + initialize = function() { + .self$items <- list() + .self$top_idx <- 0 + }, + + push = function(item) { + .self$top_idx <- .self$top_idx + 1 + .self$items[[.self$top_idx]] <- item + }, + + pop = function() { + if (.self$top_idx == 0) return(NULL) + item <- .self$items[[.self$top_idx]] + .self$top_idx <- .self$top_idx - 1 + return(item) + }, + + peek = function() { + if (.self$top_idx == 0) return(NULL) + return(.self$items[[.self$top_idx]]) + }, + + is_empty = function() { + return(.self$top_idx == 0) + }, + + size = function() { + return(.self$top_idx) + } + ) +) + +# Main function to find next greater elements +next_greater_element <- function(arr) { + "Find next greater element for each element in array using stack" + if (length(arr) == 0) return(c()) + + n <- length(arr) + result <- rep(-1, n) # Initialize all with -1 + stack <- AlgorithmStack$new() + + # Process each element from left to right + for (i in 1:n) { + # While stack is not empty and current element is greater than + # the element at index stored at top of stack + while (!stack$is_empty() && arr[i] > arr[stack$peek()]) { + index <- stack$pop() + result[index] <- arr[i] + } + + # Push current element's index to stack + stack$push(i) + } + + return(result) +} + +# Enhanced version with step-by-step visualization +next_greater_element_with_steps <- function(arr) { + "Find next greater elements with detailed step-by-step visualization" + if (length(arr) == 0) return(list(result = c(), steps = list())) + + n <- length(arr) + result <- rep(-1, n) + stack <- AlgorithmStack$new() + steps <- list() + + # Initial state + steps[[1]] <- list( + step = 0, + current_element = "Start", + array = arr, + stack_contents = c(), + result = result, + description = "Initial state" + ) + + for (i in 1:n) { + step_description <- paste("Processing element", arr[i], "at index", i) + + # Pop elements and update result + popped_elements <- c() + while (!stack$is_empty() && arr[i] > arr[stack$peek()]) { + index <- stack$pop() + result[index] <- arr[i] + popped_elements <- c(popped_elements, index) + } + + if (length(popped_elements) > 0) { + step_description <- paste(step_description, "| Found NGE for indices:", paste(popped_elements, collapse = ", ")) + } + + # Push current index + stack$push(i) + + # Get current stack contents for visualization + stack_contents <- c() + if (!stack$is_empty()) { + for (j in 1:stack$size()) { + if (j <= length(stack$items)) { + stack_contents <- c(stack_contents, stack$items[[j]]) + } + } + } + + # Record step + steps[[i + 1]] <- list( + step = i, + current_element = arr[i], + array = arr, + stack_contents = stack_contents, + result = result, + description = step_description + ) + } + + return(list(result = result, steps = steps)) +} + +# Helper function to print array nicely +print_array <- function(arr, title = "Array") { + cat(title, ": [", paste(arr, collapse = ", "), "]\n") +} + +# Helper function to print step visualization +print_step <- function(step_info) { + cat("\nStep", step_info$step, ":", step_info$description, "\n") + cat("Current element:", step_info$current_element, "\n") + print_array(step_info$array, "Input") + + if (length(step_info$stack_contents) > 0) { + stack_values <- sapply(step_info$stack_contents, function(idx) paste0(step_info$array[idx], "(", idx, ")")) + cat("Stack (indices): [", paste(stack_values, collapse = ", "), "]\n") + } else { + cat("Stack: [empty]\n") + } + + print_array(step_info$result, "Result so far") +} + +# Next Greater Element to the Right for Circular Array +next_greater_element_circular <- function(arr) { + "Find next greater elements in circular array (wrapping around)" + if (length(arr) == 0) return(c()) + + n <- length(arr) + result <- rep(-1, n) + stack <- AlgorithmStack$new() + + # Process the array twice to handle circular nature + for (i in 1:(2 * n)) { + current_index <- ((i - 1) %% n) + 1 # Convert to 1-based circular index + + while (!stack$is_empty() && arr[current_index] > arr[stack$peek()]) { + index <- stack$pop() + if (result[index] == -1) { # Only update if not already found + result[index] <- arr[current_index] + } + } + + if (i <= n) { # Only push indices in first pass + stack$push(current_index) + } + } + + return(result) +} + +# Previous Greater Element (using stack) +previous_greater_element <- function(arr) { + "Find previous greater element for each element" + if (length(arr) == 0) return(c()) + + n <- length(arr) + result <- rep(-1, n) + stack <- AlgorithmStack$new() + + # Process from left to right + for (i in 1:n) { + # Remove smaller or equal elements + while (!stack$is_empty() && arr[stack$peek()] <= arr[i]) { + stack$pop() + } + + # If stack is not empty, top element is previous greater + if (!stack$is_empty()) { + result[i] <- arr[stack$peek()] + } + + stack$push(i) + } + + return(result) +} + +# Stock Span Problem using Stack +stock_span <- function(prices) { + "Calculate stock span for each day (consecutive previous days with price <= current day)" + if (length(prices) == 0) return(c()) + + n <- length(prices) + spans <- rep(1, n) # Initialize all spans to 1 + stack <- AlgorithmStack$new() + + for (i in 1:n) { + # Pop elements while stack is not empty and + # price at stack top is less than or equal to current price + while (!stack$is_empty() && prices[stack$peek()] <= prices[i]) { + stack$pop() + } + + # If stack becomes empty, span is i (all previous days) + # Otherwise, span is difference between current index and index at stack top + spans[i] <- if (stack$is_empty()) i else (i - stack$peek()) + + # Push current index to stack + stack$push(i) + } + + return(spans) +} + +# Largest Rectangle in Histogram using Stack +largest_rectangle_histogram <- function(heights) { + "Find the largest rectangle area in histogram using stack" + if (length(heights) == 0) return(0) + + n <- length(heights) + stack <- AlgorithmStack$new() + max_area <- 0 + + for (i in 1:n) { + # While stack is not empty and current height is less than + # height at stack top, calculate area with stack top as smallest bar + while (!stack$is_empty() && heights[i] < heights[stack$peek()]) { + height <- heights[stack$pop()] + width <- if (stack$is_empty()) i - 1 else i - stack$peek() - 1 + area <- height * width + max_area <- max(max_area, area) + } + stack$push(i) + } + + # Process remaining bars in stack + while (!stack$is_empty()) { + height <- heights[stack$pop()] + width <- if (stack$is_empty()) n else n - stack$peek() + area <- height * width + max_area <- max(max_area, area) + } + + return(max_area) +} + +# Function to demonstrate all stack applications +demonstrate_stack_applications <- function() { + cat("=== Stack Applications - Problem Solving ===\n") + + # Test Case 1: Next Greater Element + cat("\n--- Next Greater Element Problem ---\n") + test_arrays <- list( + c(4, 5, 2, 25), + c(13, 7, 6, 12), + c(1, 3, 2, 4), + c(5, 4, 3, 2, 1), + c(1, 2, 3, 4, 5) + ) + + for (i in seq_along(test_arrays)) { + arr <- test_arrays[[i]] + result <- next_greater_element(arr) + cat("\nTest", i, ":\n") + print_array(arr, "Input") + print_array(result, "Next Greater") + } + + # Test Case 2: Circular Array + cat("\n--- Next Greater Element (Circular Array) ---\n") + circular_test <- c(1, 2, 1) + print_array(circular_test, "Input") + circular_result <- next_greater_element_circular(circular_test) + print_array(circular_result, "Next Greater (Circular)") + + # Test Case 3: Previous Greater Element + cat("\n--- Previous Greater Element ---\n") + prev_test <- c(4, 5, 2, 25, 7, 8) + print_array(prev_test, "Input") + prev_result <- previous_greater_element(prev_test) + print_array(prev_result, "Previous Greater") + + # Test Case 4: Stock Span Problem + cat("\n--- Stock Span Problem ---\n") + stock_prices <- c(100, 80, 60, 70, 60, 75, 85) + print_array(stock_prices, "Stock Prices") + span_result <- stock_span(stock_prices) + print_array(span_result, "Stock Spans") + cat("Explanation: Span[i] = number of consecutive days (including current) with price <= price[i]\n") + + # Test Case 5: Largest Rectangle in Histogram + cat("\n--- Largest Rectangle in Histogram ---\n") + histogram_heights <- c(6, 2, 5, 4, 5, 1, 6) + print_array(histogram_heights, "Histogram Heights") + max_area <- largest_rectangle_histogram(histogram_heights) + cat("Largest Rectangle Area:", max_area, "\n") +} + +# Detailed step-by-step demonstration +demonstrate_detailed_steps <- function() { + cat("\n\n=== Detailed Step-by-Step: Next Greater Element ===\n") + + test_array <- c(4, 5, 2, 25) + cat("\nSolving for array:", paste(test_array, collapse = ", "), "\n") + cat("Algorithm: Use stack to store indices of elements for which NGE is not found yet\n") + + solution <- next_greater_element_with_steps(test_array) + + for (step in solution$steps) { + print_step(step) + } + + cat("\nFinal Result:", paste(solution$result, collapse = ", "), "\n") + cat("\nTime Complexity: O(n) - each element pushed and popped at most once\n") + cat("Space Complexity: O(n) - for the stack in worst case\n") +} + +# Run demonstrations if script is executed directly +if (sys.nframe() == 0) { + demonstrate_stack_applications() + demonstrate_detailed_steps() +} \ No newline at end of file diff --git a/data_structures/Stack/stack_operations.r b/data_structures/Stack/stack_operations.r new file mode 100644 index 00000000..3269dc1c --- /dev/null +++ b/data_structures/Stack/stack_operations.r @@ -0,0 +1,450 @@ +# Stack Data Structure Implementation in R +# +# A stack is a linear data structure that follows the Last In First Out (LIFO) principle. +# Elements are added and removed from the same end, called the top of the stack. +# +# Time Complexities: +# - Push: O(1) - adding element to top +# - Pop: O(1) - removing element from top +# - Peek/Top: O(1) - viewing top element +# - Size: O(1) - getting stack size +# - IsEmpty: O(1) - checking if stack is empty +# +# Space Complexity: O(n) where n is number of elements +# +# Applications: +# - Function call management (call stack) +# - Expression evaluation and syntax parsing +# - Undo operations in text editors +# - Browser history (back button) +# - Depth-First Search (DFS) in graphs +# - Backtracking algorithms +# - Memory management in programming languages + +# Define Stack class using Reference Classes +Stack <- setRefClass("Stack", + fields = list( + items = "list", + top_index = "numeric", + max_size = "numeric" + ), + methods = list( + initialize = function(max_size = Inf) { + "Initialize an empty stack with optional maximum size" + .self$items <- list() + .self$top_index <- 0 + .self$max_size <- max_size + cat("Stack initialized with max size:", ifelse(is.infinite(max_size), "unlimited", max_size), "\n") + }, + + push = function(item) { + "Add an element to the top of the stack" + if (.self$size() >= .self$max_size) { + stop("Stack overflow: Cannot push more elements. Max size reached: ", .self$max_size) + } + + .self$top_index <- .self$top_index + 1 + .self$items[[.self$top_index]] <- item + cat("Pushed:", item, "| Size:", .self$size(), "\n") + }, + + pop = function() { + "Remove and return the top element from the stack" + if (.self$is_empty()) { + stop("Stack underflow: Cannot pop from empty stack") + } + + item <- .self$items[[.self$top_index]] + .self$items[[.self$top_index]] <- NULL + .self$top_index <- .self$top_index - 1 + + # Clean up the list to optimize memory + if (.self$top_index < length(.self$items)) { + .self$items <- .self$items[1:.self$top_index] + } + + cat("Popped:", item, "| Size:", .self$size(), "\n") + return(item) + }, + + peek = function() { + "Return the top element without removing it" + if (.self$is_empty()) { + stop("Stack is empty: No top element") + } + return(.self$items[[.self$top_index]]) + }, + + top = function() { + "Alias for peek() - return the top element without removing it" + return(.self$peek()) + }, + + is_empty = function() { + "Check if the stack is empty" + return(.self$top_index == 0) + }, + + is_full = function() { + "Check if the stack is full (only applicable for bounded stacks)" + return(.self$size() >= .self$max_size) + }, + + size = function() { + "Return the number of elements in the stack" + return(.self$top_index) + }, + + clear = function() { + "Remove all elements from the stack" + .self$items <- list() + .self$top_index <- 0 + cat("Stack cleared\n") + }, + + display = function() { + "Display all elements in the stack from bottom to top" + if (.self$is_empty()) { + cat("Stack is empty: []\n") + return() + } + + elements <- character(0) + for (i in 1:.self$top_index) { + elements <- c(elements, as.character(.self$items[[i]])) + } + cat("Stack: [", paste(elements, collapse = " | "), "] (bottom → top)\n") + }, + + to_vector = function() { + "Convert stack to vector (bottom to top order)" + if (.self$is_empty()) return(c()) + + result <- c() + for (i in 1:.self$top_index) { + result <- c(result, .self$items[[i]]) + } + return(result) + }, + + search = function(item) { + "Search for an item in the stack and return its position from top (1-indexed)" + if (.self$is_empty()) return(-1) + + for (i in .self$top_index:1) { + if (identical(.self$items[[i]], item)) { + return(.self$top_index - i + 1) # Position from top + } + } + return(-1) # Item not found + }, + + reverse = function() { + "Reverse the order of elements in the stack" + if (.self$size() <= 1) return() + + # Create a temporary vector and reverse it + temp_items <- .self$to_vector() + temp_items <- rev(temp_items) + + # Rebuild stack with reversed order + .self$clear() + for (item in temp_items) { + .self$push(item) + } + cat("Stack reversed\n") + } + ) +) + +# Utility function to demonstrate stack operations +demonstrate_stack_operations <- function() { + cat("\n=== Stack Data Structure Demonstration ===\n\n") + + # Create a stack with maximum size of 5 + s <- Stack$new(max_size = 5) + + cat("\n1. Basic Push Operations:\n") + s$push("A") + s$push("B") + s$push("C") + s$display() + + cat("\n2. Stack Status:\n") + cat("Size:", s$size(), "\n") + cat("Is Empty:", s$is_empty(), "\n") + cat("Is Full:", s$is_full(), "\n") + cat("Top element:", s$peek(), "\n") + + cat("\n3. Pop Operations:\n") + s$pop() + s$display() + s$pop() + s$display() + + cat("\n4. More Push Operations:\n") + s$push("D") + s$push("E") + s$push("F") + s$push("G") + s$display() + + cat("\n5. Search Operations:\n") + cat("Position of 'E' from top:", s$search("E"), "\n") + cat("Position of 'Z' from top:", s$search("Z"), "\n") + + cat("\n6. Stack to Vector:\n") + vec <- s$to_vector() + cat("As vector:", paste(vec, collapse = ", "), "\n") + + cat("\n7. Reverse Stack:\n") + s$reverse() + s$display() + + cat("\n8. Testing Stack Overflow:\n") + tryCatch({ + s$push("H") # This should cause overflow + }, error = function(e) { + cat("Error caught:", e$message, "\n") + }) + + cat("\n9. Clear Stack:\n") + s$clear() + s$display() + + cat("\n10. Testing Stack Underflow:\n") + tryCatch({ + s$pop() # This should cause underflow + }, error = function(e) { + cat("Error caught:", e$message, "\n") + }) +} + +# Expression Evaluator using Stack (bonus feature) +ExpressionEvaluator <- setRefClass("ExpressionEvaluator", + fields = list( + operators = "character", + precedence = "list" + ), + methods = list( + initialize = function() { + "Initialize expression evaluator with operator precedence" + .self$operators <- c("+", "-", "*", "/", "^", "(", ")") + .self$precedence <- list("+" = 1, "-" = 1, "*" = 2, "/" = 2, "^" = 3, "(" = 0, ")" = 0) + cat("Expression Evaluator initialized\n") + }, + + is_operator = function(char) { + "Check if character is an operator" + return(char %in% .self$operators) + }, + + get_precedence = function(op) { + "Get precedence of an operator" + return(.self$precedence[[op]]) + }, + + infix_to_postfix = function(expression) { + "Convert infix expression to postfix notation" + # Remove spaces and split into tokens + tokens <- strsplit(gsub(" ", "", expression), "")[[1]] + result <- character(0) + stack <- Stack$new() + + for (token in tokens) { + if (!.self$is_operator(token)) { + # Operand + result <- c(result, token) + } else if (token == "(") { + stack$push(token) + } else if (token == ")") { + while (!stack$is_empty() && stack$peek() != "(") { + result <- c(result, stack$pop()) + } + if (!stack$is_empty()) stack$pop() # Remove the '(' + } else { + # Operator + while (!stack$is_empty() && + .self$get_precedence(stack$peek()) >= .self$get_precedence(token)) { + result <- c(result, stack$pop()) + } + stack$push(token) + } + } + + # Pop remaining operators + while (!stack$is_empty()) { + result <- c(result, stack$pop()) + } + + return(paste(result, collapse = " ")) + }, + + evaluate_postfix = function(expression) { + "Evaluate postfix expression" + tokens <- strsplit(expression, " ")[[1]] + stack <- Stack$new() + + for (token in tokens) { + if (!.self$is_operator(token)) { + # Operand + stack$push(as.numeric(token)) + } else { + # Operator + if (stack$size() < 2) { + stop("Invalid expression: insufficient operands") + } + + b <- stack$pop() + a <- stack$pop() + + result <- switch(token, + "+" = a + b, + "-" = a - b, + "*" = a * b, + "/" = if(b != 0) a / b else stop("Division by zero"), + "^" = a ^ b, + stop("Unknown operator:", token) + ) + + stack$push(result) + } + } + + if (stack$size() != 1) { + stop("Invalid expression: too many operands") + } + + return(stack$pop()) + }, + + evaluate_infix = function(expression) { + "Evaluate infix expression by converting to postfix first" + postfix <- .self$infix_to_postfix(expression) + cat("Infix:", expression, "\n") + cat("Postfix:", postfix, "\n") + result <- .self$evaluate_postfix(postfix) + cat("Result:", result, "\n") + return(result) + } + ) +) + +# Balanced Parentheses Checker +check_balanced_parentheses <- function(expression) { + "Check if parentheses are balanced in an expression" + stack <- Stack$new() + opening <- c("(", "[", "{") + closing <- c(")", "]", "}") + pairs <- list(")" = "(", "]" = "[", "}" = "{") + + chars <- strsplit(expression, "")[[1]] + + for (char in chars) { + if (char %in% opening) { + stack$push(char) + } else if (char %in% closing) { + if (stack$is_empty()) { + return(FALSE) # Closing bracket without opening + } + + if (stack$pop() != pairs[[char]]) { + return(FALSE) # Mismatched brackets + } + } + } + + return(stack$is_empty()) # Should be empty if balanced +} + +# Function Call Stack Simulator +FunctionCallStack <- setRefClass("FunctionCallStack", + fields = list( + call_stack = "ANY" + ), + methods = list( + initialize = function() { + .self$call_stack <- Stack$new() + cat("Function Call Stack initialized\n") + }, + + call_function = function(func_name, params = "") { + "Simulate a function call" + call_info <- paste0(func_name, "(", params, ")") + .self$call_stack$push(call_info) + cat("Called:", call_info, "| Stack depth:", .self$call_stack$size(), "\n") + }, + + return_from_function = function() { + "Simulate returning from a function" + if (.self$call_stack$is_empty()) { + cat("No function to return from\n") + return() + } + + returned_func <- .self$call_stack$pop() + cat("Returned from:", returned_func, "| Stack depth:", .self$call_stack$size(), "\n") + }, + + show_call_stack = function() { + "Display the current call stack" + if (.self$call_stack$is_empty()) { + cat("Call stack is empty\n") + return() + } + + cat("Current call stack (bottom to top):\n") + .self$call_stack$display() + } + ) +) + +# Example usage and testing +if (sys.nframe() == 0) { + # Demonstrate basic stack operations + demonstrate_stack_operations() + + cat("\n\n=== Expression Evaluation Demonstration ===\n") + evaluator <- ExpressionEvaluator$new() + + # Test infix to postfix conversion and evaluation + cat("\nExpression 1:\n") + evaluator$evaluate_infix("2 + 3 * 4") + + cat("\nExpression 2:\n") + evaluator$evaluate_infix("(2 + 3) * 4") + + cat("\nExpression 3:\n") + evaluator$evaluate_infix("2 ^ 3 + 1") + + cat("\n\n=== Balanced Parentheses Check ===\n") + test_expressions <- c( + "(())", + "((()))", + "()[]{}", + "([{}])", + "(()", + "())", + "([)]" + ) + + for (expr in test_expressions) { + result <- check_balanced_parentheses(expr) + cat("'", expr, "' is", ifelse(result, "balanced", "not balanced"), "\n") + } + + cat("\n\n=== Function Call Stack Simulation ===\n") + call_stack <- FunctionCallStack$new() + + call_stack$call_function("main", "") + call_stack$call_function("foo", "x, y") + call_stack$call_function("bar", "z") + call_stack$show_call_stack() + + call_stack$return_from_function() + call_stack$return_from_function() + call_stack$show_call_stack() + + call_stack$return_from_function() + call_stack$show_call_stack() +} \ No newline at end of file From 8b2ef7844a46b970901185f769b3d3aac31a4ac8 Mon Sep 17 00:00:00 2001 From: Brijesh03032001 Date: Sun, 26 Oct 2025 02:33:35 -0700 Subject: [PATCH 2/2] Remove LeetCode problems from Stack implementation - Remove next_greater_element.r file (contains Next Greater Element, Stock Span, Largest Rectangle problems) - Update DIRECTORY.md to reflect pure Stack data structure only - Keep only stack_operations.r with comprehensive Stack implementation - Focus on educational data structure implementation without problem-solving examples --- DIRECTORY.md | 1 - data_structures/Stack/next_greater_element.r | 363 ------------------- 2 files changed, 364 deletions(-) delete mode 100644 data_structures/Stack/next_greater_element.r diff --git a/DIRECTORY.md b/DIRECTORY.md index ce29f2af..d62b4bb2 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -42,7 +42,6 @@ ## Data Structures * [Binary Search Tree](https://github.com/TheAlgorithms/R/blob/HEAD/data_structures/binary_search_tree.r) * Stack - * [Next Greater Element](https://github.com/TheAlgorithms/R/blob/HEAD/data_structures/Stack/next_greater_element.r) * [Stack Operations](https://github.com/TheAlgorithms/R/blob/HEAD/data_structures/Stack/stack_operations.r) ## Dynamic Programming diff --git a/data_structures/Stack/next_greater_element.r b/data_structures/Stack/next_greater_element.r deleted file mode 100644 index 0a569eff..00000000 --- a/data_structures/Stack/next_greater_element.r +++ /dev/null @@ -1,363 +0,0 @@ -# Next Greater Element Problem - Stack Implementation -# -# Problem Statement: -# Given an array of integers, for each element find the next greater element to its right. -# The next greater element for an element x is the first greater element on the right side of x. -# If no greater element exists, return -1 for that element. -# -# Examples: -# Input: [4, 5, 2, 25] -# Output: [5, 25, 25, -1] -# Explanation: -# - For 4, next greater is 5 -# - For 5, next greater is 25 -# - For 2, next greater is 25 -# - For 25, no greater element exists -# -# Input: [13, 7, 6, 12] -# Output: [-1, 12, 12, -1] -# -# Input: [1, 3, 2, 4] -# Output: [3, 4, 4, -1] -# -# Algorithm: Stack-based O(n) solution -# Time Complexity: O(n) - each element is pushed and popped at most once -# Space Complexity: O(n) - for the stack in worst case (decreasing sequence) - -# Simple Stack implementation for algorithm use -AlgorithmStack <- setRefClass("AlgorithmStack", - fields = list( - items = "list", - top_idx = "numeric" - ), - methods = list( - initialize = function() { - .self$items <- list() - .self$top_idx <- 0 - }, - - push = function(item) { - .self$top_idx <- .self$top_idx + 1 - .self$items[[.self$top_idx]] <- item - }, - - pop = function() { - if (.self$top_idx == 0) return(NULL) - item <- .self$items[[.self$top_idx]] - .self$top_idx <- .self$top_idx - 1 - return(item) - }, - - peek = function() { - if (.self$top_idx == 0) return(NULL) - return(.self$items[[.self$top_idx]]) - }, - - is_empty = function() { - return(.self$top_idx == 0) - }, - - size = function() { - return(.self$top_idx) - } - ) -) - -# Main function to find next greater elements -next_greater_element <- function(arr) { - "Find next greater element for each element in array using stack" - if (length(arr) == 0) return(c()) - - n <- length(arr) - result <- rep(-1, n) # Initialize all with -1 - stack <- AlgorithmStack$new() - - # Process each element from left to right - for (i in 1:n) { - # While stack is not empty and current element is greater than - # the element at index stored at top of stack - while (!stack$is_empty() && arr[i] > arr[stack$peek()]) { - index <- stack$pop() - result[index] <- arr[i] - } - - # Push current element's index to stack - stack$push(i) - } - - return(result) -} - -# Enhanced version with step-by-step visualization -next_greater_element_with_steps <- function(arr) { - "Find next greater elements with detailed step-by-step visualization" - if (length(arr) == 0) return(list(result = c(), steps = list())) - - n <- length(arr) - result <- rep(-1, n) - stack <- AlgorithmStack$new() - steps <- list() - - # Initial state - steps[[1]] <- list( - step = 0, - current_element = "Start", - array = arr, - stack_contents = c(), - result = result, - description = "Initial state" - ) - - for (i in 1:n) { - step_description <- paste("Processing element", arr[i], "at index", i) - - # Pop elements and update result - popped_elements <- c() - while (!stack$is_empty() && arr[i] > arr[stack$peek()]) { - index <- stack$pop() - result[index] <- arr[i] - popped_elements <- c(popped_elements, index) - } - - if (length(popped_elements) > 0) { - step_description <- paste(step_description, "| Found NGE for indices:", paste(popped_elements, collapse = ", ")) - } - - # Push current index - stack$push(i) - - # Get current stack contents for visualization - stack_contents <- c() - if (!stack$is_empty()) { - for (j in 1:stack$size()) { - if (j <= length(stack$items)) { - stack_contents <- c(stack_contents, stack$items[[j]]) - } - } - } - - # Record step - steps[[i + 1]] <- list( - step = i, - current_element = arr[i], - array = arr, - stack_contents = stack_contents, - result = result, - description = step_description - ) - } - - return(list(result = result, steps = steps)) -} - -# Helper function to print array nicely -print_array <- function(arr, title = "Array") { - cat(title, ": [", paste(arr, collapse = ", "), "]\n") -} - -# Helper function to print step visualization -print_step <- function(step_info) { - cat("\nStep", step_info$step, ":", step_info$description, "\n") - cat("Current element:", step_info$current_element, "\n") - print_array(step_info$array, "Input") - - if (length(step_info$stack_contents) > 0) { - stack_values <- sapply(step_info$stack_contents, function(idx) paste0(step_info$array[idx], "(", idx, ")")) - cat("Stack (indices): [", paste(stack_values, collapse = ", "), "]\n") - } else { - cat("Stack: [empty]\n") - } - - print_array(step_info$result, "Result so far") -} - -# Next Greater Element to the Right for Circular Array -next_greater_element_circular <- function(arr) { - "Find next greater elements in circular array (wrapping around)" - if (length(arr) == 0) return(c()) - - n <- length(arr) - result <- rep(-1, n) - stack <- AlgorithmStack$new() - - # Process the array twice to handle circular nature - for (i in 1:(2 * n)) { - current_index <- ((i - 1) %% n) + 1 # Convert to 1-based circular index - - while (!stack$is_empty() && arr[current_index] > arr[stack$peek()]) { - index <- stack$pop() - if (result[index] == -1) { # Only update if not already found - result[index] <- arr[current_index] - } - } - - if (i <= n) { # Only push indices in first pass - stack$push(current_index) - } - } - - return(result) -} - -# Previous Greater Element (using stack) -previous_greater_element <- function(arr) { - "Find previous greater element for each element" - if (length(arr) == 0) return(c()) - - n <- length(arr) - result <- rep(-1, n) - stack <- AlgorithmStack$new() - - # Process from left to right - for (i in 1:n) { - # Remove smaller or equal elements - while (!stack$is_empty() && arr[stack$peek()] <= arr[i]) { - stack$pop() - } - - # If stack is not empty, top element is previous greater - if (!stack$is_empty()) { - result[i] <- arr[stack$peek()] - } - - stack$push(i) - } - - return(result) -} - -# Stock Span Problem using Stack -stock_span <- function(prices) { - "Calculate stock span for each day (consecutive previous days with price <= current day)" - if (length(prices) == 0) return(c()) - - n <- length(prices) - spans <- rep(1, n) # Initialize all spans to 1 - stack <- AlgorithmStack$new() - - for (i in 1:n) { - # Pop elements while stack is not empty and - # price at stack top is less than or equal to current price - while (!stack$is_empty() && prices[stack$peek()] <= prices[i]) { - stack$pop() - } - - # If stack becomes empty, span is i (all previous days) - # Otherwise, span is difference between current index and index at stack top - spans[i] <- if (stack$is_empty()) i else (i - stack$peek()) - - # Push current index to stack - stack$push(i) - } - - return(spans) -} - -# Largest Rectangle in Histogram using Stack -largest_rectangle_histogram <- function(heights) { - "Find the largest rectangle area in histogram using stack" - if (length(heights) == 0) return(0) - - n <- length(heights) - stack <- AlgorithmStack$new() - max_area <- 0 - - for (i in 1:n) { - # While stack is not empty and current height is less than - # height at stack top, calculate area with stack top as smallest bar - while (!stack$is_empty() && heights[i] < heights[stack$peek()]) { - height <- heights[stack$pop()] - width <- if (stack$is_empty()) i - 1 else i - stack$peek() - 1 - area <- height * width - max_area <- max(max_area, area) - } - stack$push(i) - } - - # Process remaining bars in stack - while (!stack$is_empty()) { - height <- heights[stack$pop()] - width <- if (stack$is_empty()) n else n - stack$peek() - area <- height * width - max_area <- max(max_area, area) - } - - return(max_area) -} - -# Function to demonstrate all stack applications -demonstrate_stack_applications <- function() { - cat("=== Stack Applications - Problem Solving ===\n") - - # Test Case 1: Next Greater Element - cat("\n--- Next Greater Element Problem ---\n") - test_arrays <- list( - c(4, 5, 2, 25), - c(13, 7, 6, 12), - c(1, 3, 2, 4), - c(5, 4, 3, 2, 1), - c(1, 2, 3, 4, 5) - ) - - for (i in seq_along(test_arrays)) { - arr <- test_arrays[[i]] - result <- next_greater_element(arr) - cat("\nTest", i, ":\n") - print_array(arr, "Input") - print_array(result, "Next Greater") - } - - # Test Case 2: Circular Array - cat("\n--- Next Greater Element (Circular Array) ---\n") - circular_test <- c(1, 2, 1) - print_array(circular_test, "Input") - circular_result <- next_greater_element_circular(circular_test) - print_array(circular_result, "Next Greater (Circular)") - - # Test Case 3: Previous Greater Element - cat("\n--- Previous Greater Element ---\n") - prev_test <- c(4, 5, 2, 25, 7, 8) - print_array(prev_test, "Input") - prev_result <- previous_greater_element(prev_test) - print_array(prev_result, "Previous Greater") - - # Test Case 4: Stock Span Problem - cat("\n--- Stock Span Problem ---\n") - stock_prices <- c(100, 80, 60, 70, 60, 75, 85) - print_array(stock_prices, "Stock Prices") - span_result <- stock_span(stock_prices) - print_array(span_result, "Stock Spans") - cat("Explanation: Span[i] = number of consecutive days (including current) with price <= price[i]\n") - - # Test Case 5: Largest Rectangle in Histogram - cat("\n--- Largest Rectangle in Histogram ---\n") - histogram_heights <- c(6, 2, 5, 4, 5, 1, 6) - print_array(histogram_heights, "Histogram Heights") - max_area <- largest_rectangle_histogram(histogram_heights) - cat("Largest Rectangle Area:", max_area, "\n") -} - -# Detailed step-by-step demonstration -demonstrate_detailed_steps <- function() { - cat("\n\n=== Detailed Step-by-Step: Next Greater Element ===\n") - - test_array <- c(4, 5, 2, 25) - cat("\nSolving for array:", paste(test_array, collapse = ", "), "\n") - cat("Algorithm: Use stack to store indices of elements for which NGE is not found yet\n") - - solution <- next_greater_element_with_steps(test_array) - - for (step in solution$steps) { - print_step(step) - } - - cat("\nFinal Result:", paste(solution$result, collapse = ", "), "\n") - cat("\nTime Complexity: O(n) - each element pushed and popped at most once\n") - cat("Space Complexity: O(n) - for the stack in worst case\n") -} - -# Run demonstrations if script is executed directly -if (sys.nframe() == 0) { - demonstrate_stack_applications() - demonstrate_detailed_steps() -} \ No newline at end of file