1. Trang chủ
  2. » Luận Văn - Báo Cáo

Bài tiểu luận ứng dụng ngăn xếp (stack) và hàng đợi (queue) để viết chương trình biến đổi biểu thức trung tố thành tiền tố và hậu tố

25 1,6K 1

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 25
Dung lượng 139,9 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Thông thường, một cấu trúc dữ liệu được chọn cẩn thận sẽ cho phép thực hiện thuật toán hiệu quả hơn.. Một cấu trúc dữ liệu được thiết kế tốt cho phép thực hiện nhiều phép toán, sử dụng c

Trang 1

Mục lục

Mục lục 1

Phần I: Mở đầu 2

I Giới thiệu đề tài 2

II Mục đích yêu cầu của đề bài 2

1 Mục đích 2

2 Yêu cầu 3

III Phương pháp nghiên cứu 3

Phần II: Nội dung 3

I Ngăn xếp (Stack) 3

II Hàng đợi (Queue) 4

III Ứng dụng của Stack và Queue trong ký pháp Ba Lan 4

1 Khái niệm: 4

2 Chuyển đổi dạng Infix(trung tố) sang Postfix(hậu tố) 5

3 Tính giá trị biểu thức dạng Postfix(hậu tố) 6

4 Chuyển đổi dạng Infix(trung tố) sang Prefix(tiền tố) 7

5 Tình giá trị biểu thức dạng Prefix(tiền tố) 8

IV Chương trình đầy đủ 9

Phần III: Kết luận 24

TÀI LIỆU THAM KHẢO 25

Trang 2

Phần I: Mở đầu

I Giới thiệu đề tài

Trong khoa học máy tính, cấu trúc dữ liệu là cách lưu dữ liệu trong máy

tính sao cho nó có thể được sử dụng một cách hiệu quả Thông thường, một cấu trúc dữ liệu được chọn cẩn thận sẽ cho phép thực hiện thuật toán hiệu quả hơn

Việc chọn cấu trúc dữ liệu thường bắt đầu từ chọn một cấu trúc dữ liệu trừu

tượng Một cấu trúc dữ liệu được thiết kế tốt cho phép thực hiện nhiều phép toán,

sử dụng càng ít tài nguyên, thời gian xử lý và không gian bộ nhớ càng tốt Các cấu trúc dữ liệu được triển khai bằng cách sử dụng các kiểu dữ liệu, các tham chiếu và các phép toán trên đó được cung cấp bởi một ngôn ngữ lập trình

Trong đó nổi trội lên là hai cấu trúc dữ liệu đó là Stack (ngăn xếp) và Queue(hàng đợi) Stack và Queue có ứng dụng rất nhiều kể cả trong thuật toán lẫn trong thực tế Hàng ngày chúng ta thường xuyên làm việc và tiếp xúc với các biểu thức, toán hạng, toán tử… và máy tính cũng vậy Tuy nhiên máy tính không thể nào hiểuđược ngôn ngữ và cách viết của con người, vì vậy để máy tính hiểu được các biểu thức thì chúng ta phải chuyển chúng về một dạng mà máy tính có thể thực hiện

được Vì vậy em xin chọn đề tài “Ứng dụng ngăn xếp (Stack) và hàng đợi (Queue)

để viết chương trình biến đổi biểu thức trung tố thành tiền tố và hậu tố” để làm bài tiểu luận

II Mục đích yêu cầu của đề bài

1 Mục đích

Đề tài này giúp em củng cố, nâng cao kiến thức về môn học cấu trúc dữ liệu

và giải thuật Từ đó hiểu sâu hơn và vận dụng vào trong các bài toán số liệu thực tếđồng thời thông qua việc làm đề tài này giúp em biết được các phương pháp

Trang 3

2 Yêu cầu

Dùng ngôn ngữ lập trình C/C++ để cài đặt chương trình Với dữ liệu đượcnhập vào từ bàn phím

III Phương pháp nghiên cứu

+ Tham khảo tài liệu: cấu trúc dữ liệu và giải thuật, trên mạng…

+ Tìm hiểu thực tiễn, thực tế, quy cách, nhu cầu của bài toán

+ Xin ý kiến, hướng dẫn của giáo viên hướng dẫn

Phần II: Nội dung

I Ngăn xếp (Stack)

 Ngăn xếp (Stack) là một danh sách có thứ tự mà phép chèn và xóa được

thực hiện tại đầu cuối của danh sách và người ta gọi đầu cuối này là đỉnh (top) của stack Với nguyên tắc vào sau ra trước, danh sách kiểu LIFO (last

- in - first - out)

 Có 2 cách lưu trữ Stack:

+ Bằng mảng

+ Bằng danh sách liên kết

 Các thao tác cơ bản trên Stack:

Push: Đưa một phần tử vào đỉnh của Stack

Pop: Lấy từ đỉnh của Stack một phần tử

Peek: Xem đỉnh của Stack chứa nội dung là gì?

Trang 4

Trong trình soạn thảo văn bản, thao tác Undo được lưu

trong stack

Ứng dụng gián tiếp:

Cấu trúc dữ liệu bổ trợ cho thuật toán khác

Một thành phần của cấu trúc dữ liệu khác

II Hàng đợi (Queue)

 Hàng đợi là kiểu danh sách tuyến tính mà phép bổ sung được thực hiện ở 1 đầu, gọi là lối sau (rear) và phép loại bỏ thực hiện ở 1 đầu khác gọi là lối

trước (front) Nguyên tắc vào trước ra trước, danh sách kiểu FIFO (first - in

Prefix: Biểu thức tiền tố được biểu diễn bằng cách đặt toán tử lên trước các

toán hạng Cách biểu diễn này còn được biết đến với tên gọi “ký pháp Ba Lan” do

Trang 5

nhà toán học Ba Lan Jan Łukasiewicz phát minh năm 1920 Với cách biểu diễn

này, thay vì viết x + y như dạng trung tố, ta sẽ viết + x y Tùy theo độ ưu tiên của toán tử mà chúng sẽ được sắp xếp khác nhau, bạn có thể xem một số ví dụ ở phía sau phần giới thiệu này

Postfix: Ngược lại với cách Prefix, biểu thức hậu tố tức là các toán tử sẽ

được đặt sau các toán hạng Cách biểu diễn này được gọi là “ký pháp nghịch đảo

Ba Lan” hoặc được viết tắt là RPN(Reverse Polish notation), được phát minh vào

khoảng giữa thập kỷ 1950 bởi một triết học gia và nhà khoa học máy tính Charles Hamblin người Úc

Ví dụ:

2 Chuyển đổi dạng Infix(trung tố) sang Postfix(hậu tố)

Thuật toán:

Bước 1: Đọc một thành phần của biểu thức E (dạng Infix biểu diễn

bằng xâu, đọc từ trái qua phải) Giả sử thành phần đọc được là x

Bước 1.1: Nếu x là toán hạng thì viết nó vào bên phải biểu thức E1 (xâu

lưu

kết quả của Postfix)

Bước 1.2: Nếu x là dấu ‘(’ thì đẩy nó vào Stack.

Bước 1.3: Nếu x là một trong các phép toán +, -, *, / thì

Bước 1.3.1: Xét phần tử y ở đỉnh Stack.

Bước 1.3.2: Nếu Pri(y) >= Pri(x) là một phép toán thì loại y ra khỏi

Stack và viết y vào bên phải của E1 và quay lại bước 1.3.1

Bước 1.3.3: Nếu Pri(y) < Pri(x) thì đẩy x vào Stack.

Trang 6

Bước 1.4: Nếu x là dấu ‘)’ thì

Bước 1.4.1: Xét phần tử y ở đầu của Stack.

Bước 1.4.2: y là phép toán thì loại y ra khỏi Stack, viết y vào bên

phải E1 và quay trở lại 1.4.1

Bước 1.4.3: Nếu y là dấu ‘(’ loại y ra khỏi Stack.

Bước 2: Lập lại bước 1 cho đến khi toàn bộ biểu thức E được đọc qua

Bước 3: Loại phần tử ở đỉnh Stack và viết nó vào bên phải E1 Lặp lại bước này

cho đến khi Stack rỗng

Bước 4: Tính giá trị của biểu thức dưới dạng hậu tố

Ví dụ: Cho biểu thức: E = a * (b + c) – d / e

3 Tính giá trị biểu thức dạng Postfix(hậu tố)

Thuật toán:

Bước 1: Đọc lần lượt các phần tử của biểu thức E1 (từ trái qua phải) Nếu gặp toán

hạng thì đẩy nó vào Stack Nếu gặp phép toán thì lấy hai phần tử liên tiếp trong

Stack thực hiện phép toán, kết quả được đẩy vào trong Stack

Bước 2: Lập lại bước 1 cho đến khi hết tất cả các phần tử trong biểu thức E1 lúc

đó đỉnh của Stack chứa giá trị của

Trang 7

biểu thức cần tính

Bước 3: Kết thúc.

Ví dụ: tính giá trị của biểu thức sau: 4 5 + 2 3 + * 6 + 8 7 + /

Giả thuật được trình bày như sau:

4 Chuyển đổi dạng Infix(trung tố) sang Prefix(tiền tố)

Thuật toán:

Ý tưởn: Sử dụng Stack và Queue và Stackkq.

Bước 1: Đọc một thành phần của biểu thức E (dạng Infix biểu diễn bằng xâu, đọc

từ phải qua trái) Giả sử thành phần đọc được là x:

Bước 1.1: Nếu x là toán hạng thì đưa nó vào Queue.

Bước 1.2: Nếu x là dấu ‘)’ thì đẩy nó vào Stack.

Bước 1.3: Nếu x là một trong các phép toán +, -, *, / thì:

Bước 1.3.1: Kiểm tra xem stack có rỗng không? Nếu rỗng, đẩy

vào Stack, nếu không rỗng, sang bước 1.3.2

Bước 1.3.2: Lấy phần tử y ở đỉnh Stack.

Bước 1.3.3: Nếu Pre(y)>=Pre(x), đưa tất cả các phần tử trong

Queue vào Stackkq, đưa y vào Stackkq, đưa x vào Stack

Bước 1.3.4: Nếu Pre(y)<Pre(x) thì đẩy x vào Stack.

Bước 1.4: Nếu x là dấu ‘(’ thì:

Bước 1.4.1: Đưa tất cả các phần tử trong Queue vào Stackkq,

Trang 8

Bước 1.4.2: Xét phần tử y ở đầu của Stack.

Bước 1.4.3: y là phép toán thì loại y ra khỏi Stack, đưa y vào

Stackkq, quay về bước 1.4.2

Bước 1.4.3: Nếu y là dấu ‘)’ loại y ra khỏi Stack.

Bước 2: Lập lại bước 1 cho đến khi toàn bộ biểu thức E được duyệt.

Bước 3: Đưa tất cả các phần tử trong Queue vào Stackkq, tất cả phần tử trong

Stack và Stackkq

Bước 4: Lấy từng phần tử trong Stackkq ra, đó là kết quả dạng Prefix.

Bước 5: Tính giá trị của biểu thức dưới dạng tiền tố.

Ví dụ: Cho biểu thức sau hãy chuyển về dạng Prefix:

E = a * b + c / dGiải thuật được trình bày như sau:

5 Tình giá trị biểu thức dạng Prefix(tiền tố)

Thuật toán:

Bước 1: Đọc lần lượt các phần tử của biểu thức E1 (từ phải qua trái)

Bước 1.1: Nếu gặp toán hạng thì đẩy nó vào Stack.

Bước 1.2: Nếu gặp phép toán thì lấy hai phần tử liên tiếp trong Stack

thực hiện phép toán, kết quả được đẩy vào trong Stack

Bước 2: Lập lại bước 1 cho đến khi hết tất cả các phần tử trong biểu thức E1 Lúc

đó đỉnh của Stack chứa giá trị của biểu thức cần tính

Bước 3: Kết thúc.

Trang 9

Ví dụ: tính giá trị của biểu thức sau: /+7 8 + 6 * + 3 2 + 5 4

Giả thuật được trình bày như sau:

IV Chương trình đầy đủ

Trang 10

void InitStack(STACK *stack){

stack ->top = NULL;

stack ->size = 0;

}

int IsStackEmpty(STACK *stack){

return (stack ->size == 0);

}

void PushStack(STACK *stack, Item item){

if(stack ->top == NULL){

stack ->top = (STACKNODE

*)malloc(sizeof(STACKNODE));

stack ->top ->item = item;

stack ->top ->next = NULL;

}else{

Trang 11

Item PopStack(STACK *stack){

if(stack ->size > 0){

STACKNODE *t = stack ->top;

stack ->top = stack ->top ->next;

Item item = t ->item;

free(t);

stack ->size ;

return item;

}}

Item PeekStack(STACK *stack){

struct _QUEUENODE *next;

struct _QUEUENODE *prev;

} QUEUENODE;

typedef struct _QUEUE{

_QUEUENODE *front, *rear;

int size;

} QUEUE;

void InitQueue(QUEUE *queue){

queue ->front = NULL;

queue ->rear = NULL;

queue ->size = 0;

Trang 12

int IsQueueEmpty(QUEUE *queue){

return (queue ->size == 0);

}

void PushQueue(QUEUE *queue, Item item){

if(queue ->front == NULL && queue ->rear == NULL){

queue ->front = (QUEUENODE

*)malloc(sizeof(QUEUENODE));

queue ->front ->item = item;

queue ->front ->next = NULL;

queue ->front ->prev = NULL;

queue ->rear = queue ->front;

}else{

}

Item PopQueue(QUEUE *queue){

if(queue ->size != 0){

QUEUENODE *t = queue->rear;

if(queue ->rear == queue->front){

queue ->rear = NULL;

Trang 13

queue ->front = NULL;

}else{

queue ->rear = queue ->rear ->prev;

queue ->rear ->next = NULL;

}queue ->size ;

Item i = t ->item;

free(t);

return i;

}}

Item PeekQueue(QUEUE *queue)

{

if(queue->size > 0)

return queue->front->item;

}

int DocSo(char str[], int &i){

int len = strlen(str);

t[j++] = '\0';

break;

}

Trang 14

}return atoi(t);

}

void Tach(char str[], QUEUE *queue){

int len = strlen(str);

item.value = str[i];

item.type = PARENT_OPEN;

PushQueue(queue, item);

}else if(str[i] == ')'){

item.value = str[i];

item.type = PARENT_CLOSE;

PushQueue(queue, item);

}else if(str[i] >= '0' && str[i] <= '9'){

item.value = DocSo(str, i);

item.type = OPERAND;

PushQueue(queue, item);

i ;

Trang 15

}}

// chuyen tu bieu thuc trung to sang hau to

void Convert(QUEUE *queue, QUEUE *output){

int size = queue ->size;

Trang 16

while(priority(item.value) <=

priority(PeekStack(&stack).value) && stack.size > 0){

Item iTemp = PopStack(&stack);

PushQueue(output, iTemp);

}PushStack(&stack, item);

break;

}}

while(stack.size > 0) {

item = PopStack(&stack);

PushQueue(output, item);

}}

void Print(QUEUE *queue){

QUEUENODE *i;

Trang 17

}

// tinh gia tri cua bieu thuc hau to

float Calculate(QUEUE *queue){

Trang 18

item.type = OPERAND;

PushStack(&stack, item);

}}

return PopStack(&stack).value;

}

// chuyen bieu thuc trung to sang tien to

void Convert2(QUEUE *queue, QUEUE *output){

int size = queue ->size;

Trang 19

priority(PeekStack(&stack).value) && stack.size > 0){

Item iTemp = PopStack(&stack);

PushQueue(output, iTemp);

}PushStack(&stack, item);

break;

case PARENT_CLOSE:{

Trang 20

PushStack(&stack, item);

}

break;

}}

while(stack.size > 0){

item = PopStack(&stack);

PushQueue(output, item);

}}

void Print2(QUEUE *queue){

printf("\n");

}

// tinh gia tri cua bieu thuc tien to

Trang 21

float Calculate2(QUEUE *queue){

Trang 22

result = a / b;

}item.value = result;

item.type = OPERAND;

PushStack(&stack, item);

}}

Trang 23

Kết quả như sau:

Nhận xét: vẫn còn rất nhiều cách khác thuật toán khác để có thể áp dụng chuyển

1 biểu thức trung tố sang hậu tố và tiền tố, tính giá trị của biểu thức tiền tố và hậu

tố Thế nhưng đây là cách đầy đủ và rõ ràng nhất Nó áp dụng rất tốt cho nhưng

người đang lập trình Bởi vì nó bao gồm đầy đủ, sử dụng cả Stack và Queue

Trang 24

Phần III: Kết luận

Thông qua việc tìm hiểu về ứng dụng của Stack và Queue để để viết chươngtrình biến đổi biểu thức trung tố thành tiền tố, hậu tố và tính giá trị của biểu thứctiền tố và hậu tố em đã rút ra được rất nhiều điều Từ cách xác định được giải thuậtđến tư duy logic và chương trình đã chạy thành công trên phần mềm Devcpp++5.11 bằng ngôn ngữ C/C++ Rút ra được cách làm một bài tiểu luận đúng vàchuẩn

Có được kết quả trên là nhờ có sự dạy dỗ chu đáo của cô giáo Trịnh ThịPhú trong quá trình truyền thụ kiến thức môn học cấu trúc dữ liệu và giải thuật,đồng thời cô cũng là người hướng dẫn tận tình trong suốt quá trình thực hiện đề tàitiểu luận môn học này

Em xin chân thành cám ơn cô!

Thanh Hóa, ngày….tháng 11 năm 2015

Giáo viên hướng dẫn

Ths Trịnh Thị Phú

Sinh viên thực hiện

Hoàng Năng Hưng

Trang 25

TÀI LIỆU THAM KHẢO

[1] Giáo trình cấu trúc dữ liệu và giải thuật, Đỗ Xuân Lôi, NXB Đại học Quốc Gia

Hà Nội

[2] Lập trình C căn bản, Hanoi Aptech Computer Education Center

[3] Gs Phạm Văn Ất Kỹ thuật lập trình C cơ sở và nâng cao, NXB Giao thông

vận tải Hà Nội – 2006

Ngày đăng: 20/11/2015, 16:42

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w