ctdl stack quece

Post on 24-Oct-2014

129 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

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

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

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

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

Ngăn xếpNgăn xếp

• Minh họa thao tác Push

Data

Top

Ngăn xếpNgăn xếp

• Minh họa thao tác Pop

Data

Top

Ngăn xếpNgăn xếp

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

Data

Top

?

?

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ớ

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

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

};

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

}

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

}

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

}

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

}

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

}

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

}

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

? ?

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

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

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;

};

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

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;

}

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

}

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

}

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

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

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

}

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

• …

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

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

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

Phòng vé

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)

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

Hàng đợiHàng đợi

• Minh họa thao tác EnQueue

• Minh họa thao tác DeQueue

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ớ

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

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

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;

};

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

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

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

}

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

}

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

}

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

}

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

}

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;

}

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;

}

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 ?

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

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;

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);

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;

}

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;

}

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;

}

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;

}

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;

}

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;

}

top related