Tạo một danh sách hàng đợi B chứa số thứ tự xếp hàng của khách

hungnguyen Vậy là em còn chả hiểu đề yêu cầu làm gì, em phải biết đề muốn em làm gì bằng cách. Thứ 1: Hiểu từng chữ trong đề nghĩa là gì, google và đọc về danh sách là gì, hàng đợi là gì, mảng là gì. Thứ 2: Em phải hình dung ra mình sẽ phải làm nó bằng công cụ nào mà ở đây là ngôn ngữ lập trình, công nghệ nào.

Thứ 3: Em sẽ phải hiểu các thao tác cơ bản với những khái niệm ở bước 1 được sử dụng trong bước 2 như thế nào. Ví dụ: hãy tìm kiếm: "Hàng đợi trong python", "hàng đợi trong C#", ... Trước khi tìm kiếm những điều này em phải hiểu hàng đợi là gì và nó hoạt động như thế nào trong bước 1 trước.

  • #1

    ai có thể giúp mk được ko plsss :(( thực sự qá khó vs mk Đề 2 viết chương trình mô phỏng quy trình sắp xếp hàng đặt vế xem phim như sau : Danh sách liên kết A chứa số ghế của các ghế trống trong rạp (ban đàu khởi tạo các số ghế từ 1 đến n). danh sách hàng đợi B chứa số thứ tự xếp hàng của khách. dang sách liên kết C chứa thông tin khách hàng đã mua vé( số ghế, tên) chức năng lấy số xếp hàng: thêm vào nút B, nếu B rỗng thì nút thêm sẽ có số thứ tự xếp hàng là 1 ,ngược lại thì số thứ tự xếp hàng là K+1 với K là số thứ tự của nút cuối của B chức năng mua vé:nếu còn ghế trống và có khách đang chờ mua vé thì xóa nút khỏi B ,lấy tên khách hàng và số ghế khách chọn để thêm nút C đồng thời loại số ghế đó khỏi A chức năng hủy vé : xóa nút khỏi C dồng thời loại số ghế đó khỏi A,

    chức năng hiển thị : hiển thị thông tin những vé đã bán ( DSLK C

  • #2

    // quanlybanve.cpp : Defines the entry point for the console application. // #include"stdafx.h" #include <iostream> #include <string> using namespace std; struct NodeA { int soghetrong; NodeA *tiep; }; struct listA { NodeA*dau, *cuoi; }; typedef struct QueueA *maytrong; struct NodeB { int sothutuxephang[33]; NodeB *tiep; }; struct QueueB { NodeB *dau, *cuoi; }; struct NodeC { char tenkhach[33]; int soghe; NodeC *tiep; }; struct ListC { NodeC *dau, *cuoi; }; void putA(listA &m, int x) { NodeA *data1 = new NodeA[1]; data1->soghetrong = x; data1->tiep = NULL; if (m.dau == NULL)m.dau = m.cuoi = data1; else { m.cuoi->tiep = data1; m.cuoi = data1; } } int get(listA &m) { NodeA *x = new NodeA[1]; x = m.dau; m.dau = m.dau->tiep; int y = x->soghetrong; delete x; return y; } void showA(listA m) { NodeA *x1; x1 = m.dau; cout << "---------------------------------------------------------"; if (x1 == NULL) cout << "\nKhong con ghe trong nao ca"; } void showC(ListC m) { NodeC *x2; x2 = m.dau; if (x2 == NULL) cout << "\ndanh sach rong"; else { cout << "\nDanh sach khach hang mua ve:"; cout << "\nten khach\t\tsoghe"; do { cout << x2->tenkhach << "\t" << x2->soghe << "\t" << endl; x2 = x2->tiep; } while (x2 != NULL); } } void putC(ListC &a, int soghe, char tenkhach[33]) { NodeC *h = new NodeC[1]; (h->tenkhach, tenkhach); h->soghe = soghe; h->tiep = NULL; if (a.dau == NULL) a.dau = a.cuoi = h; else { a.cuoi->tiep = h; a.cuoi = h; } } void getC(ListC &C, int x) { NodeC *h; h = C.dau; if (h->soghe == x) { C.dau = C.dau->tiep; delete h; } else { while (h->tiep->soghe != x&&h != C.cuoi) h = h->tiep; if (h == C.cuoi)cout << "\nXoa that bai"; else { NodeC *h2; h2 = h->tiep; if (h2 != C.cuoi) h->tiep = h->tiep->tiep; else { h->tiep = NULL; C.cuoi = h; } delete h2; } } } void putB(QueueB &m, int sothutuxephang) { NodeB *data2 = new NodeB[1]; data2->tiep = NULL; if (m.dau == NULL) m.cuoi = m.dau = data2; else { m.cuoi->tiep = data2; m.cuoi = data2; } } void getB(QueueB &B, int sothutuxephang) { NodeB *data3; data3 = B.dau; B.dau = B.dau->tiep; delete data3; } void showB(QueueB m) { NodeB *x4; x4 = m.dau=m.cuoi=NULL; if (x4 == NULL) cout << "\nKhong co khach hang nao ca"; else { cout << "\nso thu tu xep hang cua khach:"; while (x4 != NULL) { cout << "so thu tu xep hang " << x4->sothutuxephang; x4 = x4->tiep; } } } void muave(listA &A, QueueB &B, ListC &C) { char ten[33]; int soghe; cout << "\n---------------------------------------------------------"; cout << "Nhap ten khach:"; cin.ignore(1); cin.getline(ten,33); if (A.dau != NULL)//A khac rong { cout << "nhap so ghe: "; cin >> soghe; int z = get(A); putC(C, soghe, ten); cout << "Da cap ghe cho khach hang:" << z << ten[20]; } else { cout << "Khong con ghe trong nen khach da duoc them vao hang doi B:"; putB(B, soghe); } } void xoave(listA &A, ListC &C) { int x5; cout << "---------------------------------------------------------"; if (C.dau == NULL) cout << "\nKhong co khach hang nao tra ve"; else { cout << "\nNhap vao so ghe muon huy: "; cin >> x5; //Tim xem x co trong C khong? NodeC *h; h = C.dau; while (h != NULL) { if (h->soghe == x5)break; else h = h->tiep; } if (h != NULL)//Co x trong C { //Loai bo h khoi C getC(C, x5); //Them x vao A putA(A, x5); cout << "Tra ghe thanh cong, so ghe duoc dua vao danh sach A"; cin >> x5; } else cout << "So ghe tra nhap khong chinh xac"; } } int main() { listA A;//DS ghe trong QueueB B;//Danh sach khach lay so thu tu xep hang ListC C;//thong tin khach mua ve A.dau = A.cuoi = NULL; B.dau = B.cuoi = NULL; C.dau = C.cuoi = NULL; //Khoi tao A cout << "Nhap so ghe cua cac ghe trong trong rap: "; int n; cin >> n; for (int i = 1;i <= n;i++) putA(A, i); int check; lap: cout << endl << endl << " QUAN LY BAN VE XEM PHIM O RAP " << endl; cout << " -------------------------------------------------------------" << endl; cout << " | Lua chon cac chuc nang. |" << endl; cout << " | Bam so 1 :lay so xep hang. |" << endl; cout << " | Bam so 2 :de chon chuc nang mua ve. |" << endl; cout << " | Bam so 3 :de chon chuc nang huy ve. |" << endl; cout << " | bam so 4 :de hien thi thong tin. |" << endl; cout << " | Bam so 0 :neu ban muon thoat khoi chuong trinh. |" << endl; cout << " -------------------------------------------------------------" << endl << endl; cin >> check; switch (check) { case 0:return 0; case 1:showB(B); goto lap; case 2: muave(A, B, C); goto lap; case 3: xoave(A, C); goto lap; case 4: showC(C); goto lap; default:cout << "Xin moi ban lua chon lai: "; goto lap; } }

    vẫn còn vài chức năng chưa ổn đinh

    Tạo một danh sách hàng đợi B chứa số thứ tự xếp hàng của khách

  • This entry is part 2 of 16 in the series Cấu trúc dữ liệu

    71 / 100

    Ở bài này chúng ta sẽ tìm hiểu về cấu trúc dữ liệu Hàng đợi(Queue). Đây là cấu trúc dữ liệu đặc biệt không cho phép truy cập trực tiếp tới các phần tử ở giữa. Bài này sẽ trình bày cho các bạn lý thuyết về hàng đợi, cách cài đặt hàng đợi và một số biến thể của hàng đợi trong C/C++. 

    1. Lý thuyết về hàng đợi

    Hàng đợi(tiếng anh: Queue) là một cấu trúc dữ liệu dùng để lưu giữ các đối tượng theo cơ chế FIFO (viết tắt từ tiếng Anh: First In First Out), nghĩa là “vào trước ra trước”.

    Hình ảnh về hàng đợi rất hay gặp trong đời sống hàng ngày, hình ảnh việc xếp hàng dưới đây là một mô phỏng dễ hiểu nhất cho cấu trúc dữ liệu hàng đợi(queue): Người vào đầu tiên sẽ được tiến đón đầu tiên;Người mới vào bắt buộc phải xếp hàng ở phía cuối.

    Tạo một danh sách hàng đợi B chứa số thứ tự xếp hàng của khách
    Cấu trúc dữ liệu hàng đợi

    Trong cấu trúc hàng đợi(queue), ta chỉ có thể thêm các phần tử vào một đầu của queue(giả sử là cuối), và cũng chỉ có thể xóa phần tử ở đầu còn lại của queue(tạm gọi là đầu). Như vậy, ở một đầu không thể xảy ra hai hành động thêm và xóa đồng thời.

    Như vậy, với cấu trúc Hàng đợi(Queue), chúng ta có các chức năng sau:

    • EnQueue: Thêm phần tử vào cuối(rear) của Queue.
    • DeQueue: Xóa phần tử khỏi đầu(front) của Queue. Nếu Queue rỗng thì thông báo lỗi.
    • IsEmpty: Kiểm tra Queue rỗng.
    • Front: Lấy giá trị của phần tử ở đầu(front) của Queue. Lấy giá trị không làm thay đổi Queue.

    2. Cài đặt hàng đợi bằng mảng

    Ở mục này, chúng ta sẽ thực hiện cài đặt các chức năng của Queue đã nói ở phần trước. Mục này tôi sẽ cùng các bạn đi cài đặt queue bằng mảng, bởi vì nó sẽ đơn giản hơn, giúp các bạn dễ hiểu hơn. Các cách cài đặt khác sẽ được trình bày ở phần sau.

    Để cài đặt được Queue, chúng ta sẽ cần sử dụng các biến như sau:

    • queue[]: Một mảng một chiều mô phỏng cho hàng đợi
    • arraySize: Số lượng phần tử tối đa có thể lưu trữ trong queue[]
    • front: Chỉ số của phần tử ở đang đầu queue. Nó sẽ là chỉ số của phần tử sẽ bị xóa ở lần tiếp theo
    • rear: Chỉ số của phần tử tiếp theo sẽ được thêm vào cuối của queue

    Bây giờ ta sẽ đi vào cài đặt từng chức năng của Hàng đợi:

    2.1. Enqueue – Thêm vào cuối hàng đợi

    Nếu hàng đợi chưa đầy, chúng ta sẽ thêm phần tử cần thêm vào cuối(rear) của hàng đợi. Ngược lại, thông báo lỗi.

    Các bạn lưu ý, rear là chỉ số của phần tử sẽ được thêm ở lần tiếp theo. Do đó, thêm xong rồi ta mới tăng rear lên 1 đơn vị. Giá trị rear cần thay đổi nên được truyền theo tham chiếu.

    void Enqueue(int queue[], int element, int& rear, int arraySize) {

        if(rear == arraySize)            // Queue is full

                printf("OverFlow\n");

        else{

             queue[rear] = element;    // Add the element to the back

             rear++;

        }

    }

    2.2. Dequeue – Xóa khỏi đầu hàng đợi

    Nếu hàng đợi có ít nhất 1 phần tử, chúng ta sẽ tiến hành xóa bỏ phần tử ở đầu của hàng đợi bằng cách tăng front lên 1 giá trị.

    Ở đây, front đang là chỉ số của phần tử sẽ bị xóa rồi. Cho nên chỉ cần tăng là xong, đó cũng là lý do ta cần truyền tham số front sử dụng tham chiếu.

    void Dequeue(int queue[], int& front, int rear) {

        if(front == rear)            // Queue is empty

            printf("UnderFlow\n");

        else {

            queue[front] = 0;        // Delete the front element

            front++;

        }

    }

    Tới đây chắc nhiều bạn thắc mắc tại sao lại tăng front mà không phải là giảm. Các bạn xem giải thích ở hình sau nhé:

    Tạo một danh sách hàng đợi B chứa số thứ tự xếp hàng của khách
    Lý giải tại sao tăng front khi dequeue

    2.3. Front – Lấy giá trị ở đầu hàng đợi

    Hàm này sẽ lấy và trả về giá trị của phần tử đang ở đầu hàng đợi

    int Front(int queue[], int front) {

        return queue[front];

    }

    2.4. Các hàm hỗ trợ khác

    Hàm lấy kích thước của Hàng đợi, nói cách khác là số lượng phần tử đang có trên hàng đợi

    int Size(int front, int rear) {

        return (rear - front);

    }

    Hàm kiểm tra queue rỗng

    bool IsEmpty(int front, int rear) {

        return (front == rear);

    }

    Tạo một danh sách hàng đợi B chứa số thứ tự xếp hàng của khách
    Cơ chế hoạt động của hàng đợi(chỉ số tăng theo chiều từ trên xuống dưới)

    3. Ứng dụng của hàng đợi

    Để thấy được vai trò của cấu trúc dữ liệu queue cũng như hiểu hơn về nó. Chúng ta sẽ đi vào một bài toán cụ thể như sau:

    Bạn có một chuỗi ký tự. Hãy lấy ký tự ở đầu của chuỗi và thêm nó vào cuối chuỗi. Hãy cho tôi thấy sự thay đỗi của chuỗi sau khi thực hiện hành động trên N lần.

    Ý tưởng: Chuỗi ký tự trên có thể xem xét như là một hàng đợi. Tại mỗi bước, chúng ta sẽ dequeue(xóa) phần tử ở đầu chuỗi và thực hiện enqueue(thêm) phần tử đó cuối chuỗi. Lặp lại N lần bước công việc này, chúng ta sẽ có câu trả lời.

    Lời giải:

    0

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    #include <iostream>

    #include <cstdio>

    using namespace std;

    void Enqueue(char queue[], char element, int& rear, int arraySize) {

        if(rear == arraySize)            // Queue is full

            printf("OverFlow\n");

        else {

            queue[rear] = element;    // Add the element to the back

            rear++;

        }

    }

    void Dequeue(char queue[], int& front, int rear) {

        if(front == rear)            // Queue is empty

            printf("UnderFlow\n");

        else {

            queue[front] = 0;        // Delete the front element

            front++;

        }

    }

    char Front(char queue[], int front) {

        return queue[front];

    }

    int main() {

        char queue[20] = {'a', 'b', 'c', 'd'};        

        int front = 0, rear = 4;                

        int arraySize = 20;                // Size of the array

        int N = 3;                    // Number of steps

        char ch;

        for(int i = 0;i < N;++i) {

            ch = Front(queue, front);

            Enqueue(queue, ch, rear, arraySize);

            Dequeue(queue, front, rear);

        }

        for(int i = front;i < rear;++i)

            printf("%c", queue[i]);

        printf("\n");

        return 0;

    }

    4. Các biến thể của Queue

    Trong mục này, chúng ta sẽ đi tìm hiểu về 2 biến thể khác của hàng đợi. Các biến thể này là cải tiến của hàng đợi tiêu chuẩn phía trên nhưng vẫn tuân thủ quy luật của hàng đợi. Các biến thể này có ưu điểm hơn và tính ứng dụng tốt hơn.

    1. Double-ended queue(Hàng đợi 2 đầu)
    2. Circular queue(Hàng đợi vòng)

    4.1. Hàng đợi 2 đầu

    Trong hàng đợi tiêu chuẩn phía trên, dữ liệu được thêm ở cuối và xóa đi ở đầu của hàng đợi. Nhưng với Double-ended queue, dữ liệu có thể thêm hoặc xóa ở cả đầu(front) và cuối(rear) của hàng đợi.

    Nào, hãy cùng tôi đi cài đặt các hàm cho các chức năng của queue 2 đầu nào.

    Thêm dữ liệu vào cuối queue

    void InsertAtBack(int queue[], int element, int &rear, int array_size){

        if(rear == array_size)

            printf("Overflow\n");

        else{

            queue[rear] = element;

            rear = rear + 1;

        }

    }

    Xóa dữ liệu ở cuối queue

    void DeleteFromBack(int queue[], int &rear, int front){

        if(front == rear)

            printf("Underflow\n");

        else{

            rear = rear - 1;

            queue[rear] = 0;

        }

    }

    Thêm dữ liệu vào đầu queue

    void InsertAtFront(int queue[], int &rear, int &front, int element, int array_size){

        if(rear == array_size)

            printf("Overflow\n");

        else{

            for(int i=rear; i>front; i--)

                queue[i] = queue[i-1];

            queue[front] = element;

            rear = rear+1;

        }

    }

    Xóa dữ liệu ở đầu queue

    void DeleteAtFront(int queue[], int &front, int &rear){

        if(front == rear)

            printf("Underflow\n");

        else{

            queue[front] = 0;

            front = front + 1;

        }

    }

    Lấy giá trị ở đầu queue

    int GetFront(int queue[], int front){

        return queue[front];

    }

    Lấy giá trị ở cuối queue

    int GetRear(int queue[], int rear){

        return queue[rear-1];

    }

    Các hàm chức năng khác như SizeIsEmpty giống với hàng đợi tiêu chuẩn.

    4.2. Hàng đợi vòng

    Hàng đợi vòng là một cải tiến của hàng đợi tiêu chuẩn. Trong hàng đợi tiêu chuẩn, khi một phần tử bị xóa khỏi hàng đợi, các vị trí bị xóa đó sẽ không được tái sử dụng. Hàng đợi vòng sinh ra để khắc phục sự lãng phí này.

    Tạo một danh sách hàng đợi B chứa số thứ tự xếp hàng của khách
    Hàng đợi vòng sử dụng lại các vị trí đã bị xóa ở đầu mảng

    Trong khi thêm phần tử vào hàng đợi vòng, nếu chỉ số rear đã ở vị trí cuối của mảng, khi đó bạn vẫn có thể thêm vào hàng đợi bằng cách thêm vào phía đầu của mảng(đó là các vị trí ở đầu mảng đã bị xóa đi và chưa được dùng).

    Để cài đặt hàng đợi vòng, ngoài các biến sử dụng trong hàng đợi tiêu chuẩn, chúng ta cần thêm một biến khác nữa để lưu số lượng phần tử đang có trong hàng đợi, đặt nó là count

    Bây giờ chúng ta cùng đi viết các hàm cho hàng đợi vòng nhé.

    Enqueue

    void Enqueue(int queue[], int element, int& rear, int arraySize, int& count) {

        if(count == arraySize)            // Queue is full

                printf(“OverFlow\n”);

        else{

            queue[rear] = element;

            rear = (rear + 1)%arraySize;

            count = count + 1;

        }

    }

    Mình giải thích tại sao lại là (rear + 1)%arraySize : Giả sử khi rear = arraySize - 1, khi đó với hàng đợi tiêu chuẩn bạn sẽ không thể thêm nữa. Nhưng với hàng đợi vòng, ta sẽ thêm chừng nào count != arraySize. arraySize là số phần tử tối đa có thể có, do vậy, count != arraySize nghĩa là còn ô trống để insert vào queue. Chỉ số được insert vào queue như sau(giả sử arraySize = 3 nhé):

    • Nếu rear = 0, giá trị rear thực là (0 + 1) % 3 = 1
    • Nếu rear = 1, giá trị rear thực là (1 + 1) % 3 = 2
    • Nếu rear = 2, giá trị rear thực là (2 + 1) % 3 = 0

    Các bạn nên nhớ: rear là chỉ số của phần tử sẽ được insert ở lần tiếp theo. Mỗi khi dequeue, count sẽ phải giảm đi 1. Ngược lại, nếu enqueue thành công, count sẽ tăng lên 1.

    Giải thích này cũng đúng với front trong hàm dequeue dưới đây.

    Dequeue

    void Dequeue(int queue[], int& front, int rear, int& count) {

        if(count == 0)            // Queue is empty

            printf(“UnderFlow\n”);

        else {

            queue[front] = 0;        // Delete the front element

            front = (front + 1)%arraySize;

            count = count - 1;

        }

    }

    Front

    int Front(int queue[], int front) {

        return queue[front];

    }

    Size

    int Size(int count) {

        return count;

    }

    IsEmpty

    bool IsEmpty(int count) {

        return (count == 0);

    }

    5. Bài tập thực hành

    Dưới đây là một số bài tập thực hành về kiến thức hàng đợi:

    • Bài tập hàng đợi – Luyện Code
    • https://www.spoj.com/PTIT/problems/P175SUME/
    • https://vn.spoj.com/problems/MSE07B/
    • https://www.hackerearth.com/practice/data-structures/queues/basics-of-queues/practice-problems/