Ngăn xếp là kiểu dữ liệu tuyến tính mà phép bổ sung hay loại bỏ phần tử luôn được thực hiện ở 1 đầu gọi là đỉnh của ngăn xếp.
Ngăn xếp hoạt động dựa trên nguyên tắc vào sau ra trước.
Hai thao tác thường gặp với ngăn xếp là thêm một nút vào đỉnh vào đỉnh ngăn xếp (push) và loại bỏ một nút (pop) tại đỉnh ngăn xếp. Khi thêm một nút vào đỉnh ngăn xếp thì ta phải kiểm tra xem ngăn xếp đã đầy hay chưa. Khi loại bỏ một nút tại đỉnh ngăn xếp ta phải kiểm tra xem ngăn xếp có rỗng hay không.
Có thể lưu trữ ngăn xếp dưới dạng một vector S gồm n phần tử liên tiếp nhau. Nếu T là địa chỉ của phần tử đỉnh stack thì T có giá trị biến đổi khi stack hoạt động. Ta gọi phần tử đầu tiên của ngăn xếp là phần tử thứ 0, như vậy stack rỗng khi T có giá trị nhỏ hơn 0, ta quy ước là -1. Stack tràn khi T có giá trị là n-1.Mỗi khi 1 phần tử được thêm vào stack thì T tăng lên 1 đơn vị và mỗi khi loại bỏ 1 phần tử khỏi stack thì giá trị của T giảm 1 đơn vị.
Hình 3.1. Ngăn xếp
Để khai báo một ngăn xếp chúng ta có thể sử dụng mảng một chiều, phần tử thứ 0 là đáy stack, phần tử cuối là đỉnh stack. Một stack tổng quát là một cấu trúc gồm 2 trường: trường top là một số nguyên chỉ đỉnh stack, trường node là một mảng một chiều gồm MAX phần tử trong đó mỗi phần tử là một nút của stack. Một nút của stack có thể là một biến đơn hoặc một cấu trúc phản ánh tập thông tin về nút hiện tại. Ví dụ, khai báo các stack để lưu trữ các số nguyên:
# define MAX 100; typedef struct{
int top;
int nodes[MAX]; }stack;
Các thao tác làm việc với stack:
Khi khai báo stack sử dụng danh sách tuyến tính, chúng ta cần định nghĩa MAX đủ lớn để lưu trữ được mọi phần tử của stack. Một stack đã bị tràn thì không thể thêm một phần tử mới vào stack; một stack rỗng thì không thể loại bỏ phần tử khỏi stack.
Vì vậy, chúng ta cần kiểm tra xem stack có bị tràn hoặc rỗng hay không. Thao tác Empty: Kiểm tra xem stack có rỗng hay không
Thao tác Push: Thêm nút mới x vào đỉnh stack và thay đổi đỉnh stack Thao tác Pop: Loại bỏ nút tại đỉnh stack
Cài đặt minh họa stack bằng mảng: #include <stdlib.h>
#include <stdio.h>
#define Max 100 //so phan tu toi da cua Stack typedef int item; //kieu du lieu cua Stack struct Stack
{
int Top; //Dinh Top
item Data[Max]; //Mang cac phan tu };
void Init (Stack &S); //khoi tao Stack rong int Isempty(Stack S); //kiem tra Stack rong int Isfull(Stack S); //kiem tra Stack day
void Push(Stack &S, item x); //them phan tu vao Stack
int Peak(Stack S); //Lay phan tu o dau Stack nhung khong xoa int Pop(Stack &S); //Loai bo phan tu khoi Stack
void Input (Stack &S); //Nhap Stack void Output(Stack S); //Xuat Stack
void Init (Stack &S) //khoi tao Stack rong {
S.Top = 0; //Stack rong khi Top la 0 }
int Isempty(Stack S) //kiem tra Stack rong {
return (S.Top == 0); }
int Isfull(Stack S) //kiem tra Stack day {
return (S.Top == Max); // }
void Push(Stack &S, item x) //them phan tu vao Stack {
if (!Isfull(S)) {
S.Data[S.Top] = x; //Gan du lieu S.Top ++; //Tang Top len 1 }
}
int Peak(Stack S) //Lay phan tu o dau Stack nhung khong xoa {
return S.Data[S.Top-1]; //Lay du lieu tai Top }
int Pop(Stack &S) //Loai bo phan tu khoi Stack {
if (!Isempty(S)) {
S.Top --; //Giam Top
return S.Data[S.Top]; //Lay du lieu tai Top }
}
void Input (Stack &S) {
int n; item x; do {
printf("Nhap so phan tu cua Stack (<%d) :",Max); scanf("%d",&n);
for (int i=0; i<n; i++) {
printf("Nhap phan tu thu %d : ", i+1); scanf("%d",&x); Push(S,x); } } void Output(Stack S) {
for (int i=S.Top-1; i>=0; i--) printf("%d ",S.Data[i]); printf("\n"); } int main() { Stack S; Init(S); Input(S); Output(S); int lua_chon;
printf("Moi ban chon phep toan voi DS LKD:"); printf("\n1: Kiem tra Stack rong");
printf("\n2: Kiem tra Stack day"); printf("\n3: Them phan tu vao Stack"); printf("\n4: Xoa phan tu trong Stack"); printf("\n5: Xuat Stack");
printf("\n6: Thoat"); do { printf("\nBan chon: "); scanf("%d",&lua_chon); switch (lua_chon) { case 1: {
if (Isempty(S)) printf("Stack rong !"); else printf ("Stack khong rong !"); break;
} case 2:
{
if (Isfull(S)) printf("Stack day !"); else printf ("Stack chua day !"); break;
} case 3: {
item x;
printf ("Nhap phan tu can chen vao DS: "); scanf("%d",&x); Push(S,x); break; } case 4: { Pop(S); break; } case 5: { Output(S); break; } case 6: break; } }while (lua_chon !=6); return 0; }
Cài đặt minh họa stack bằng danh sách móc nối: #include <stdlib.h>
#include <stdio.h>
typedef int item; //kieu du lieu struct Node
{
item Data; //du lieu Node *Next; //link };
{
Node *Top; };
void Init (Stack &S); //khoi tao Stack rong int Isempty(Stack S); //kiem tra Stack rong int Len (Stack S); //Do dai Stack
void Push(Stack &S, item x); //them phan tu vao Stack
int Peak(Stack S); //Lay phan tu o dau Stack nhung khong xoa int Pop(Stack &S); //Loai bo phan tu khoi Stack
void Input (Stack &S); //Nhap Stack void Output(Stack S); //Xuat Stack Node *MakeNode(item x); //Tao 1 Node
void Init (Stack &S) //khoi tao Stack rong {
S.Top = NULL; }
int Isempty(Stack S) //kiem tra Stack rong {
return (S.Top == NULL); }
int Len (Stack S) {
Node *P = S.Top; int i=0;
while (P != NULL) //trong khi chua het Stack thi van duyet { i++; P = P->Next; } return i; }
Node *MakeNode(item x) //tao 1 Node {
Node *P = (Node*) malloc(sizeof(Node)); P->Next = NULL;
P->Data = x; return P; }
void Push(Stack &S, item x) //them phan tu vao Stack { Node *P = MakeNode(x); P->Next = S.Top; S.Top = P; }
int Peak(Stack S) //Lay phan tu o dau Stack nhung khong xoa {
return S.Top->Data; }
int Pop(Stack &S) //Loai bo phan tu khoi Stack {
if (!Isempty(S)) {
item x = S.Top->Data; //luu lai gia tri S.Top = S.Top->Next; //Xoa phan tu Top return x;
} }
void Input (Stack &S) //nhap danh sach { int i=0; item x; do { i++;
printf ("Nhap phan tu thu %d : ",i); scanf("%d",&x);
if (x != 0) Push(S,x);
} while(x != 0); //nhap 0 de ket thuc } void Output(Stack S) { Node *P = S.Top; while (P != NULL) { printf("%d ",P->Data); P = P->Next;
} printf("\n"); } int main() { Stack S; Init(S); Input(S); Output(S); int lua_chon;
printf("Moi ban chon phep toan voi DS LKD:"); printf("\n1: Kiem tra Stack rong");
printf("\n2: Do dai Stack");
printf("\n3: Them phan tu vao Stack"); printf("\n4: Xoa phan tu trong Stack"); printf("\n5: Xuat Stack");
printf("\n6: Thoat"); do { printf("\nBan chon: "); scanf("%d",&lua_chon); switch (lua_chon) { case 1: {
if (Isempty(S)) printf("Stack rong !"); else printf ("Stack khong rong !"); break;
} case 2: {
printf("Do dai Stack: %d",Len(S)); break;
} case 3: {
item x;
printf ("Nhap phan tu can chen vao DS: "); scanf("%d",&x);
Push(S,x); break;
} case 4: { Pop(S); break; } case 5: { Output(S); break; } case 6: break; } }while (lua_chon !=6); return 0; }
Sử dụng stack có sẵn trong thư viện C++:
#include <iostream> // io #include <stack> // use stack
using namespace std;
int main() {
stack <int> S; // khai bao Stack voi kieu du lieu la int
for (int i = 0; i < 10; i++) {
S.push(i*78 + 26); // chen cac phan tu vao stack }
cout << "Do dai stack: " << S.size() << "\n";
// xuat tat ca phan tu trong stack
while (!S.empty()) { // trong khi stack chua trong int x = S.top(); // lay gia tri top
S.pop(); // loai bo khoi stack cout << x << " ";
cout << "\n";
return 0; }
Ứng dụng của stack:
Stack được áp dụng để biểu diễn nhiều thuật toán phức tạp, đặc biệt là các thuật toán có sử dụng lời gọi đệ qui. Dưới đây là các ví dụ điển hình sử dụng stack:
Đảo ngược xâu ký tự
Chuyển đổi từ hệ thập phân sang cơ số bất kỳ Tính giá trị biểu thức hậu tố