Giáo trình Cấu trúc dữ liệu và Giải thuật - Chương 4: Ngăn xếp và hàng đợi - Đỗ Tuấn Anh

1. Định nghĩa Stack

2. Lưu trữ kế tiếp với Stack (sử dụng mảng)

3. Ứng dụng của Stack

4. Định nghĩa Queue

5. Lưu trữ kế tiếp với Queue (sử dụng mảng)

6. Ứng dụng của Queue (not yet)

7. Lưu trữ móc nối với Stack

8. Lưu trữ móc nối với Queue (bài tập)

9. Stack và cài đặt đệ quy (not neccesary)

pdf77 trang | Chuyên mục: Cấu Trúc Dữ Liệu & Giải Thuật | Chia sẻ: tuando | Lượt xem: 400 | Lượt tải: 0download
Tóm tắt nội dung Giáo trình Cấu trúc dữ liệu và Giải thuật - Chương 4: Ngăn xếp và hàng đợi - Đỗ Tuấn Anh, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
: value = left / right;
break;
case '^': value = pow(left, right);
break;
}
return value;
}
int postfixEval(string expression)
{
// expValue lưu kết quả của biểu thức
int left, right, expValue;
char ch;
// Tạo một stack lưu trữ toán hạng
IntStack* stack = CreateStack(MAX);
// Duyệt từng ký tự cho đến khi hết xâu
for (int i=0; i < expression.length(); i++)
{
// đọc một ký tự
ch = expression[i];
// nếu ch là toán hạng
if (isdigit(ch))
// đẩy toán hạng vào stack
PushStack(stack, ch - '0');
Hàm postfixEval()
// nếu ch là toán tử
else if (isOperator(ch)){ 
// rút stack 2 lần để lấy 2
// toán hạng left và right
PopStack(stack, &right);
PopStack(stack, &left);
// Tính "left op right" 
result = compute(left, right, ch);
// Đẩy result vào stack
PushStack(stack, temp);
}else //không phải toán hạng hoặc toán t
printf(“Bieu thuc loi”);
}
// Kết thúc tính toán, giá trị biểu thức 
// nằm trên đỉnh stack, đưa vào expValue
PopStack(stack, expValue);
return expValue;
}
Chuyển đổi trung tố→hậu tố
Toán hạng sẽ được ghi ngay vào xâu kết quả
Trong khi quét biểu thức số học:
Không cần sử dụng stack cho toán hạng.
Khi gặp toán tử hoặc dấu ngoặc, đẩy vào stack.
stack toán tử
Quản lý thứ tự ưu tiên giữa các toán tử
Xử lý các biểu thức con.
Hạng
Chỉ xét các toán tử hai ngôi.
Hạng.
1 nếu là toán hạng
-1 nếu là +, -, *, /, %, ^
0 nếu là (, ) 
Ví dụ 1
stack dùng để lưu trữ một cách tạm thời các toán tử trong 
khi chờ toán hạng 2 (phải) tương ứng.
a + b * c
+
Stack 
toán tử:
Xâu hậu tố: a cb +*
*
* có mức ưu tiên cao hơn + 
⇒ Thêm vào stack
Ví dụ 2
Sử dụng stack để xử lý các toán tử có cùng thứ tự
ưu tiên hoặc thấp hơn.
a * b / c + d
*
Stack toán tử:
Xâu hậu tố: a *b /c
/
* có cùng mức ưu tiên với / 
⇒ rút * và ghi nó vào xâu hậu tố
trước khi thêm / vào stack.
d
+
+
/ có mức ưu tiên cao hơn +
Ví dụ 3
Sử dụng giá trị mức ưu tiên để xử lý ^ (tính lũy thừa).
a ^ b ^ c
^
Stack toán tử:
Xâu hậu tố: a cb ^^
^ thứ 2 có mức ưu tiên là 4 nhưng
^ thứ 1 có mức ưu tiên là 3
⇒ ^ thứ 2 được đẩy tiếp vào stack
(do đó nó sẽ được rút ra trước ^ thứ 1)
Mức ưu tiên đầu vào: 4 khi ^ là đầu vào.
Mức ưu tiên tại stack: 3 khi ^ nằm trong stack. 
^
Ví dụ 4
Hai mức ưu tiên cho dấu ngoặc trái (
a * ( b + c )
*
Stack toán tử:
Xâu hậu tố: a cb *+
( có mức ưu tiên là 5 ⇒
đưa vào stack.
Mức ưu tiên đầu vào: 5 cao hơn bất kỳ toán tử nào.
(tất cả các toán tử trong stac phải giữ nguyên vì có một biểu thức con mới.)
Mức ưu tiên tại stack: -1 thấp hơn của bất kỳ toán tử nào.
(không toán tử nào trong biểu thức con được xóa cho đến khi gặp dấu ngoặc mở)
(
+ ( hiện có mức ưu tiên là -1 ⇒
tiếp tục ở trong stack.
Mức ưu tiên đầu vào và tại Stack
Mức ưu tiên
đầu vào
Mức ưu tiên
tại stackToán tử
+ - 1 1 -1
* / % 2 2 -1
^ 4 3 -1
( 5 -1 0
) 0 0 0
Hạng
Các quy luật đánh giá
Ghi ký tự vào xâu hậu tố nếu nó là toán hạng.
Nếu ký tự là một toán tử hoặc (, so sánh mức ưu tiên của nó
với mức ưu tiên của toán tử tại đỉnh stack.
Rút phần tử đỉnh stack nếu mức ưu tiên của phần tử tại stack
là cao hơn hoặc bằng và ghi tiếp nó vào xâu hậu tố.
Lặp cho đến khi toán tử tại đỉnh stack có hạng thấp hơn,
đẩy ký tự vào stack.
Nếu ký tự là ), rút tất cả các toán tử ra khỏi stack cho đến khi 
gặp ( và ghi các toán tử vào xâu hậu tố. Rút ( ra khỏi stack.
Khi kết thúc biểu thức trung tố, rút tất cả các toán tử ra khỏi stack
và ghi vào xâu hậu tố.
Ví dụ
3 * (4 – 2 ^ 5) + 6 
Stack toán tử
Hậu tố 3
* [2]
3
( [-1]
* [2]
3
( [-1]
* [2]
3 4
( [-1]
* [2]
- [1]
3 4
( [-1]
* [2]
- [1]
3 4 2
( [-1]
* [2]
- [1]
^ [3]
3 4 2
( [-1]
* [2]
- [1]
^ [3]
3 4 2 5
( [-1]
* [2]
3 4 2 5 ^ -
cont’d
* [2]
3 4 2 5 ^ -
Pop (
+ [1]
3 4 2 5 ^ - * 3 4 2 5 ^ - * 6 
+ [1]
3 4 2 5 ^ - * 6 + 
3 * (4 – 2 ^ 5) + 6 
Stack
typedef struct Operator {
char symbol; // toán tử
// mức ưu tiên đầu vào của toán tử op
int inputPrecedence; 
// mức ưu tiên trong stack của toán tử op
int stackPrecedence; 
}Operator;
typedef struct OpStack {
Operator * stackAry;
.
} OpStack ;
Xây dựng một stack cho phép lưu trữ các toán tử và mức ưu tiên của nó.
Output Stack Symbols
Rút các toán tử trong stack có stack precedence ≥ input precendence
của ký tự đang đọc.
void PopHigherOrEqualOp(OpStack* stack, Operator& op
string& postfix)
{
Operator op2;
while(!IsEmpty(stack) && 
(op2 = Top(stack)).stackPrecedence >= 
op.inputPrecedence)
{
Pop(stack);
postfix += op2.symbol;
}
}
Hàm chuyển đổi trung tố - hậu tố
Ghi toán hạng ra xâu hậu tố.
Gọi outputHigherOrEqual() nếu gặp toán tử.
Infix2Postfix() thực hiện những công việc sau:
Gọi outputHigherOrEqual() nếu gặp ).
Kết thúc khi đọc hết biểu thức
string Infix2Postfix ( string infix) {
string postfix; // lưu xâu biểu thức hậu tố
OpStack* stack = CreateStack( MAX); // tạo stack
// Duyệt từng ký tự của biểu thức
for (i=0; i < infix.length(); i++) {
ch = infix [i];
//****** Trường hợp toán hạng ************
if (isdigit(ch))
// ghi toán hạng vào biểu thức hậu tố
postfix += ch;
//******* Trường hợp toán tử hoặc '(' *****
else if (isOperator(ch) || ch == '(')
{
// rút các toán tử có mức ưu tiên cao hơn 
// ra khỏi stack
Operator op = createOperator(ch);
PopHigherOrEqualOp(stack, op, postfix);
// đẩy toán tử hiện tại vào stack
Push(stack, op);
}
//******** Trường hợp ‘)' *************
else if (ch == ‘)’)
{
// tạo một biến Operator cho ')‘
Operator op = CreateOperator(ch);
// Rút tất cả toán tử của biểu thức con 
// cho đến khi gặp '('
PopHigherOrEqualOp(stack, op, postfix);
// Rút '(' ra khỏi stack
Pop(stack); 
}
} // end for
// Rút các toán tử còn lại trg stack, ghi vào xâu
while (!IsEmpty(stack)) {
op = Pop(stack);
postfix += op.symbol;
}
return postfix;
}
4. Định nghĩa Queue
zQueue: là danh sách mà thêm phải được 
thực hiện tại một đầu còn xóa phải thực 
hiện tại đầu kia.
Thêm
(Enqueue)
Xóa
(Dequeue) CuốiĐầu
Figure 5-1
• Queue là một kiểu cấu trúc FIFO: First In First 
Out
Ví dụ của Queue trong thực tế
Các thao tác cơ bản với Queue
z Enqueue – Thêm một phần tử vào cuối queue
zTràn Overflow
z Dequeue – Xóa một phần tử tại đầu queue
zQueue rỗng?
z Front – Trả lại phần tử tại đầu queue
zQueue rỗng?
z End – Trả lại phần tử tại cuối queue
zQueue rỗng
Figure 5-2
Enqueue
Figure 5-3
Dequeue
Figure 5-4
Queue Front
Figure 5-5
Queue Rear
Lưu trữ Queue
zTương tự như Stack, có 2 cách lưu trữ:
{Lưu trữ kế tiếp: sử dụng mảng
{Lưu trữ móc nối: sử dụng danh sách móc nối
Figure 5-15
5. Lưu trữ kế tiếp với Queue
Figure 5-16
Queue tăng hết mảng
• Do đó cần sử dụng một mảng rất lớn?
Queue dạng vòng
A
B
front
rear
A
BC
front
rear
A
BC
D
front
rear
D
B
C
rear
front
D
BC
E
front
rear
Queue thực hiện trên mảng
11 37 22 15 3 -7 1
queueAry maxsize count front rear
front rear
7 4 1 5
Định nghĩa cấu trúc Queue
typedef struct intqueue {
int *queueAry;
int maxSize;
int count;
int front;
int rear;
}IntQueue;
Tạo Queue
IntQueue* CreateQueue (int max) {
IntQueue *queue;
queue = (IntQueue *)malloc(sizeof(IntQueue));
/* Cấp phát cho mảng */
queue->queueAry = malloc(max * sizeof(int));
/* Khởi tạo queue rỗng */
queue->front = -1;
queue->rear = -1;
queue->count = 0;
queue->maxSize = maxSize;
return queue;
} /* createQueue */
Enqueue
int enqueue (struct intqueue *queue, int datain) {
if (queue->count == queue->maxSize)
return 0; /* queue is full */
(queue->rear)++;
if (queue->rear == queue->maxSize)
/* Queue wraps to element 0 */
queue->rear = 0;
queue->queueAry[queue->rear] = datain; 
if (queue->count == 0) {
/* Inserting into null queue */
queue->front = 0;
queue->count = 1;
} /* if */
else (queue->count)++;
return 1;
Dequeue
int dequeue (struct intqueue *queue, int *dataOutPtr) {
if (!queue->count)
return 0;
*dataOutPtr = queue->queueAry[queue->front];
(queue->front)++;
if (queue->front == queue->maxSize)
/* queue front has wrapped to element 0 */
queue->front = 0;
if (queue->count == 1)
/* Deleted only item in queue */
queue->rear = queue->front = -1;
(queue->count)--;
return 1;
queueFront
int queueFront (struct intqueue *queue,
int *dataOutPtr) { 
if (!queue->count) 
return 0;
else { 
*dataOutPtr = queue->queueAry[queue->front];
return 1;
} /* else */
} /* queueFront */
queueRear
int queueRear (struct intqueue *queue,
int *dataOutPtr) {
if (!queue->count) 
return 0;
else { 
*dataOutPtr = queue->queueAry[queue->rear];
return 1;
} /* else */
} /* queueRear */
emptyQueue and fullQueue
int emptyQueue (struct intqueue *queue) 
{
return (queue->count == 0);
} /* emptyQueue */
int fullQueue (struct intqueue *queue ) 
{
return ( queue->count == queue->maxSize);
} /* fullQueue */
destroyQueue
struct intqueue *destroyQueue (struct intqueue
*queue) 
{
if (queue)
{
free (queue->queueAry); 
free (queue);
} /* if */
return NULL;
} /* destroyQueue */
6. Lưu trữ móc nối với Stack
Các cấu trúc của head và node
link link
Khai báo stack
typedef struct node 
{
int data ;
struct node *link ;
} STACK_NODE;
typedef struct stack
{
int count ; 
STACK_NODE *top ; 
} STACK;
createStack
static STACK *createStack ()
{
STACK *stack ;
stack = (STACK *) malloc( sizeof (STACK) ) ;
if (stack)
{
stack->top = NULL ;
stack->count = 0;
} /* if */
return stack ;
} /* createStack */
Push
zGiống như Thêm một phần tử mới vào
danh sách trước phần tử đầu
pushStack
static int pushStack(STACK *stack, int dataIn) {
STACK_NODE *newPtr;
newPtr = (STACK_NODE *) malloc(sizeof( 
STACK_NODE));
if (newPtr == NULL)
return 0; /* no more space */
newPtr->data = dataIn; 
newPtr->link = stack->top; 
stack->top = newPtr; 
( stack->count )++; 
return 1;
} /* pushStack */
7. Lưu trữ móc nối với Queue
zBài tập về nhà: Xây dựng Queue móc nối

File đính kèm:

  • pdfgiao_trinh_cau_truc_du_lieu_va_giai_thuat_chuong_4_ngan_xep.pdf