Ngăn xếp
Ngăn xếp là cấu trúc dữ liệu trừu tượng (ADT), thường được sử dụng trong hầu hết các ngôn ngữ lập trình. Nó được đặt tên là stack vì nó hoạt động giống như một ngăn xếp trong thế giới thực, ví dụ - một cỗ bài hoặc một đống đĩa, v.v.
Một ngăn xếp trong thế giới thực chỉ cho phép các hoạt động tại vị trí trên cùng của ngăn xếp. Ví dụ, chúng ta chỉ có thể đặt hoặc thêm một lá bài hay một cái đĩa vào trên cùng của ngăn xếp. Do đó, cấu trúc dữ liệu trừu tượng ngăn xếp chỉ cho phép các thao tác dữ liệu tại vị trí trên cùng. Tại bất cứ thời điểm nào, chúng ta chỉ có thể truy cập phần tử trên cùng của ngăn xếp.
Đặc điểm này làm cho ngăn xếp trở thành cấu trúc dữ liệu dạng LIFO. LIFO là viết tắt của Last-In-First-Out. Ở đây, phần tử được đặt vào (được chèn, được thêm vào) cuối cùng sẽ được truy cập đầu tiên. Trong thuật ngữ ngăn xếp, hoạt động chèn được gọi là hoạt động PUSH và hoạt động xóa được gọi là hoạt động POP.
Mô tả cấu trúc dữ liệu ngăn xếp
Sơ đồ sau mô tả một ngăn xếp và các hoạt động của nó:
Một ngăn xếp có thể được triển khai theo phương thức của Mảng, Cấu trúc, Con trỏ và Danh sách Liên kết. Stack có thể là một kích thước cố định hoặc nó có thể có ý nghĩa thay đổi kích thước. Phần dưới chúng ta sẽ triển khai ngăn xếp bởi sử dụng các mảng với việc triển khai các ngăn xếp cố định.
Hoạt động cơ bản
Các hoạt động ngăn xếp có thể liên quan đến việc khởi tạo ngăn xếp, sử dụng nó và sau đó xóa nó. Ngoài những thứ cơ bản này, một ngăn xếp được sử dụng cho hai thao tác chính sau:
- push () - Đẩy (lưu trữ) một phần tử trên ngăn xếp.
- pop () - Loại bỏ (truy cập) một phần tử khỏi ngăn xếp.
Khi dữ liệu đã được PUSH lên trên ngăn xếp:
Để sử dụng stack một cách hiệu quả, chúng ta cũng cần kiểm tra trạng thái của stack. Để phục vụ cho mục đích này, dưới đây là một số tính năng hỗ trợ khác của ngăn xếp:
- peek () - lấy phần tử ở trên cùng của ngăn xếp mà không xóa nó.
- isFull () - kiểm tra xem ngăn xếp đã đầy chưa.
- isEmpty () - kiểm tra xem stack có trống không.
Tại mọi thời điểm, chúng ta duy trì một con trỏ tới phần tử dữ liệu vừa được PUSH cuối cùng vào trên ngăn xếp. Vì con trỏ này luôn đại diện cho đỉnh của ngăn xếp, do đó được đặt tên là top . Con trỏ top cung cấp giá trị của phần tử trên cùng của ngăn xếp mà không thực sự loại bỏ nó.
Trước tiên chúng ta nên tìm hiểu về các thủ tục để hỗ trợ các chức năng ngăn xếp:
peek()
Giải thuật của hàm peek():
begin procedure peek
return stack[top]
end procedure
Triển khai hàm peek() trong ngôn ngữ C:
Ví dụ:
int peek() {
return stack[top];
}
isfull()
Giải thuật của hàm isfull():
begin procedure isfull
if top equals to MAXSIZE
return true
else
return false
endif
end procedure
Triển khai hàm isfull() trong ngôn ngữ C:
Example
bool isfull() {
if(top == MAXSIZE)
return true;
else
return false;
}
isempty()
Giải thuật của hàm isempty():
begin procedure isempty
if top less than 1
return true
else
return false
endif
end procedure
Sự triển khai của hàm isempty() trong ngôn ngữ C sẽ hơi khác một chút. Chúng ta khởi tạo top từ -1, giống như chỉ mục của mảng bắt đầu từ số 0. Vì thế, chúng ta kiểm tra nếu top là dưới 0 hoặc -1 để xác định thêm stack có trống hay không. Dưới đây là đoạn mã:
Ví dụ:
bool isempty() {
if(top == -1)
return true;
else
return false;
}
Hoạt động Push
Quá trình đưa một phần tử dữ liệu mới vào ngăn xếp được gọi là thao tác push. Hoạt động push bao gồm một loạt các bước:
- Bước 1 - Kiểm tra xem ngăn xếp đã đầy chưa.
- Bước 2 - Nếu ngăn xếp đầy, tiến trình bị lỗi và thoát.
- Bước 3 - Nếu ngăn xếp không đầy, hãy tăng từ top để trỏ tới phần tử bộ nhớ trống tiếp theo.
- Bước 4 - Thêm phần tử dữ liệu vào vị trí ngăn xếp, nơi mà top đang trỏ đến trên ngăn xếp
- Bước 5 - Trả về thành công.
Nếu danh sách liên kết được sử dụng để thực hiện ngăn xếp, thì trong bước 3, chúng ta cần cấp phát một không gian động.
Thuật toán cho hoạt động PUSH
Một thuật toán đơn giản cho hoạt động Push có thể được bắt đầu như sau -
begin procedure push: stack, data
if stack is full
return null
endif
top ← top + 1
stack[top] ← data
end procedure
Thực hiện thuật toán này trong C, rất dễ dàng. Xem mã sau -
Thí dụ
void push(int data) {
if(!isFull()) {
top = top + 1;
stack[top] = data;
} else {
printf("Could not insert data, Stack is full.\n");
}
}
Hoạt động Pop
Việc truy cập nội dung phần tử trong khi xóa nó từ ngăn xếp còn được gọi là Hoạt động POP. Trong một triển khai mảng của hoạt động pop (), phần tử dữ liệu không thực sự bị loại bỏ, thay vào đó top sẽ bị giảm về vị trí thấp hơn trong ngăn xếp để trỏ tới giá trị tiếp theo. Nhưng trong sự triển khai Danh sách liên kết, hoạt động pop() thực sụ xóa phần tử xữ liệu và xóa nó khỏi không gian bộ nhớ.
Hoạt động POP có thể bao gồm các bước sau:
- Bước 1: kiểm tra xem ngăn xếp là trống hay không.
- Bước 2: nếu ngăn xếp là trống, tiến trình bị lỗi và thoát ra.
- Bước 3: nếu ngăn xếp là không trống, truy cập phần tử dữ liệu tại top đang trỏ tới.
- Bước 4: giảm giá trị của top đi 1.
- Bước 5: trả về thành công.
Thuật toán cho hoạt động Pop
Một thuật toán đơn giản cho hoạt động Pop có thể được bắt đầu như sau:
begin procedure pop: stack
if stack is empty
return null
endif
data ← stack[top]
top ← top - 1
return data
end procedure
Việc thực hiện thuật toán này trong C, như sau -
Thí dụ
int pop(int data) {
if(!isempty()) {
data = stack[top];
top = top - 1;
return data;
} else {
printf("Could not retrieve data, Stack is empty.\n");
}
}
- Hiếu Kiều -