M i v n đ c a th c t liên quan t i c ch FIFO nh c ch g i ti n, rút ti n trong ngân hàng, đ t vé máy bay đ u có th ng d ng đ c b ng hàng đ i. Hàng đ i còn có nh ng ng d ng trong vi c gi i quy t các bài toán c a H đi u hành và ch ng trình d ch nh bài toán đi u khi n các quá trình, đi u khi n n p ch ng trình vào b nh hay bài toán l p l ch. B n đ c có th tham kh o thêm trong các tài li u [1], [2]. D i đây, chúng ta đ a ra m t ng d ng c a hàng đ i đ gi i quy t bài toán “Nhà s n xu t và Ng i tiêu dùng”.
Ví d 3.2- Gi i quy t bài toán ”Ng i s n xu t và nhà tiêu dùng “ v i s các vùng đ m h n ch .
Chúng ta mô t quá trình s n xu t và tiêu dùng nh hai quá trình riêng bi t và th c hi n song hành, ng i s n xu t có th s n xu t t i đa n m t hàng. Ng i tiêu dùng ch đ c phép s d ng trong s n m t hàng. Tuy nhiên, ng i s n xu t ch có th l u tr vào kho khi và ch khi kho ch a b đ y. Ng c l i, n u kho hàng không r ng (kho có hàng) ng i tiêu dùng có th tiêu dùng nh ng m t hàng trong kho theo nguyên t c hàng nào nh p vào kho tr c đ c tiêu dùng tr c gi ng nh c ch FIFO c a queue. Sau đây là nh ng thao tác ch y u trên hàng đ i đ gi i quy t bài toán:
Ta xây d ng hàng đ i nh m t danh sách tuy n tính g m MAX ph n t m i ph n t là m t c u trúc, hai bi n front, rear tr đ n l i vào và l i ra trong queue:
typedef struct{ int mahang; char ten[20]; } hang;
typedef struct {
int front, rear; hang node[MAX]; } queue;
Thao tác Initialize: thi t l p tr ng thái ban đ u c a hàng đ i. tr ng thái này, font và rear có cùng m t giá tr MAX-1.
void Initialize ( queue *pq){
pq->front = pq->rear = MAX -1; }
Thao tác Empty: ki m tra hàng đ i có tr ng thái r ng hay không. Hàng đ i r ng khi front == rear.
int Empty(queue *pq){
if (pq->front==pq->rear) return(TRUE); return(FALSE); }
Thao tác Insert: thêm X vào hàng đ i Q. N u vi c thêm X vào hàng đ i đ c th c hi n đ u hàng, khi đó rear có giá tr 0, n u rear không ph i đ u hàng đ i thì giá tr c a nó đ c t ng lên 1 đ n v .
void Insert(queue *pq, hang x){ if (pq->rear==MAX-1 ) pq->rear=0; else
(pq->rear)++; if (pq->rear ==pq->front){
printf("\n Queue full"); delay(2000);return; }
else
pq->node[pq->rear]=x; }
Thao tác Remove: lo i b ph n t v trí front kh i hàng đ i. N u hàng đ i tr ng thái r ng thì thao tác Remove không th th c hi n đ c, trong tr ng h p khác front đ c t ng lên m t đ n v .
hang Remove(queue *pq){ if (Empty(pq)){
printf("\n Queue Empty"); delay(2000); } else { if (pq->front ==MAX-1) pq->front=0; else pq->front++; } return(pq->node[pq->front]); }
Thao tác Traver: Duy t t t c các nút trong hàng đ i. void Traver( queue *pq){
int i;
if(Empty(pq)){
printf("\n Queue Empty");
return;
}
if (pq->front ==MAX-1)
else
i = pq->front+1; while (i!=pq->rear){
printf("\n %11d % 15s", pq->node[i].mahang, pq->node[i].ten); if(i==MAX-1)
i=0;
else
i++; }
printf("\n %11d % 15s", pq->node[i].mahang, pq->node[i].ten); } D i đây là toàn b v n b n ch ng trình: #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <dos.h> #include <string.h> #include <math.h> #define MAX 50 #define TRUE 1 #define FALSE 0 typedef struct{ int mahang; char ten[20]; } hang; typedef struct {
int front, rear; hang node[MAX]; } queue;
/* nguyen mau cua ham*/ void Initialize( queue *pq); int Empty(queue *); void Insert(queue *, hang x); hang Remove(queue *);
void Traver(queue *); /* Mo ta ham */
void Initialize ( queue *pq){
pq->front = pq->rear = MAX -1; }
int Empty(queue *pq){
return(TRUE); return(FALSE); }
void Insert(queue *pq, hang x){ if (pq->rear==MAX-1 ) pq->rear=0; else
(pq->rear)++; if (pq->rear ==pq->front){
printf("\n Queue full"); delay(2000);return; } else pq->node[pq->rear]=x; } hang Remove(queue *pq){ if (Empty(pq)){
printf("\n Queue Empty"); delay(2000); } else { if (pq->front ==MAX-1) pq->front=0; else pq->front++; } return(pq->node[pq->front]); }
void Traver( queue *pq){ int i;
if(Empty(pq)){
printf("\n Queue Empty");
return; } if (pq->front ==MAX-1) i=0; else i = pq->front+1; while (i!=pq->rear){
printf("\n %11d % 15s", pq->node[i].mahang, pq->node[i].ten); if(i==MAX-1)
i=0;
else
i++; }
printf("\n %11d % 15s", pq->node[i].mahang, pq->node[i].ten); }
void main(void){ queue q;
char chucnang, front1; char c; hang mh; clrscr();
Initialize(&q); do {
clrscr();
printf("\n NGUOI SAN XUAT/ NHA TIEU DUNG"); printf("\n 1- Nhap mot mat hang");
printf("\n 2- Xuat mot mat hang"); printf("\n 3- Xem mot mat hang"); printf("\n 4- Xem hang moi nhap"); printf("\n 5- Xem tat ca");
printf("\n 6- Xuat toan bo");
printf("\n Chuc nang chon:");chucnang=getch(); switch(chucnang){
case ‘1’:
printf("\n Ma mat hang:"); scanf("%d", &mh.mahang); printf("\n Ten hang:");scanf("%s", mh.ten);
Insert(&q,mh);break;
case ‘2’:
if (!Empty(&q)){
mh=Remove(&q);
printf("\n %5d %20s",mh.mahang, mh.ten); }
else {
printf("\n Queue Empty"); delay(1000);
}
break;
case ‘3’:
front1=(q.front==MAX-1)?0:q.front+1; printf("\n Hang xuat");
printf("\n%6d%20s",q.node[front1].mahang,q.node[front1].ten); break;
case ‘4’:
printf("\n Hang moi nhap");
printf("\n%5d%20s",q.node[q.rear].mahang,q.node[q.rear].ten); break;
case ‘5’:
printf("\ Hang trong kho"); Traverse(&q);delay(2000);break; } } while(chucnang!=’0’); } 3.3. DANH SÁCH LIÊN K T N 3.3.1. Gi i thi u và đnh ngh a
M t danh sách móc n i, ho c ng n g n h n, m t danh sách, là m t dãy có th t các ph n t đ c g i là đnh. Danh sách có đi m b t đ u, g i là tiêu đ hay đnh đ u, m t đi m cu i cùng g i là đnh cu i. M i đnh trong danh sách đ u có cùng ki u ngay c khi ki u này có nhi u d ng khác nhau.
B n ch t đ ng là m t trong nh ng tính ch t chính c a danh sách móc n i. Có th thêm ho c b t đnh trong danh sách vào m i lúc, m i v trí. Vì s đnh c a danh sách không th d ki n tr c đ c, nên khi th c hi n, chúng ta ph i dùng con tr mà không dùng đ c m ng đ b o đ m vi c th c hi n hi u qu và tin c y.
M i đnh trong danh sách đ u g m hai ph n. Ph n th nh t ch a d li u. D li u có th ch là m t bi n đ n ho c là m t c u trúc (ho c con tr c u trúc) có ki u nào đó. Ph n th hai c a đnh là m t con tr ch vào đa ch c a đnh ti p theo trong danh sách. Vì v y có th d dàng s d ng các đnh c a danh sách qua m t c u trúc t tr ho c đ qui.
Danh sách móc n i đ n gi n d i đây xây d ng m i đnh c a danh sách ch l u gi m t bi n nguyên.
/*đnh c a danh sách đ n ch ch a m t s nguyên*/ struct don {
int phantu; struct don *tiep; };
typedef struct don don_t;
Trong tr ng h p này, bi n nguyên phantu c a t ng đnh ch a d li u còn bi n con tr tiep ch a đa ch c a đnh ti p theo. S đ bi u di n danh sách móc n i đ n đ c bi u di n nh hình d i đây:
Ph n_t Ph n_t Ph n_t ....
T ng quát h n, m i đnh c a danh sách có th ch a nhi u ph n t d li u. Trong tr ng h p này, h p lý h n c là đnh ngh a m t ki u c u trúc t ng ng v i d li u c n l u gi t i m i đnh. Ph ng pháp này đ c s d ng trong đnh ngh a ki u sau đây:
/*đnh c a danh sách t ng quát */ struct tq { thtin_t phantu; struc tq*tiep; }; typedef struct tq tq_t; Ki u c u trúc thtin_t ph i đ c đnh ngh a tr c đó đ t ng ng v i các d li u s đ c l u tr t i t ng đnh. Danh sách đ c t o nên t ki u đnh này gi ng nh s đ trong Hình 3.4, ngo i tr vi c m i phantu là m t bi n nguyên.
3.3.2. Các thao tác trên danh sách móc n i
Các thao tác trên danh sách móc n i bao g m vi c c p phát b nh cho các đnh và gán d li u cho con tr . danh sách đ c t o nên đúng đ n, ta bi u di n ph n t cu i danh sách là m t con tr NULL. Con tr NULL là tín hi u thông báo không còn ph n t nào ti p theo trong danh sách n a.
Ti n h n c là chúng ta đnh ngh a m t con tr t i danh sách nh sau:
struct node { int infor; struct node *next; };
typedef struct node *NODEPTR; // Con tr t i node
C p phát b nh cho m t node:
NODEPTR Getnode(void) { NODEPTR p;
P = (NODEPTR) malloc(sizeof( struct node)); Return(p);
}
Gi i phóng b nh c a m t node”
NODEPTR Freenode( NODEPTR p){ free(p);
}
Chèn m t ph n t m i vào đ u danh sách:
Các b c đ chèn m t ph n t m i vào đ u danh sách c n th c hi n là: X C p không gian b nh đ l u gi m t đnh m i;
X Thi t l p liên k t v i đnh m i.
S đ bi u di n phép thêm m t đnh m i vào đ u danh sách đ c th hi n nh trên hình 3.5.
Node c n chèn vào đ u danh sách móc n i.
Hình 3.5. Thêm đnh m i vào đ u danh sách móc n i đ n
void Push_Top( NODEPTR *plist, int x) { NODEPTR p;
p= Getnode(); // c p không gian nh cho đnh m i p -> infor = x; // gán giá tr thích h p cho đnh m i p ->next = *plist;
*plist = p; // thi t l p liên k t }
Thêm m t ph n t m i vào cu i danh sách:
thêm m t node vào cu i danh sách, ta c n th c hi n qua các b c sau: X C p phát b nh cho node m i;
X Gán giá tr thích h p cho node m i;
X Di chuy n con tr t i ph n t cu i danh sách; X Thi t l p liên k t cho node m i.
S đ th hiên phép thêm m t ph n t m i vào cu i danh sách đ c th hi n nh trong hình 3.6
Hình 3.6. Thêm node m i vào cu i danh sách.
infor next infor next infor next
infor next
infor next infor next infor next
void Push_Bottom( NODEPTR *plist, int x) { NODEPTR p, q;
p= Getnode(); // c p phát b nh cho node m i p->infor = x; // gán giá tr thông tin thích h p q = *plist; // chuy n con tr t i cu i danh sách while (q-> next != NULL)
q = q -> next;
// q là node cu i cùng c a danh sách liên k t q -> next = p; //node cu i bây gi là node p; p ->next = NULL; // liên k t m i c a p }
Thêm node m i q vào gi a danh sách tr c node p:
thêm node q vào tr c node p, chúng ta c n l u ý node p ph i có th c trong danh sách. Gi s node p là có th c, khi đó x y ra hai tình hu ng: ho c node p là node cu i cùng c a danh sách liên k t t c p->next =NULL, ho c node p ch a ph i là cu i cùng hay p->next != NULL. Tr ng h p th nh t, chúng ta ch c n g i t i thao tác Push_Bottom(). Tr ng h p th 2, chúng ta th c hi n theo các b c nh sau:
X C p phát b nh cho node m i; X Gán giá tr thích h p cho node;
X Thi t l p liên k t node q v i node k ti p p; X Thi t l p liên k t node node p v i node q; void Push_Before( NODEPTR p, int x ){
NODEPTR q; if (p->next==NULL) Push_Bottom(p, x);
else {
q= Getnode(); // c p phát b nh cho node m i q -> infor = x; // gán giá tr thông tin thích h p
q-> next = p-> next; // thi t l p liên k t node q v i node k ti p p; p->next = q; // thi t l p liên k t node p v i node k ti p q; }
}
p
q
Hình 3.7. Phép thêm ph n t vào gi a danh sách liên k t đ n.
Xoá m t node ra kh i đ u danh sách:
Khi lo i b node kh i đ u danh sách liên k t, chúng ta c n chú ý r ng n u danh sách đang r ng thì không th th c hi n vi c lo i b . Trong tr ng h p còn l i, ta th c hi n nh sau:
X Dùng node p tr t i đ u danh sách;
X D ch chuy n v trí đ u danh sách t i node ti p theo; X Lo i b liên k t v i p;
X Gi i phóng node p; void Del_Top( NODEPTR *plist) {
NODEPTR p;
p = *plist; // node p tr t i đ u danh sách; if (p==NULL) return; // danh sách r ng
(*plist) = (*plist) -> next; // d ch chuy n node g c lên node k ti p p-> next = NULL; //lo i b liên k t v i p
Freenode(p); // gi i phóng p; }
Lo i b node cu i danh sách:
M t node cu i danh sách có th x y ra ba tình hu ng sau: X Danh sách r ng: ta không c n th c hi n lo i b ;
X Danh sách ch có đúng m t node: ng v i tr ng h p lo i b node g c; Tr ng h p còn l i danh sách có nhi u h n m t node, khi đó ta ph i d ch chuy n t i node g n node cu i cùng nh t đ th c hi n lo i b .
void Del_Bottom(NODEPTR *plist) { NODEPTR p, q;
if (*plist==NULL) return; //không làm gì
else if ( (*plist)->next==NULL)) // danh sách có m t node Del_Top(plist);
else {
infor next
infor next infor next infor next
p = *plist;
while (p->next!=NULL){
q = p;
p = p->next; // q là node sau node p;
}
// p là node cu i danh sách;
q->next =NULL; //node cu i cùng là q Freenode(p); //gi i phóng p;
} }
Lo i b node gi a danh sách (tr c node p):
C n đ ý r ng, n u tr c node p là NULL (p->next==NULL) thì ta không th c hi n lo i b đ c. Tr ng h p còn l i chúng ta th c hi n nh sau:
X Dùng node q tr t i node tr c node p; X Lo i b liên k t c a q;
X Gi i phóng q. void Del_before(NODEPTR p){
NODEPTR q;
if (p->next==NULL) return; // không làm gì q = p ->next;
p->next = q->next; Freenode(q); }
B n đ c có th tìm th y nh ng cài đ t c th c a danh sách liên k t đ n trong các tài li u [1], [2].
3.4. DANH SÁCH LIÊN K T KÉP
M i khi thao tác trên danh sách, vi c duy t danh sách theo c hai chi u t ra thu n ti n h n cho ng i s d ng. ôi khi chúng ta ph i di chuy n trong danh sách t node cu i lên node đ u ho c ng c l i b ng cách đi qua m t lo t các con tr . i u này có th d dàng gi i quy t đ c n u ta t ng thông tin ch a t i t ng đnh c a danh sách. Ngoài con tr ch a đa ch đnh ti p theo, ta thêm con tr tr c đ ch a đa ch đ ng sau đnh này. Làm nh v y, chúng ta thu đ c m t c u trúc d li u m i g i là danh sách liên k t kép.
struct node {
int infor;
struct node *right;// con tr t i node sau struct node *left; // con tr t i node k ti p };
Hình 3.8. Mô t m t danh sách liên k t kép.
Các thao tác trên danh sách liên k t kép c ng t ng t nh danh sách liên k t đ n. Nh ng c n chú ý r ng, m i node p c a danh sách liên k t kép có hai đ ng liên k t là p-> left và p->right;
Thao tác thêm node m i vào đ u danh sách liên k t kép:
X C p phát b nh cho node m i; X Gán giá tr thích h p cho node m i; X Thi t l p liên k t cho node m i; void Push_Top(NODEPTR *plist, int x){
NODEPTR p;
p = Getnode(); //c p phát b nh cho node p ->infor = x; //gán giá tr thích h p; p -> right = *plist; // thi t l p liên k t ph i (*plist) ->left = p; // thi t liên k t v i *plist p-> left = NULL;// thi t l p liên k t trái *plist = p;
}
Thao tác thêm node vào cu i danh sách:
X N u danh sách r ng thì thao tác này trùng v i thao tác thêm node m i vào đ u danh sách.
X N u danh sách không r ng chúng ta th c hi n nh sau: ̇ C p phát b nh cho node;
̇ Gán giá tr thích h p cho node;
̇ Chuy n con tr t i node cu i trong danh sách; ̇ Thi t l p liên k t trái;
̇ Thi t l p liên k t ph i; void Push_Bottom(NODEPTR *plist, int x){
NODEPTR p, q; if (*plist ==NULL)
Push_Top(plist, x); else {
p= Getnode();// c p phát b nh cho node p->infor =x; //gán giá tr thích h p //chuy n con tr t i node cu i danh sách