Index
Stack
A stack is a fundamental data structure that follows the Last-In, First-Out (LIFO) principle, meaning that the last element added to the stack is the first one to be removed. It operates on two main operations: push and pop.
Here’s an overview of stack operations:
- Push: Adds an element to the top of the stack.
- Pop: Removes the element from the top of the stack.
- Peek (or Top): Returns the element at the top of the stack without removing it.
- isEmpty: Checks if the stack is empty.
- isFull: Checks if the stack is full (for fixed-size stacks).
Stacks are commonly used in various computer science applications, including:
- Function call management: Storing return addresses during function calls.
- Expression evaluation and parsing: Evaluating expressions and parsing syntax.
- Undo functionality in text editors and software: Storing previous states to enable undo operations.
- Backtracking algorithms: Storing states to backtrack to previous decisions.
- Memory management: Storing variables and function call information during program execution.
Stacks can be implemented using various underlying data structures, including arrays and linked lists. The choice of implementation depends on factors like memory constraints, performance requirements, and the specific application context.
Stack Implementation using Arrays
Reasons to implement stacks using arrays:
- Memory Efficient: Array elements do not hold the next elements address like linked list nodes do.
- Easier to implement and understand: Using arrays to implement stacks require less code than using linked lists, and for this reason it is typically easier to understand as well.
A reason for not using arrays to implement stacks:
- Fixed size: An array occupies a fixed part of the memory. This means that it could take up more memory than needed, or if the array fills up, it cannot hold more elements.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *stack;
int top;
int capacity;
} Stack;
Stack* createStack(int capacity) {
Stack *newStack = (Stack*)malloc(sizeof(Stack));
newStack->stack = (int*)malloc(capacity * sizeof(int));
newStack->top = -1;
newStack->capacity = capacity;
return newStack;
}
void push(Stack *s, int element) {
if (s->top == s->capacity - 1) {
printf("Stack is full\n");
return;
}
s->stack[++s->top] = element;
}
int pop(Stack *s) {
if (s->top == -1) {
printf("Stack is empty\n");
return -1;
}
return s->stack[s->top--];
}
int peek(Stack *s) {
if (s->top == -1) {
printf("Stack is empty\n");
return -1;
}
return s->stack[s->top];
}
int isEmpty(Stack *s) {
return s->top == -1;
}
int size(Stack *s) {
return s->top + 1;
}
void printStack(Stack *s) {
printf("Stack: ");
for (int i = 0; i <= s->top; ++i) {
printf("%c ", s->stack[i]);
}
printf("\n");
}
int main() {
Stack *myStack = createStack(100);
push(myStack, 'A');
push(myStack, 'B');
push(myStack, 'C');
push(myStack, 'D');
// Print initial stack
printStack(myStack);
printf("Pop: %c\n", pop(myStack));
printf("Peek: %c\n", peek(myStack));
printf("isEmpty: %d\n", isEmpty(myStack));
printf("Size: %d\n", size(myStack));
return 0;
}
Output:
Stack: A B C
Pop: D
Peek: C
isEmpty: 0
Size: 3
Code Explanation
1. Include Header Files
#include <stdio.h>
#include <stdlib.h>
stdio.h
: Provides input/output functions likeprintf
.stdlib.h
: Provides memory allocation functions likemalloc
.
2. Define the Stack Structure
typedef struct {
int *stack;
int top;
int capacity;
} Stack;
- A
Stack
structure is defined with three members:stack
: A pointer to an array that stores the stack elements.top
: An integer that tracks the index of the top element in the stack.capacity
: The maximum number of elements the stack can hold.
3. Function: createStack
Stack* createStack(int capacity) {
Stack *newStack = (Stack*)malloc(sizeof(Stack));
newStack->stack = (int*)malloc(capacity * sizeof(int));
newStack->top = -1;
newStack->capacity = capacity;
return newStack;
}
- Purpose: Creates a new stack with a specified capacity.
- Parameters:
capacity
: The maximum number of elements the stack can hold.
- Steps:
- Allocate memory for the
Stack
structure. - Allocate memory for the
stack
array. - Initialize
top
to-1
(indicating an empty stack). - Set the
capacity
of the stack. - Return the newly created stack.
- Allocate memory for the
4. Function: push
void push(Stack *s, int element) {
if (s->top == s->capacity - 1) {
printf("Stack is full\n");
return;
}
s->stack[++s->top] = element;
}
- Purpose: Adds an element to the top of the stack.
- Parameters:
s
: A pointer to the stack.element
: The element to be added.
- Steps:
- Check if the stack is full (
top == capacity - 1
).- If full, print “Stack is full” and return.
- Increment
top
and add the element to the stack.
- Check if the stack is full (
5. Function: pop
int pop(Stack *s) {
if (s->top == -1) {
printf("Stack is empty\n");
return -1;
}
return s->stack[s->top--];
}
- Purpose: Removes and returns the top element from the stack.
- Parameters:
s
: A pointer to the stack.
- Steps:
- Check if the stack is empty (
top == -1
).- If empty, print “Stack is empty” and return
-1
.
- If empty, print “Stack is empty” and return
- Return the top element and decrement
top
.
- Check if the stack is empty (
6. Function: peek
int peek(Stack *s) {
if (s->top == -1) {
printf("Stack is empty\n");
return -1;
}
return s->stack[s->top];
}
- Purpose: Returns the top element of the stack without removing it.
- Parameters:
s
: A pointer to the stack.
- Steps:
- Check if the stack is empty (
top == -1
).- If empty, print “Stack is empty” and return
-1
.
- If empty, print “Stack is empty” and return
- Return the top element.
- Check if the stack is empty (
7. Function: isEmpty
int isEmpty(Stack *s) {
return s->top == -1;
}
- Purpose: Checks if the stack is empty.
- Parameters:
s
: A pointer to the stack.
- Returns:
1
if the stack is empty (top == -1
).0
otherwise.
8. Function: size
int size(Stack *s) {
return s->top + 1;
}
- Purpose: Returns the number of elements in the stack.
- Parameters:
s
: A pointer to the stack.
- Returns:
- The number of elements (
top + 1
).
- The number of elements (
9. Function: printStack
void printStack(Stack *s) {
printf("Stack: ");
for (int i = 0; i <= s->top; ++i) {
printf("%c ", s->stack[i]);
}
printf("\n");
}
- Purpose: Prints all elements in the stack.
- Parameters:
s
: A pointer to the stack.
- Steps:
- Iterate through the stack from index
0
totop
. - Print each element.
- Iterate through the stack from index
10. Main Function
int main() {
Stack *myStack = createStack(100);
push(myStack, 'A');
push(myStack, 'B');
push(myStack, 'C');
push(myStack, 'D');
// Print initial stack
printStack(myStack);
printf("Pop: %c\n", pop(myStack));
printf("Peek: %c\n", peek(myStack));
printf("isEmpty: %d\n", isEmpty(myStack));
printf("Size: %d\n", size(myStack));
return 0;
}
- Steps:
- Create a stack with a capacity of
100
. - Push elements
'A'
,'B'
,'C'
, and'D'
onto the stack. - Print the stack.
- Pop the top element and print it.
- Peek at the new top element and print it.
- Check if the stack is empty and print the result.
- Print the size of the stack.
- Create a stack with a capacity of
Stack Implementation using Linked List
A reason for using linked lists to implement stacks:
- Dynamic size: The stack can grow and shrink dynamically, unlike with arrays.
Reasons for not using linked lists to implement stacks:
- Extra memory: Each stack element must contain the address to the next element (the next linked list node).
- Readability: The code might be harder to read and write for some because it is longer and more complex.
#include <stdio.h>
#include <stdlib.h>
// Define a structure for the node
struct Node {
int data;
struct Node* next;
};
// Define a structure for the stack
struct Stack {
struct Node* top;
};
// Function to initialize the stack
void initialize(struct Stack *stack) {
stack->top = NULL; // Initialize top to NULL to indicate an empty stack
}
// Function to check if the stack is empty
int isEmpty(struct Stack *stack) {
return (stack->top == NULL); // If top is NULL, stack is empty
}
// Function to push an element onto the stack
void push(struct Stack *stack, int item) {
// Create a new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
printf("Memory allocation failed\n");
return;
}
// Assign data to the new node
newNode->data = item;
// Set the next of the new node to the current top
newNode->next = stack->top;
// Move the top to point to the new node
stack->top = newNode;
}
// Function to pop an element from the stack
int pop(struct Stack *stack) {
if (isEmpty(stack)) {
printf("Stack Underflow\n");
return -1; // Return an error value
}
// Retrieve the item at the top of the stack
int item = stack->top->data;
// Store the current top node
struct Node* temp = stack->top;
// Move the top to the next node
stack->top = stack->top->next;
// Free the memory of the popped node
free(temp);
return item; // Return the popped item
}
// Function to peek at the top element of the stack
int peek(struct Stack *stack) {
if (isEmpty(stack)) {
printf("Stack is empty\n");
return -1; // Return an error value
}
return stack->top->data; // Return the item at the top of the stack
}
int main() {
struct Stack stack;
initialize(&stack);
// Push elements onto the stack
push(&stack, 10);
push(&stack, 20);
push(&stack, 30);
// Print the top element of the stack
printf("Top element of stack: %d\n", peek(&stack));
// Pop elements from the stack and print them
printf("Elements popped from stack:\n");
while (!isEmpty(&stack)) {
printf("%d\n", pop(&stack));
}
return 0;
}
Output:
Top element of stack: 30
Elements popped from stack:
30
20
10
Code explanation
1. Define the Node Structure
struct Node {
int data;
struct Node* next;
};
- A
Node
structure is defined with two members:data
: Stores the integer value of the node.next
: A pointer to the next node in the linked list.
2. Define the Stack Structure
struct Stack {
struct Node* top;
};
- A
Stack
structure is defined with one member:top
: A pointer to the top node of the stack.
3. Function: initialize
void initialize(struct Stack *stack) {
stack->top = NULL; // Initialize top to NULL to indicate an empty stack
}
- Purpose: Initializes the stack by setting
top
toNULL
. - Parameters:
stack
: A pointer to the stack.
4. Function: isEmpty
int isEmpty(struct Stack *stack) {
return (stack->top == NULL); // If top is NULL, stack is empty
}
- Purpose: Checks if the stack is empty.
- Parameters:
stack
: A pointer to the stack.
- Returns:
1
if the stack is empty (top == NULL
).0
otherwise.
5. Function: push
void push(struct Stack *stack, int item) {
// Create a new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
printf("Memory allocation failed\n");
return;
}
// Assign data to the new node
newNode->data = item;
// Set the next of the new node to the current top
newNode->next = stack->top;
// Move the top to point to the new node
stack->top = newNode;
}
- Purpose: Adds an element to the top of the stack.
- Parameters:
stack
: A pointer to the stack.item
: The element to be added.
- Steps:
- Allocate memory for a new node.
- Assign
item
to thedata
field of the new node. - Set the
next
of the new node to the currenttop
. - Update
top
to point to the new node.
6. Function: pop
int pop(struct Stack *stack) {
if (isEmpty(stack)) {
printf("Stack Underflow\n");
return -1; // Return an error value
}
// Retrieve the item at the top of the stack
int item = stack->top->data;
// Store the current top node
struct Node* temp = stack->top;
// Move the top to the next node
stack->top = stack->top->next;
// Free the memory of the popped node
free(temp);
return item; // Return the popped item
}
- Purpose: Removes and returns the top element from the stack.
- Parameters:
stack
: A pointer to the stack.
- Steps:
- Check if the stack is empty (
top == NULL
).- If empty, print “Stack Underflow” and return
-1
.
- If empty, print “Stack Underflow” and return
- Retrieve the
data
of the top node. - Store the top node in a temporary pointer.
- Move
top
to the next node. - Free the memory of the popped node.
- Return the retrieved
data
.
- Check if the stack is empty (
7. Function: peek
int peek(struct Stack *stack) {
if (isEmpty(stack)) {
printf("Stack is empty\n");
return -1; // Return an error value
}
return stack->top->data; // Return the item at the top of the stack
}
- Purpose: Returns the top element of the stack without removing it.
- Parameters:
stack
: A pointer to the stack.
- Steps:
- Check if the stack is empty (
top == NULL
).- If empty, print “Stack is empty” and return
-1
.
- If empty, print “Stack is empty” and return
- Return the
data
of the top node.
- Check if the stack is empty (
8. Main Function
int main() {
struct Stack stack;
initialize(&stack);
// Push elements onto the stack
push(&stack, 10);
push(&stack, 20);
push(&stack, 30);
// Print the top element of the stack
printf("Top element of stack: %d\n", peek(&stack));
// Pop elements from the stack and print them
printf("Elements popped from stack:\n");
while (!isEmpty(&stack)) {
printf("%d\n", pop(&stack));
}
return 0;
}
- Steps:
- Initialize the stack.
- Push elements
10
,20
, and30
onto the stack. - Print the top element of the stack (
30
). - Pop all elements from the stack and print them (
30
,20
,10
).