ctdl stack quece

58
Stack & Queue Stack & Queue Ngăn xếp & Hàng đợi Ngăn xếp & Hàng đợi

Upload: pham-anh-tuan

Post on 24-Oct-2014

129 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CTDL Stack Quece

Stack & QueueStack & QueueNgăn xếp & Hàng đợiNgăn xếp & Hàng đợi

Page 2: CTDL Stack Quece

Nội dungNội dung

• Trình bày khái niệm Stack và Queue

• Minh họa các ứng dụng

• Các phương pháp xây dựng Stack và Queue dựa trên những cấu trúc dữ liệu đã biết

•Stack–Ví dụ–Định nghĩa–Các thao tác cơ bản–Xây dựng Stack

•Queue–Ví dụ–Định nghĩa–Các thao tác cơ bản–Xây dựng Queue

Page 3: CTDL Stack Quece

Ngăn xếp (Stack)Ngăn xếp (Stack)

Chồng khay cà phê

Chồng tiền xu

Chồng sách Chồng áo sơ mi

Các ví dụ về Ngăn xếp

Page 4: CTDL Stack Quece

Ngăn xếp - Định nghĩaNgăn xếp - Định nghĩa

• Stack là 1 cấu trúc:– gồm nhiều phần tử có thứ tự– hoạt động theo cơ chế “Vào sau – Ra trước” (LIFO –

Last In, First Out) Đỉnh ngăn xếp

Page 5: CTDL Stack Quece

Ngăn xếp - Định nghĩaNgăn xếp - Định nghĩa

• Các thao tác cơ bản trên Stack:– InitStack: khởi tạo Stack rỗng– IsEmpty: kiểm tra Stack rỗng ?– IsFull: kiểm tra Stack đầy ?– Push: thêm 1 phần tử vào đỉnh Stack, có thể làm

Stack đầy– Pop: lấy ra 1 phần tử từ đỉnh Stack, có thể làm Stack

rỗng– StackTop: kiểm tra phần tử đầu Stack

Push Pop

Page 6: CTDL Stack Quece

Ngăn xếpNgăn xếp

• Minh họa thao tác Push

Data

Top

Page 7: CTDL Stack Quece

Ngăn xếpNgăn xếp

• Minh họa thao tác Pop

Data

Top

Page 8: CTDL Stack Quece

Ngăn xếpNgăn xếp

• Minh họa thao tác StackTop Ngăn xếp không thay đổi

Data

Top

?

?

Page 9: CTDL Stack Quece

Ngăn xếpNgăn xếp

• Có hai cách để xây dựng ngăn xếp– Sử dụng mảng 1 chiều– Sử dụng danh sách liên kết đơn

Mảng 1 chiều Danh sách liên kết đơn- Viết chương trình dễ dàng, nhanh chóng

- Bị hạn chế do số lượng phần tử cố định

- Tốn chi phí tái cấp phát và sao chép vùng nhớ nếu sử dụng mảng động

Phức tạp khi triển khai chương trình

Không bị cố định về số phần tử, phụ thuộc vào bộ nhớ

Page 10: CTDL Stack Quece

Ngăn xếp – Sử dụng mảngNgăn xếp – Sử dụng mảng

936

9 3 60 1 2 3 4 5 6 7 8 9

Xây dựng ngăn xếp bằng mảng 1 chiều

Ngăn xếp có 3 phần tử

StkTopĐỉnh ngăn xếp

StackStack

TopTop

Page 11: CTDL Stack Quece

Ngăn xếp – Sử dụng mảngNgăn xếp – Sử dụng mảng

• // Giả sử Stack chứa các phần tử kiểu nguyên

• // (int) - Khai báo cấu trúc Stack

typedef struct STACK {

int* StkArray; // mảng chứa các phần tử

int StkMax; // số phần tử tối đa

int StkTop; // vị trí đỉnh Stack

};

Page 12: CTDL Stack Quece

Ngăn xếp – Sử dụng mảngNgăn xếp – Sử dụng mảng

• Thao tác “Khởi tạo Stack rỗng”int InitStack(STACK& s, int MaxItems){

s.StkArray = new int[MaxItems];if (s.StkArray == NULL)

return 0; // Không cấp phát được bộ nhớs.StkMax = MaxItems;s.StkTop = -1; // chưa có phần tử nào trong Stackreturn 1; // khởi tạo thành công

}

Page 13: CTDL Stack Quece

Ngăn xếp – Sử dụng mảngNgăn xếp – Sử dụng mảng

• Thao tác “Kiểm tra Stack rỗng”

int IsEmpty(const STACK &s)

{

if (s.StkTop==-1)

return 1; // Stack rỗng

return 0; // Stack không rỗng

}

Page 14: CTDL Stack Quece

Ngăn xếp – Sử dụng mảngNgăn xếp – Sử dụng mảng

• Thao tác “Kiểm tra Stack đầy”

int IsFull(const STACK &s)

{

if (s.StkTop==s.StkMax-1)

return 1; // Stack đầy

return 0; // Stack chưa đầy

}

Page 15: CTDL Stack Quece

Ngăn xếp – Sử dụng mảngNgăn xếp – Sử dụng mảng

• Thao tác “Push”: thêm một phần tử vào đỉnh Stack

int Push (STACK& s, int newitem)

{

if (IsFull(s))

return 0; // stack đầy, không thể thêm

s.StkTop++;

s.StkArray[s.StkTop] = newitem;

return 1; // thêm thành công

}

Page 16: CTDL Stack Quece

Ngăn xếp – Sử dụng mảngNgăn xếp – Sử dụng mảng

• Thao tác “Pop”: lấy ra 1 phần tử từ đỉnh Stack

int Pop(STACK& s, int& outitem)

{

if (IsEmpty(s))

return 0; // Stack rỗng, không lấy ra được

outitem = s.StkArray[s.StkTop];

s.StkTop--;

return 1; // lấy ra thành công

}

Page 17: CTDL Stack Quece

Ngăn xếp – Sử dụng mảngNgăn xếp – Sử dụng mảng

• Thao tác “StackTop”: kiểm tra 1 phần tử ở đỉnh Stack, không làm thay đổi Stack

int StackTop(const STACK s, int& outitem){

if (IsEmpty(s))return 0; // Stack rỗng, không lấy ra được

outitem = s.StkArray[s.StkTop];return 1; // lấy ra thành công

}

Page 18: CTDL Stack Quece

Ngăn xếp – Ví dụ ứng dụngNgăn xếp – Ví dụ ứng dụng

• Kiểm tra sự tương ứng của các cặp ngoặc đơn trong một biểu thức

• ( ( A + B ) / C ( A + B ) / C)

• Đảo ngược một chuỗi ký tự

• Cá Ăn Kiến nếiK nĂ áC

? ?

Page 19: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

97

4

NStkCnt StkTop

7Data Link

9Data Link

4

Data Link

Page 20: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK• Cấu tạo đầu stack

• Cấu tạo một phần tử trong stack

N

StkCnt StkTop

Data Link

stackStkCnt <integer>StkTop <node pointer>

end stack

nodeData <datatype>Link <node pointer>

end node

Page 21: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

// Khai báo cấu trúc một phần tử trong stacktypedef struct tagSTACK_NODE {

int Data;tagSTACK_NODE *pNext;

} STACK_NODE;// Khai báo cấu trúc stacktypedef struct STACK {

int StkCount;STACK_NODE *StkTop;

};

Page 22: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

• VD: Thực hiện một số thao tác trên stack

STACK s;

InitStack(s);

Push(s, 7);

Push(s, 4);

Pop(s, x); // x = ?

NStkCnt StkTop

7Data Link

4Data Link

Page 23: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

• Thao tác “Khởi tạo stack rỗng”:

void InitStack(STACK& s)

{

s.StkTop = NULL;

s.StkCount = 0;

}

Page 24: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

• Thao tác “Kiểm tra stack rỗng”:

int IsEmpty(const STACK& s)

{

if (s.StkTop == NULL)

return 1; // stack rỗng

return 0; // stack không rỗng

}

Page 25: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

• Thao tác “Kiểm tra stack đầy”:int IsFull (const STACK s){

// thử tạo mới một phần tử

STACK_NODE* temp = new STACK_NODE;// nếu không tạo được stack đầy

if (temp == NULL)return 1; // stack đầy

delete temp;return 0; // stack chưa đầy

}

Page 26: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

• Thao tác “Push”: thêm 1 phần tử vào đỉnh stack thêm vào đầu danh sách liên kết

int Push(STACK &s, int newitem){

if (IsFull(s))return 0; // Stack đầy, không thêm vào được

STACK_NODE *pNew = new STACK_NODE;pNew->Data = newitem;pNew->pNext = s.StkTop;s.StkTop = pNew;s.StkCount++;return 1; // Thêm thành công

}

NStkCnt StkTop

7Data Link

4Data Link

Page 27: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

• Thao tác “Pop”: lấy ra 1 phần tử từ đỉnh stack xóa phần tử đầu danh sách liên kết

int Pop(STACK &s, int& outitem){

if (IsEmpty(s))return 0; // Stack rỗng, không lấy ra được

// lưu lại con trỏ đến ptử đầuSTACK_NODE *temp = s.StkTop;outitem = s.StkTop->Data;s.StkTop = s.StkTop->pNext;delete temp;s.StkCount--;return 1; // Lấy ra thành công

}

NStkCnt StkTop

7Data Link

4Data Link

temp

outitem = 4

Page 28: CTDL Stack Quece

Ngăn xếp – Sử dụng DSLKNgăn xếp – Sử dụng DSLK

• Thao tác “StackTop”: kiểm tra 1 phần tử ở đỉnh stack, không làm thay đổi stack

int StackTop(STACK &s, int& outitem){

if (IsEmpty(s))return 0; // Stack rỗng, không lấy ra được

outitem = s.StkTop->Data;return 1; // Lấy ra thành công

}

Page 29: CTDL Stack Quece

Ngăn xếp – Ứng dụngNgăn xếp – Ứng dụng

• Stack có nhiều ứng dụng:

• Lưu vết trong thuật toán “back-tracking” (theo dõi dấu vết)

• Tính giá trị biểu thức toán học (thuật toán Balan ngược)

• Khử đệ quy

• …

Page 30: CTDL Stack Quece

Ngăn xếp – Quick SortNgăn xếp – Quick Sort

• Để khử đệ quy cho Quick Sort, ta sử dụng một stack để lưu lại các partition (phân hoạch) cần tiến hành sắp xếp.

• Ý tưởng:– Push phân hoạch đầu tiên (0, n-1) vào stack– Trong khi stack chưa rỗng

• Pop một phân hoạch từ stack

• Chọn phần tử trục trên phân hoạch này

• Điều chỉnh phân hoạch tương ứng với trục

• Push 2 phân hoạch bên trái và phải trục vào stack

Page 31: CTDL Stack Quece

Ngăn xếp – Quick SortNgăn xếp – Quick Sort

• Push phân hoạch đầu tiên (0, n-1) vào stack

• Trong khi stack chưa rỗng– Pop một phân hoạch từ stack

– Chọn phần tử trục trên phân hoạch này

– Điều chỉnh phân hoạch tương ứng với trục

– Push 2 phân hoạch bên trái và phải trục vào stack

(0,4)

11 55 44 77 330 1 2 3 4

i j

t

11 33 44 77 550 1 2 3 4

(0,1)

(3,4)

11 33 44 55 770 1 2 3 4

Stack rỗngStack rỗngStopStop

Page 32: CTDL Stack Quece

Hàng đợi (Queue)Hàng đợi (Queue)

Phòng vé

Page 33: CTDL Stack Quece

Hàng đợi – Định nghĩaHàng đợi – Định nghĩa

• Hàng đợi là một cấu trúc:– Gồm nhiều phần tử có thứ tự– Hoạt động theo cơ chế “Vào trước, ra trước” (FIFO -

First In First Out)

Page 34: CTDL Stack Quece

Hàng đợi – Định nghĩaHàng đợi – Định nghĩa

• Các thao tác cơ bản trên hàng đợi:– InitQueue: khởi tạo hàng đợi rỗng– IsEmpty: kiểm tra hàng đợi rỗng ?– IsFull: kiểm tra hàng đợi đầy ?– EnQueue: thêm 1 phần tử vào cuối hàng đợi, có thể

làm hàng đợi đầy– DeQueue: lấy ra 1 phần tử từ đầu Queue, có thể làm

Queue rỗng– QueueFront, QueueRear: kiểm tra phần tử đầu và

phần tử cuối Queue

Page 35: CTDL Stack Quece

Hàng đợiHàng đợi

• Minh họa thao tác EnQueue

• Minh họa thao tác DeQueue

Page 36: CTDL Stack Quece

Hàng đợiHàng đợi

• Có hai cách để xây dựng hàng đợi– Sử dụng mảng 1 chiều– Sử dụng danh sách liên kết đơn

Mảng 1 chiều Danh sách liên kết đơn- Viết chương trình dễ dàng, nhanh chóng

- Bị hạn chế do số lượng phần tử cố định

- Tốn chi phí tái cấp phát và sao chép vùng nhớ nếu sử dụng mảng động

Phức tạp khi triển khai chương trình

Không bị cố định về số phần tử, phụ thuộc vào bộ nhớ

Page 37: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

• Dùng 1 mảng (QArray) để chứa các phần tử.

• Dùng 1 số nguyên (QMax)để lưu số phần tử tối đa trong hàng đợi

• Dùng 2 số nguyên (QFront, QRear) để xác định vị trí đầu, cuối hàng đợi

• Dùng 1 số nguyên (QNumItems)để lưu số phần tử hiện có trong hàng đợi

Page 38: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

0 1 2 3 4 5 6

Qarray 37 22 15 3

QMax = 7

QNumItems = 4

QFront = 1

QRear = 4

Page 39: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

// Giả sử Queue chứa các phần tử kiểu nguyên (int)

// Khai báo cấu trúc Queue

typedef struct QUEUE {

int* QArray;

int QMax;

int QNumItems;

int QFront;

int QRear;

};

Page 40: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

• Khi thêm nhiều phần tử sẽ xảy ra hiện tượng “tràn giả”

• Giải pháp? Nối dài mảng (mảng động) hay sử dụng một mảng vô cùng lớn?

0 1 2 3 4 5 6

Qarray 37 22 15 3 7 9

QMax = 7

QNumItems = 4

QFront = 1

QRear = 4

Page 41: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

• Xử lý mảng như một danh sách liên kết vòng0 1 2 3 4 5 6

Qarray 37 22 15 3 7 9

QMax = 7

QNumItems = 4

QFront = 1

QRear = 4

Page 42: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

• Thao tác “Khởi tạo Queue rỗng”:int InitQueue(QUEUE& q, int MaxItem){

q.QArray = new int[MaxItem];if (q.QArray == NULL)

return 0; // không đủ bộ nhớq.QMax = MaxItem;q.QNumItems = 0;q.QFront = q.QRear = -1;return 1; // thành công

}

Page 43: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

• Thao tác “Kiểm tra Queue rỗng”:

int IsEmpty(QUEUE q)

{

if (q.QNumItems == 0)

return 1; // rỗng

return 0; // không rỗng

}

Page 44: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

• Thao tác “Kiểm tra Queue đầy”:

int IsFull(QUEUE q)

{

if (q.QMax == q.QNumItems)

return 1; // đầy

return 0; // không đầy

}

Page 45: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng• Thao tác EnQueue: thêm 1 phần tử vào cuối Queueint EnQueue(QUEUE &q, int newitem){

if (IsFull(q))return 0; // Queue đầy, không thêm vào được

q.QRear++;if (q.QRear==q.QMax) // “tràn giả”

q.QRear = 0; // Quay trở về đầu mảngq.QArray[q.QRear] = newitem;

// thêm phần tử vào cuối Queueif (q.QNumItems==0)

q.QFront = 0;q.QNumItems++;return 1; // Thêm thành công

}

Page 46: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng• Thao tác DeQueue: lấy ra 1 phần tử ở đầu Queueint DeQueue(QUEUE &q, int& itemout){

if (IsEmpty(q))return 0; // Queue rỗng, không lấy ra được

itemout = q.QArray[q.QFront]; // lấy phần tử đầu raq.QFront++;q.QNumItems--;if (q.QFront==q.QMax) // nếu đi hết mảng …

q.QFront = 0; // … quay trở về đầu mảngif (q.QNumItems==0) // nếu lấy ra phần tử cuối cùng

q.QFront = q.QRear = -1; // khởi tạo lại Queuereturn 1; // Lấy ra thành công

}

Page 47: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

• Thao tác QueueFront: Kiểm tra phần tử ở đầu Queue

int QueueFront(const QUEUE &q, int& itemout)

{

if (IsEmpty(q))

return 0; // Queue rỗng, không kiểm tra

// lấy phần tử đầu ra

itemout = q.QArray[q.QFront];

return 1;

}

Page 48: CTDL Stack Quece

Hàng đợi – Sử dụng mảngHàng đợi – Sử dụng mảng

• Thao tác QueueRear: Kiểm tra phần tử ở cuối Queue

int QueueRear(const QUEUE &q, int& itemout)

{

if (IsEmpty(q))

return 0; // Queue rỗng, không kiểm tra

// lấy phần tử cuối ra

itemout = q.QArray[q.QRear];

return 1;

}

Page 49: CTDL Stack Quece

Hàng đợi – Ví dụ ứng dụngHàng đợi – Ví dụ ứng dụng

• Quản lý việc thực hiện các tác vụ (task) trong môi trường xử lý song song

• Hàng đợi in ấn các tài liệu

• Vùng nhớ đệm (buffer) dùng cho bàn phím

• Quản lý thang máy

• Trắc nghiệm: Cho 1 chuỗi str. Kiểm tra xem chuỗi str có đối xứng ?

Page 50: CTDL Stack Quece

Hàng đợiHàng đợi

• Bài tập lý thuyết: Hãy xây dựng 1 Queue bằng cách sử dụng danh sách liên kết đơn

• Ðịnh nghĩa cấu trúc dữ liệu

• Xây dựng các thao tác cơ bản

Page 51: CTDL Stack Quece

Hàng đợi – Sử dụng DSLKHàng đợi – Sử dụng DSLK

• Khai báo cấu trúctypedef struct tagNODE{

int data;tagNODE* pNext;

} NODE, *PNODE;

typedef struct tagQUEUE{

int NumItems;PNODE pFront, pRear;

} QUEUE;

Page 52: CTDL Stack Quece

Hàng đợi – Sử dụng DSLKHàng đợi – Sử dụng DSLK

• Các thao tác cơ bản

int InitQueue(QUEUE& q);

int IsEmpty(const QUEUE& q);

int IsFull(const QUEUE& q);

int EnQueue(QUEUE &q, int newitem);

int DeQueue(QUEUE &q, int& itemout);

int QueueFront(const QUEUE &q, int& itemout);

int QueueRear(const QUEUE &q, int& itemout);

Page 53: CTDL Stack Quece

Hàng đợi – Sử dụng DSLKHàng đợi – Sử dụng DSLK

• Khởi tạo Queue rỗng

int InitQueue(QUEUE& q)

{

q.NumItems = 0;

q.pFront = q.pRear = NULL;

return 1;

}

Page 54: CTDL Stack Quece

Hàng đợi – Sử dụng DSLKHàng đợi – Sử dụng DSLK

• Kiểm tra Queue rỗngint IsEmpty(const QUEUE& q)

{

return (q.NumItems==0);

}

• Kiểm tra Queue đầyint IsFull(const QUEUE& q){

PNODE tmp = new NODE;if (tmp==NULL)

return 1;delete tmp;return 0;

}

Page 55: CTDL Stack Quece

Hàng đợi – Sử dụng DSLKHàng đợi – Sử dụng DSLK

• Thêm 1 phần tử vào cuối Queueint EnQueue(QUEUE &q, int newitem){

if (IsFull(q)==1)return 0;

PNODE p = new NODE;p->data = newitem;p->pNext = NULL;

if (q.pFront==NULL && q.pRear==NULL)q.pFront = q.pRear = p;

else{

q.pRear->pNext = p;q.pRear = p;

}q.NumItems++;return 1;

}

Page 56: CTDL Stack Quece

Hàng đợi – Sử dụng DSLKHàng đợi – Sử dụng DSLK

• Lấy ra 1 phần tử ở đầu Queueint DeQueue(QUEUE &q, int& itemout){

if (IsEmpty(q)==1)return 0;

PNODE p = q.pFront;q.pFront = p->pNext;itemout = p->data;

q.NumItems--;delete p;if (q.NumItems==0)

InitQueue(q);return 1;

}

Page 57: CTDL Stack Quece

Hàng đợi – Sử dụng DSLKHàng đợi – Sử dụng DSLK

• Kiểm tra 1 phần tử ở đầu Queue

int QueueFront(const QUEUE &q, int& itemout)

{

if (IsEmpty(q)==1)

return 0;

itemout = q.pFront->data;

return 1;

}

Page 58: CTDL Stack Quece

Hàng đợi – Sử dụng DSLKHàng đợi – Sử dụng DSLK

• Kiểm tra 1 phần tử ở cuối Queue

int QueueRear(const QUEUE &q, int& itemout)

{

if (IsEmpty(q)==1)

return 0;

itemout = q.pRear->data;

return 1;

}