2.1. Cấu trúc dữ liệu ngăn xếp
Một ngăn xếp là một cấu trúc dữ liệu tuyến tính tuân theo nguyên tắc Vào sau ra trước (LIFO). Điều này có nghĩa là phần tử cuối cùng được chèn vào bên trong ngăn xếp sẽ được lấy ra trước.
Bạn có thể nghĩ về cấu trúc dữ liệu ngăn xếp như một chồng đĩa chồng lên nhau.
Biểu diễn ngăn xếp tương tự như một đống đĩa
Ở đây, bạn có thể:
Và nếu bạn muốn có đĩa ở dưới cùng, trước tiên bạn phải loại bỏ tất cả các đĩa ở trên cùng. Đây chính xác là cách cấu trúc dữ liệu ngăn xếp hoạt động.
2.1.1.Nguyên lý LIFO của ngăn xếp
Trong thuật ngữ lập trình, việc đặt một phần tử lên đầu ngăn xếp được gọi là Push (Đẩy) và việc xóa một phần tử được gọi là Pop (Xoá).
Các thao tác đẩy và bật ngăn xếp
Trong hình ảnh trên, mặc dù mục 3 được giữ lại cuối cùng, nhưng nó đã bị xóa đầu tiên. Đây chính xác là cách Nguyên tắc LIFO (Vào sau ra trước) hoạt động.
Chúng ta có thể triển khai ngăn xếp trong bất kỳ ngôn ngữ lập trình nào như C, C++, Java, Python hoặc C#, nhưng thông số kỹ thuật thì khá giống nhau.
2.1.2.Các hoạt động cơ bản của Ngăn xếp:
Có một số thao tác cơ bản cho phép chúng ta thực hiện các hành động khác nhau trên một ngăn xếp.
2.1.3.Hoạt động của cấu trúc dữ liệu ngăn xếp
Các hoạt động diễn ra như sau:
Hoạt động của cấu trúc dữ liệu ngăn xếp
2.1.4. Triển khai Ngăn xếp trong Python, Java, C và C++
Python
# Stack implementation in python
# Creating a stack
def create_stack():
stack = []
return stack
# Creating an empty stack
def check_empty(stack):
return len(stack) == 0
# Adding items into the stack
def push(stack, item):
stack.append(item)
print("pushed item: " + item)
# Removing an element from the stack
def pop(stack):
if (check_empty(stack)):
return "stack is empty"
return stack.pop()
stack = create_stack()
push(stack, str(1))
push(stack, str(2))
push(stack, str(3))
push(stack, str(4))
print("popped item: " + pop(stack))
print("stack after popping an element: " + str(stack))
Java
// Stack implementation in Java
class Stack {
private int arr[];
private int top;
private int capacity;
// Creating a stack
Stack(int size) {
arr = new int[size];
capacity = size;
top = -1;
}
// Add elements into stack
public void push(int x) {
if (isFull()) {
System.out.println("OverFlow\nProgram Terminated\n");
System.exit(1);
}
System.out.println("Inserting " + x);
arr[++top] = x;
}
// Remove element from stack
public int pop() {
if (isEmpty()) {
System.out.println("STACK EMPTY");
System.exit(1);
}
return arr[top--];
}
// Utility function to return the size of the stack
public int size() {
return top + 1;
}
// Check if the stack is empty
public Boolean isEmpty() {
return top == -1;
}
// Check if the stack is full
public Boolean isFull() {
return top == capacity - 1;
}
public void printStack() {
for (int i = 0; i <= top; i++) {
System.out.println(arr[i]);
}
}
public static void main(String[] args) {
Stack stack = new Stack(5);
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
stack.pop();
System.out.println("\nAfter popping out");
stack.printStack();
}
}
#C
// Stack implementation in C
#include <stdio.h>
#include <stdlib.h>
#define MAX 10
int count = 0;
// Creating a stack
struct stack {
int items[MAX];
int top;
};
typedef struct stack st;
void createEmptyStack(st *s) {
s->top = -1;
}
// Check if the stack is full
int isfull(st *s) {
if (s->top == MAX - 1)
return 1;
else
return 0;
}
// Check if the stack is empty
int isempty(st *s) {
if (s->top == -1)
return 1;
else
return 0;
}
// Add elements into stack
void push(st *s, int newitem) {
if (isfull(s)) {
printf("STACK FULL");
} else {
s->top++;
s->items[s->top] = newitem;
}
count++;
}
// Remove element from stack
void pop(st *s) {
if (isempty(s)) {
printf("\n STACK EMPTY \n");
} else {
printf("Item popped= %d", s->items[s->top]);
s->top--;
}
count--;
printf("\n");
}
// Print elements of stack
void printStack(st *s) {
printf("Stack: ");
for (int i = 0; i < count; i++) {
printf("%d ", s->items[i]);
}
printf("\n");
}
// Driver code
int main() {
int ch;
st *s = (st *)malloc(sizeof(st));
createEmptyStack(s);
push(s, 1);
push(s, 2);
push(s, 3);
push(s, 4);
printStack(s);
pop(s);
printf("\nAfter popping out\n");
printStack(s);
}
#C++
// Stack implementation in C++
#include <stdlib.h>
#include <iostream>
using namespace std;
#define MAX 10
int size = 0;
// Creating a stack
struct stack {
int items[MAX];
int top;
};
typedef struct stack st;
void createEmptyStack(st *s) {
s->top = -1;
}
// Check if the stack is full
int isfull(st *s) {
if (s->top == MAX - 1)
return 1;
else
return 0;
}
// Check if the stack is empty
int isempty(st *s) {
if (s->top == -1)
return 1;
else
return 0;
}
// Add elements into stack
void push(st *s, int newitem) {
if (isfull(s)) {
cout << "STACK FULL";
} else {
s->top++;
s->items[s->top] = newitem;
}
size++;
}
// Remove element from stack
void pop(st *s) {
if (isempty(s)) {
cout << "\n STACK EMPTY \n";
} else {
cout << "Item popped= " << s->items[s->top];
s->top--;
}
size--;
cout << endl;
}
// Print elements of stack
void printStack(st *s) {
printf("Stack: ");
for (int i = 0; i < size; i++) {
cout << s->items[i] << " ";
}
cout << endl;
}
// Driver code
int main() {
int ch;
st *s = (st *)malloc(sizeof(st));
createEmptyStack(s);
push(s, 1);
push(s, 2);
push(s, 3);
push(s, 4);
printStack(s);
pop(s);
cout << "\nAfter popping out\n";
printStack(s);
}
Độ phức tạp của thời gian ngăn xếp
Đối với việc triển khai ngăn xếp dựa trên mảng, các thao tác đẩy và lấy ra mất thời gian không đổi, tức là O(1).
Ứng dụng của cấu trúc dữ liệu ngăn xếp
Mặc dù stack là một cấu trúc dữ liệu đơn giản để triển khai, nhưng nó rất mạnh mẽ. Những cách sử dụng phổ biến nhất của stack là:
ĐỌC CHƯƠNG I CẤU TRÚC DỮ LIỆU & THUẬT TOÁN TẠI ĐÂY :
1.Cấu trúc dữ liệu và thuật toán -CHƯƠNG I :Giới thiệu DSA
2.Cấu trúc dữ liệu và thuật toán -CHƯƠNG I :Giới thiệu DSA (tiếp theo...)
3.Cấu trúc dữ liệu và thuật toán -CHƯƠNG I :Giới thiệu DSA (Phần 3...)