Tải bản đầy đủ (.docx) (15 trang)

thảo luận cấu trúc dữ liệu và giải thuật, đề tài ứng dụng của stack ngăn xếp

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (567.74 KB, 15 trang )

Đề tài: Ứng dụng của Stack- Ngăn xếp
Phần I: Giới thiệu về ngăn xếp
Khái niệm

1.

Ngăn xếp là một dạng đặc biệt của danh sách mà việc bổ sung hay loại bỏ một phần
tử đều được thực hiện ở một đầu của danh sách gọi là đỉnh. Nói cách khác, ngăn xếp là
một cấu trúc dữ liệu có 2 thao tác cơ bản: bổ sung (push) và loại bỏ (pop), trong đó loại
bỏ sẽ tiến hành loại phần tử mới nhất được đưa vào danh sách. Chính vì tính chất này mà
ngăn xếp còn được gọi kiểu dữ liệu có nguyên tắc LIFO (Last in first out – vào sau ra
trước)
2.

Các tác vụ trên ngăn xếp
a) Initialize
Chức năng: Khởi động ngăn xếp
Dữ liệu nhập: Không
Dữ liệu xuất: stack top về vị trí khởi đầu.
b)

Empty

Chức năng kiểm tra ngăn xếp có bị rỗng không.
Dữ liệu nhập: Không
Dữ liệu xuất: True or False (True: khi ngăn xếp rỗng, False: ngăn xếp không bị
rỗng).
c)

Pusth


Chức năng: thêm nút mới tại đỉnh ngăn xếp
Dữ liệu nhập: nút mới.
Dữ liệu xuất: không
d)

Pop

Chức năng: xóa nút tại đỉnh ngăn xếp.
Dữ liệu nhập: Không.
Điều kiện: stack không bị rỗng.
1


Dữ liệu xuất: nút bị xóa.
Stacktop:

e)

Chức năng: truy xuất nút tại đỉnh ngăn xếp.
Dữ liệu nhập: Không.
Điều kiện: stack không bị rỗng.
Dữ liệu xuất: nút tại đỉnh ngăn xếp.
Stacksize

f)

Chức năng: xác định số nút hiện có trong ngăn xếp.
Dữ liệu: Không.
Dữ liệu xuất: số nút hiện có trong ngăn xếp
Clearstack


g)

Chức năng: xóa tất cả các nút ở trong ngăn xếp.
Dữ liệu nhập: không.
Dữ liệu xuất:stack top về vị trí khởi đầu.
h)

Copystack:

Chức năng: copy ngăn xếp thành ngăn xếp mới.
Dữ liệu nhập: stack nguồn.
Dữ liệu xuất: ngăn xếp mới giống ngăn xếp cũ.

3.

Phương pháp cài đặt ngăn xếp

Có rất nhiều cách cài đặt một ngăn xếp nhưng đơn giản cũng như để dễ hình dung nhất
là cài đặt bằng mảng hay còn gọi là cài đặt theo kiểu kế tiếp. Ngoài ra còn nhiều cách cài
đặt khác như cài đặt bằng Danh sách liên kết (DSLK đơn, DSLK vòng, DSLK kép,
DSLK vòng+kép).

2


Phần II: Ứng dụng ngăn xếp vào bài toán cụ thể- Bài toán sửa kho tàu
1.

Mô tả bài toán

Xét mạng đường sắt sau đây:

Các toa tàu ở đường ray A bên phải (được đánh số 1, 2, ..., n) cần phải hoán vị
chuyển sang đường ray B bên trái. B được xem như đầu ra của các toa tàu, còn A được
xem là đầu vào. Một toa có thể chuyển thẳng sang đường ray bên trái, hay nó có thể rẽ
xuống đường ray bên cạnh (để sửa chữa) để sau này sẽ đi ra đường ray bên trái. Các toa
tàu không được phép đi ngược chiều.
Cho trước một hoán vị toa tàu ở đầu ra B. Hãy cho biết liệu hoán vị đó có xảy ra
hay không.
Ví dụ: Ở đầu vào, có 4 toa tàu, ở đầu ra các toa tàu theo thứ tự là 3, 1, 4, 2. Hoán vị
này không thể xảy ra. Vì toa đầu tiên là toa 3, điều này chứng tỏ nó đi thẳng ra đầu ra B,
còn các toa 1 và 2 được chuyển vào kho. Khi ra khỏi kho thì toa 2 phải ra trước nghĩa là
phải có thứ tự 2 trước 1. Điều này mâu thuẫn với thứ tự 2 sau 1 trong hoán vị 3, 1, 4, 2.
2.

Ý tưởng của bài toán

Bài toán cần kiểm tra tính hợp lệ của hoán vị toa tàu ở đường ray ra, dãy các toa ở
đường ray vào mặc định là dãy 1, 2, ..., n theo thứ tự từ trái qua phải.
- Gọi (b) = {b1, b2, ..., bn} là dãy toa tàu ở đường ray vào, thì bi = i với i = 1, 2, ...,n.
- Gọi (a) = {a1, a2, ..., an} là dãy các toa tàu ở đường ray ra. Việc kiểm tra tính hợp
lệ của dãy (a) như sau:
Lần lượt xét các toa tàu ai ở đường ray ra theo chiều từ trái sang phải, nghĩa là ităng
dần từ 1, 2, ..., đến n.
- Với mỗi toa ai ta tìm xem nó có trong đường ray vào không.
- Nếu ai có trong (b) thì mọi toa tàu d có có chỉ số nhỏ hơn ai chắc chắn đã được
đưa vào kho sửa chữa, ví dụ với n = 5, nếu a 1 = 4 thì chắc chắn các toa 1, 2, 3 đã được
đưa vào kho sửa chữa. Khi đó ta đưa tất cả các toa d này vào kho (tức là đẩy chúng vào
một ngăn xếp), trước khi xét toa tầu tiếp theo ở đường rayra
- Nếu ai không có trong (b) thì chắc chắn nó phải ở trong kho, hơn nữa phải ở vị trí cửa

kho sửa chữa (đỉnh ngăn xếp). Nếu ai có ở vị trí cửa kho thì ta “lấy nó ra” khỏi kho, nếu
3


ngược lại thì chứng tỏ dãy (a) là dãy hoán vị không hợp lệ tại i, và đây là dấu hiệu duy
nhất để kiểm tra một dãy (a) có hợp lệ hay không.
3.

Thuật toán

Bước 1: nhập số toa tàu, nhập hoán vị đầu ra cho trước b[i], đầu vào a[i] đánh STT
1…n.
Bước 2: Nếu stack có phần tử thì so sánh với phần tử của mảng b đang xét
2.1 i=1
2.2 Nếu phần tử x ở đỉnh của stack = b[i] đang xét: chuyển 2.3, ngược lại tới 2.7
2.3 c[i]=b[i]
2.4 in ra toa này được chuyển từ kho ra đường ray ra C
2.5 tăng i thêm 1;
2.6 kiểm tra ngăn xếp. Nếu ngăn xếp rỗng chuyển bước 3, ngược lại chuyển bước 2.2
2.7 Dừng lại.
Bước 3: Nếu stack k có phần tử thì lần lượt kiểm tra các phần tử trong mảng đầu vào.
3.1 j=1
3.2 Nếu a[j] = b[i], tới 3.3, ngược lại tới 3.7
3.3 c[i] = b[i];
3.4 In cách dịch chuyển toa này: từ đường ray vào A đến đường ray ra C.
3.5 Tăng j : j++
3.6 Kiểm tra j3.7 Đưa a[j] vào stack.
3.8 In cách dịch chuyển toa này: từ đường ray vào A đến đường ray D
Bước 4: Sau khi duyệt hết các phần tử trong b mà ngăn xếp vẫn còn phần tử, in ra

không chuyển được nữa, hoán vị không xảy ra, ngược lại nếu ngăn xếp rỗng tới bước 5.
Bước 5: In ra: hoán vị có thể xảy ra.
4


4.

Sơ đồ khối

5


5.

Chương trình

Sử dụng phần mềm Cfree để chạy chương trình (chương trình được lưu bằng file
CPP đính kèm)
#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<iostream>

#define MAX 1000
#define TRUE 1
#define FALSE 0

int n;
int j, found;
int P[MAX], B[MAX];

int *b;

// Cai dat stack bang mang
typedef struct {
int top;
int d[MAX];
}stack;

// Khoi tao stack
void stackInitialize( stack *s)
6


{
s->top = - 1;
return;
}

// Kiem tra ngan xep rong
int stackEmpty( stack *s)
{
if(s->top == -1) return 1;
return 0;
}

// Them phan tu vao ngan xep
int push(stack *s, int x) {
s->top = (s->top) + 1;
s->d[s->top] = x;
return s->d[s->top];

}

// Lay 1 phan tu ra khoi ngan xep
int pop(stack *s) {
return(s->d[s->top--]);
}

7


// Ham kiem tra hoan vi co xay ra hay khong
void KiemTra() {
stack s;
s.top = -1;
int *a, *c;
int i, j, count, found, x;
count = 1; found = 0;
a = (int*)malloc((n+1)*sizeof(int));
c = (int*)malloc((n+1)*sizeof(int));
printf("\n Ta chuyen lan luot roi dua ra thong bao hoan vi co xay ra hay
khong.\n ");
for(i = 1; i <= n; i++)
a[i] = i;
for(i = 1; i <= n; i++) {
while(!stackEmpty(&s)) {
x = s.d[s.top];
if(x == b[i]) {
c[i] = b[i];
printf(" chuyen tu D sang C");
pop(&s);

i++;
}
else break;

}
8


for(j = count; j <= n; j++) {
if(a[j] == b[i]) {
c[i] = b[i];
printf(" chuyen tu A sang C");
count ++;

break;
}
else {
push(&s, a[j]);
printf(" chuyen tu A sang D");
count ++;
}

}
}
if ( (count > n) &&(!stackEmpty(&s)) ) {
printf(" Hoan vi khong xay ra!");
}
if ( (count > n) &&(stackEmpty(&s)) ) printf(" Hoan vi co xay ra!");
free(a); free(c);
getch();

9


}

/// Ham kiem tra phuc vu cho viec liet ke cac hoan vi co the xay ra
void KiemTraHoanVi() {
stack s;
s.top = -1;
int *a, *c;
int i, j, count, x;
count = 1; found = 0;
a = (int*)malloc((n+1)*sizeof(int));
c = (int*)malloc((n+1)*sizeof(int));
for(i = 1; i <= n; i++)
a[i] = i;
for(i = 1; i <= n; i++) {
while(!stackEmpty(&s)) {
x = s.d[s.top];
if(x == b[i]) {
c[i] = b[i];
pop(&s);
i++;
}
else break;

}
10



for(j = count; j <= n; j++) {
if(a[j] == b[i]) {
c[i] = b[i];
count ++;
break;
}
else {
push(&s, a[j]);
count ++;
}
}
}
if ( (count > n) &&(!stackEmpty(&s)) ) {
found = FALSE;
}
if ( (count > n) &&(stackEmpty(&s)) ) found = TRUE;
free(a); free(c);
}
/// Dua ra cac hoan vi
void result() {
int i;
b = (int*)malloc((n+1)*sizeof(int));
for(i = 1; i <= n; i++)
b[i] = P[i];
11


KiemTraHoanVi();
if(found == TRUE) {
for(i = 1; i <= n; i++) printf("%3d", b[i]);

printf("\n");
}
free(b);
}

/// Ham phuc vu sinh hoan vi
void Try(int i) {
int j;
for(j = 1; j <= n; j++) {
if(B[j]) {
P[i] = j;
B[j] = FALSE;
if(i == n) result();
else Try(i + 1);
B[j] = TRUE;
}
}
}

void Cackhanang(){
12


for(int i = 1; i <= n; i++) B[i] = TRUE;
Try(1);
getch();
}

main() {
int ch;

printf("\n So toa tau n = ");
scanf("%d", &n);
printf("\nChon 1 trong 3 chuc nang: \n");
printf("\nChon phim 1 neu muon kiem tra 1 hoan vi la co xay ra hay ko");
printf("\nChon phim 2 neu muon dua ra tat ca hoan vi co the xay ra.");
printf("\nChon phim 3 de thoat khoi chuong trinh.\n");
while(1) {
printf("\nChon chuc nang: "); scanf("%d", &ch);
// <ul>
switch(ch) {
case 1:
b = (int*)malloc((n+1)*sizeof(int));
printf("\n Nhap thu tu can tao: \n");
fflush(stdin);
for(int i = 1; i <= n; i++) {
printf("\n b[%d] = ", i);
13


scanf("%d", &b[i]);
}
KiemTra();
free(b);break;
case 2:
printf("\n Cac hoan vi co the tao thanh la: \n");
Cackhanang();break;
case 3:
exit(0);
default:
printf("\n Chuc nang ban chon ko co. Xin chon lai");

getch();
}
}
}

14


6.

Demo chương trình

15



×