Đồ án ” Bài toán Quản lý sinh viên bằng danh sách liên kết đơn ” pdf

Ngày đăng: 06/03/2014, 00:22

Quản sinh viên bằng danh sách liên kết đơncNguyễn Ngọc Quang 1Đề tài: Quản sinh viên bằng danh sách liên kết đơnPhần Mở đầu1. do chọn chủ đề:CNTT là một trong những nghề lớn mạnh vượt bậc trong những năm gần đây. Ngày nay với sự lớn mạnh lập tức của xã hội thì CNTT được áp dụng rộng rãi ở đa số toàn bộ các ngành nghề & ngày càng đóng vai trò quan trọng, trở thành một phần cần thiết trong đời sống hằng ngày. CNTT là một nghề đòi hỏi ở người học một nền móng tri thức bền vững, sự suy nghĩ logic cao, hiểu biết sâu rộng trên nhiều ngành nghề. Với chúng em hiện còn đang là những sinh viên CNTT phải có sự đầu tư, không ngừng học hỏi để chuyên sâu tri thức. Do đó để củng cố lại tri thức đã học, chủ đề mà em chọn để thực hiện đồ án là: Bài toán Quản sinh viên bằng danh sách liên kết đơn 2. Mục tiêu của chủ đề.- Củng cố lại tri thức đã học về danh sách liên kết nói chung & danh sách liên kết đơn nói riêng.- Tập luyện tuyệt kỹ lập trình trên từ ngữ C++.- Vận dụng thuyết đã học khắc phục bài toán áp dụng cụ thể3. Phạm vi phân tích.- thuyết về danh sách liên kết đơn- Bài toán quản sinh viên4. Cách thức phân tích.- Phân tích ebook cấu tạo dữ liệu & giải thuật trên sách.- Tìm kiếm & phân tích trên mạng Mạng internet. Nguyễn Ngọc Quang 2Đề tài: Quản sinh viên bằng danh sách liên kết đơnCHƯƠNG 1: CƠ SỞ LÝTHUYẾT1. Tổng quan về danh sách liên kết1.1. Định nghĩaDanh sách liên kếtdanh sách mà các phần tử ( Node) liên kết với nhau nhờ vào vùng liên kết của chúng. Mỗi node bao gồm 2 phần: Phần Data dùng để chứa dữ liệu cần xử & phần liên kết dùng để liên kết tới các node khác.1.2 .Phân loại.Tùy cách liên kết giữa các phần tử, danh sách liên kết gồm có nhiều loại khác nhau:- Danh sách liên kết đơn: mỗi phần tử liên kết với phần tử xếp sau nó trong danh sách.- Danh sách liên kết đôi/kép: mỗi phần tử liên kết với các phần tử đứng trước & sau nó trong danh sách.- Danh sách liên kết vòng: phần tử cuối danh sách liên kết với phần tử đầu danh sách.1.3. Danh sách liên kết đơn.1.3.1. Định nghĩa.Danh sách liên kết đơn là một cấu tạo lưu trữ trong đó các phần tử của danh sách không cố định, các phần tử trong danh sách chẳng thể truy cập trực tiếp. Mong muốn truy cập bất kỳ phần tử nào đó trong danh sách phải bắt nguồn từ phần tử trước hết. Mỗi Node trong danh sách có thể được trình diễn như sau.Trong số đó:- Data: trường chưa bài viết thông tin của phần tử- Next: chứa địa chỉ của Node kế đến hay có cách gọi khác là vùng liên kết.Cú pháp:Nguyễn Ngọc Quang 3Data NextĐề tài: Quản sinh viên bằng danh sách liên kết đơnStuct Node {Kiểu_dữ_liệu Data;Node*next; }Có thể hình dung danh sách liên kết đơn qua hình vẽ sau:Hình 1.1: Danh sách liên kết đơn1.3.2.Thao tác trên 1 node.- Khai báo biến con trỏ p là biến con trỏ kiểu Node: Node *p.- Cấp phát bộ nhớ lưu trữ cho Node mới – được trỏ bởi p: p=new Node.- Truy cập vào trường info: p->info.- Truy cập vào trường next : p->next.- Hủy Node được trỏ bởi p: delete (p).1.3.3. Các thao tác trên danh sách liên kết đơnThao tác trên danh sách liên kết khác với thao tác trên mảng, khi cần thêm Node vào danh sách liên kết thì ta xin cấp phát bộ nhớ lưu trữ cho Node & nối Node đó vào danh sách & khi không sử dụng thì ta giải phóng nó khỏi danh sách. Truy cập trên danh sách cũng khác đối với trên mảng. Nếu ở mảng ta truy cập trực tiếp thông qua chỉ số mảng (thông qua địa chỉ ô nhớ) thì ở danh sách liên kết ta phải truy cập một cách tuần tự. Khi làm việc trên danh sách liên kết đơn không khác gì với vậy nên ta cần lưu ý những điểm sau:- Danh sách luôn có con trỏ đầu danh sách: con trỏ L- Danh sách luôn có giá trị báo kết thúc danh sách: NULL.- Trường next của mỗi Node chỉ chứa địa chỉ của Node sau nó, trừ Node cuối.- Trường next của Node cuối cùng chứa giá trị NULL.- Không tách danh sách thành 2 danh sách con nếu danh sách phần sau chưa có con trỏ tới.- Khởi tạo danh sách rỗng: L = NULLNguyễn Ngọc Quang 4Đề tài: Quản sinh viên bằng danh sách liên kết đơn1.3.3.1. Duyệt danh sách liên kết đơnDuyệt lần lượt qua từng Node của danh sách.Mục_đích(Node *L){ Node *p=L; //cho con trỏ p trỏ vào đầu danh sách L.while(!điều kiện dừng){ [xử p->info];//xuất thông tin ra màn hình, thực hiện các phép toán… p= p->Next; //cho con trỏ p trỏ tới Node tiếp theo. }1.3.3.2. Chèn một phần tử vào danh sáchĐể chèn một phần tử X vào danh sách ta cấp phát bộ nhớ lưu trữ cho 1 Node mới được trỏ bởi q & gán giá trị X cho trường infoNode *q;q=new Node;q->info=X;Chèn một Node mới vào danh sách có 4 trường hợp:- Trường hợp 1: Chèn Node được trỏ bởi q vào đầu sáchBước 1: cho vùng liên kết của q chứa địa chỉ Node đầu danh sách.q->next=L;(1)Bước 2: cho L trỏ tới q : cập nhập lại con trỏ đầu danh sách.L = q; (2)Nguyễn Ngọc Quang 5Đề tài: Quản sinh viên bằng danh sách liên kết đơnHình 1.2: ….- Trường hợp 2: Chèn Node được trỏ bởi q vào sau Node trỏ bởi p trong danh sáchBước 1: Cho vùng liên kết của Node được trỏ bởi q chứa địa chỉ Node ngay sau Node được trỏ bởi p.q->next=p->next; (1)Bước 2: Cho vùng liên kết của Node được trỏ bởi q chứa địa chỉ của Node được trỏ bởi p.p->next=q; (2)Hình 1.3: …- Trường hợp 3: Chèn Node được trỏ bởi q vào cuối danh sáchBước 1: Nếu danh sách rỗng thì danh sách bây giờ có 1 phần tử chính là q vừa mới chèn vào, return.Bước 2: Trái lại nếu danh sách không rỗng• Cho con trỏ p chứa địa chỉ Node đầu danh sách: Nguyễn Ngọc Quang 6Đề tài: Quản sinh viên bằng danh sách liên kết đơnNode *p=L;• Duyệt danh sách từ đầu cho tới Node cuối cùngwhile(p->next!=NULL) p=p->next;• Cho phần liên kết của Node được trỏ bởi p chứa địa chỉ của q p->next=q;• Cập nhập lại Node cuối cùng lúc này chính là Node q vừa mới tạo thành.q->next=NULL;- Trường hợp 4: Chèn Node được trỏ bởi q vào trước Node được trỏ bởi pBước 1: Nếu p trỏ đầu danh sách, thực hiện chèn đầu danh sách(trường hợp1), return.Bước 2: Trái lại cho con trỏ t chứa địa chỉ Node trước Node được trỏ bởi p trong danh sách: Node *t; t->next=p;Chèn Node được trỏ bởi q vào sau Node được trỏ bởi t (trường hợp 2).1.3.3.3. Xóa một phần tử ra khỏi danh sách: có 2 trường hợp xảy ra- Trường hợp 1: Thực hiện xóa đầu danh sách nếu p chứa địa chỉ Node đầudanh sách (L)Bước 1: Cho con trỏ đầu danh sách L trỏ vào Node sau nó.L=L->next; (1)Bước 2: Giải phóng Node p ra khỏi danh sách.Delete(p);Nguyễn Ngọc Quang 7Đề tài: Quản sinh viên bằng danh sách liên kết đơnHình 1.4: …- Trường hợp 2: Con trỏ p chứa địa chỉ Node bất kỳ nhưng không phải Node đầuBước 1: Cho con trỏ q trỏ đầu danh sách L , dùng vòng lặp cho nó trỏ tới địa chỉ Node trước Node được trỏ bởi p trong danh sách.q=L; while(q->next!=p) q=q->next; (1)Bước 2: Gán địa chỉ của Node ngay sau Node được trỏ bởi p vào ô nhớ next của Node được trỏ bởi qq->Next=p->next; (2)Bước 3: Giải phóng Node được trỏ bởi pdelete(p);(3)Hình 1.5: …Nguyễn Ngọc Quang 8Đề tài: Quản sinh viên bằng danh sách liên kết đơn1.3.4.4. Tìm kiếm phần tử trong danh sáchBước 1: Cho p trỏ vào đầu danh sách L & khởi tạo biến found=0Node *p=L; int found=0;Bước 2: Thực hiện vòng lặp để duyệt p chạy từ đầu danh sách tới cuối danh sách, tại mỗi Node nếu trường info của Node được trỏ bởi p =X thì cho found=1 để dừng vòng lặp. Trái lại nếup!=X thì cho p trỏ tới địa điểm Node ngay sau Node được trỏ bởi p.while(p!=NULLvàamp;&found= =0)if(p->info=X) found=1;else p=p->next; (*)Bước 3: Return pHình 1.6: 1.3.3.5. Đảo các phần tử trong danh sáchBước 1: Khởi tạo 3 biến con trỏ p, t, q. Trong đó p trỏ vào đầu danh sách L, t= NULL (không trỏ vào địa chỉ nào cả), q trỏ vào địa chỉ Node được trỏ bởi p.Node *p=L,*t=NULL,*q=p ;Nguyễn Ngọc Quang 9Đề tài: Quản sinh viên bằng danh sách liên kết đơnBước 2: Dùng vòng lặp duyệt p chạy từ đầu tới cuối danh sách. Trong lúc thực hiện vòng lặp• Cho vùng liên kết của Node được trỏ bởi q chứa địa chỉ của tq->next=t;• Cho t trỏ đến địa điểm Node được trỏ bởi q (cập nhập lại t). t=q;Rõ ràng như sau:While(p!=NULL){ q=p; p=p->next; (1)q->next=t ; (2)t=q; (3) }B ước 3 :Cho L trỏ đến địa điểm Node được trỏ bởi t (cập nhập lại L)L=tHình 1.7: Nguyễn Ngọc Quang 10[…]… bằng danh sách liên kết đơn } // int main() { menu_chinh(); } 2.6 Màn hình kết quả 2.6.1 List chính của chương trình Nguyễn Ngọc Quang 34 Chủ đề: danh sách sinh viên 2.6.3 Hiển thị danh sách sinh viên Nguyễn Ngọc Quang 35 Chủ đề: sinh viên theo mã sinh viên. .. SINH VIÊN 2.1 Đặc tả quản học sinh- sinh viên Công việc quản sinh viên đòi hỏi tính tỉ mỉ, thận trọng trong từng khâu ghi chép các thông tin cá nhân của sinh viên: mã số sinh viên, tên sinh viên, ngày tháng năm sinh, … danh sách sinh viên – In thông tin sinh viên ra màn hình Nguyễn Ngọc Quang 12 Chủ đề: sinh viên theo mã sinh viên – Duyệt qua danh sách – Tìm kiếm theo mã sinh viên mà người dùng yêu cầu – Hiển thị sinh viên vừa tìm thấy màn hình 2.3.2.4.Xóa sinh viên theo mã số sinh viên – Duyệt qua danh sách – Tìm kiếm sinh viên theo mã sinh viên mà người… ch=getch(); cin.sync(); }while(ch!=27); }} 2.4.3 Hiển thị danh sách sinh viên void xuat(node first) { node p; p=first; while(p!=NULL) { cout< >ma; while(p!=NULL&&p->masv!=ma) . tài: Quản lý sinh viên bằng danh sách liên kết đơn CHƯƠNG 2: ỨNG DỤNG DANH SÁCH LIÊN KẾT ĐƠN VÀO QUẢNLÝ SINH VIÊN.2.1. Đặc tả bài toán. Quản lý sinh viên. tài: Quản lý sinh viên bằng danh sách liên kết đơn CHƯƠNG 1: CƠ SỞ LÝTHUYẾT1. Tổng quan về danh sách liên kết 1.1. Định nghĩa Danh sách liên kết là danh sách

Xem Thêm  Web IDL Standard - typeerror list object is not callable

Đề tài:đơncNguyễn Ngọc Quang 1Đề tài:đơnPhần Mở đầu1.chọn đề tài:Công nghệ thông tin là một trong những ngành phát triển vượt bậc trong những năm gần đây. Ngày nay với sự phát triển nhanh chóng của xã hội thì công nghệ thông tin được ứng dụng rộng rãi ở hầu hết tất cả các lĩnh vực và ngày càng đóng vai tròtrọng, trở thành một phần thiết yếu trong đời sống hằng ngày. Công nghệ thông tin là một ngành đòi hỏi ở người học một nền tảng kiến thức vững chắc, sự tư duy logic cao, hiểu biết sâu rộng trên nhiều lĩnh vực. Với chúng em hiện đang là nhữngcông nghệ thông tin cần phải có sự đầu tư, không ngừng học hỏi để nâng cao kiến thức.để củng cố lại kiến thức đã học, đề tài mà em chọn để thực hiệnlà:Quản2. Mục tiêu của đề tài.- Củng cố lại kiến thức đã học vềnói chung vàsáchnói riêng.- Rèn luyện kỹ năng lập trình trên ngôn ngữ C++.- Ứng dụngthuyết đã học giải quyếtứng dụng cụ thể3. Phạm vi nghiên cứu.-thuyết vềđơn-viên4. Phương pháp nghiên cứu.- Nghiên cứu tài liệu cấu trúc dữ liệu và giải thuật trên sách.- Tìm kiếm và nghiên cứu trên mạng Internet. Nguyễn Ngọc Quang 2Đề tài:đơnCHƯƠNG 1: CƠ SỞ LÝTHUYẾT1. Tổngvềkết1.1. Định nghĩaDanhlàmà các phần tử ( Node)với nhau nhờ vào vùngcủa chúng. Mỗi node bao gồm 2 phần: Phần Data dùng để chứa dữ liệu cần xửvà phầndùng đểtới các node khác.1.2 .Phân loại.Tùy cáchgiữa các phần tử,gồm có nhiều loại khác nhau:-đơn: mỗi phần tửvới phần tử đứng sau nó trongsách.-đôi/kép: mỗi phần tửvới các phần tử đứng trước và sau nó trongsách.-vòng: phần tử cuốivới phần tử đầusách.1.3.đơn.1.3.1. Khái niệm.Danhlà một cấu trúc lưu trữ trongcác phần tử củakhông cố định, các phần tử trongkhông thể truy cập trực tiếp. Muốn truy cập bất kỳ phần tử nàotrongphải xuất phát từ phần tử đầu tiên. Mỗi Node trongcó thể được biểu diễn như sau.Trong đó:- Data: trường chưa nội dung thông tin của phần tử- Next: chứa địa chỉ của Node tiếp theo hay còn gọi là vùngkết.Cú pháp:Nguyễn Ngọc Quang 3Data NextĐề tài:đơnStuct Node {Kiểu_dữ_liệu Data;Node*next; }Có thể hình dungqua hình vẽ sau:Hình 1.1:đơn1.3.2.Thao tác trên 1 node.- Khai báo biến con trỏ p là biến con trỏ kiểu Node: Node *p.- Cấp phát bộ nhớ cho Node mới – được trỏ bởi p: p=new Node.- Truy cập vào trường info: p->info.- Truy cập vào trường next : p->next.- Hủy Node được trỏ bởi p: delete (p).1.3.3. Các thao tác trênđơnThao tác trênkhác với thao tác trên mảng, khi cần thêm Node vàothì ta xin cấp phát bộ nhớ cho Node và nối Nodevàosách và khi không sử dụng thì ta giải phóng nó khỏisách. Truy cập trêncũng khác so với trên mảng. Nếu ở mảng ta truy cập trực tiếp thông qua chỉ số mảng (thông qua địa chỉ ô nhớ) thì ởta phải truy cập một cách tuần tự. Khi làm việc trêncũng tương tự như vậy nên ta cần chú ý những điểm sau:-luôn có con trỏ đầusách: con trỏ L-luôn có giá trị báothúcsách: NULL.- Trường next của mỗi Node chỉ chứa địa chỉ của Node sau nó, trừ Node cuối.- Trường next của Node cuối cùng chứa giá trị NULL.- Không táchthành 2con nếuphần sau chưa có con trỏ tới.- Khởi tạorỗng: L = NULLNguyễn Ngọc Quang 4Đề tài:đơn1.3.3.1. DuyệtđơnDuyệt lần lượt qua từng Node củasách.Mục_đích(Node *L){ Node *p=L; //cho con trỏ p trỏ vào đầuL.while(!điều kiện dừng){ [xửp->info];//xuất thông tin ra màn hình, thực hiện các phép toán… p= p->Next; //cho con trỏ p trỏ tới Node kế tiếp. }1.3.3.2. Chèn một phần tử vàosáchĐể chèn một phần tử X vàota cấp phát bộ nhớ cho 1 Node mới được trỏ bởi q và gán giá trị X cho trường infoNode *q;q=new Node;q->info=X;Chèn một Node mới vàocó 4 trường hợp:- Trường hợp 1: Chèn Node được trỏ bởi q vào đầu sáchBước 1: cho vùngcủa q chứa địa chỉ Node đầusách.q->next=L;(1)Bước 2: cho L trỏ tới q : cập nhập lại con trỏ đầusách.L = q; (2)Nguyễn Ngọc Quang 5Đề tài:đơnHình 1.2: ….- Trường hợp 2: Chèn Node được trỏ bởi q vào sau Node trỏ bởi p trongsáchBước 1: Cho vùngcủa Node được trỏ bởi q chứa địa chỉ Node ngay sau Node được trỏ bởi p.q->next=p->next; (1)Bước 2: Cho vùngcủa Node được trỏ bởi q chứa địa chỉ của Node được trỏ bởi p.p->next=q; (2)Hình 1.3: …- Trường hợp 3: Chèn Node được trỏ bởi q vào cuốisáchBước 1: Nếurỗng thìhiện tại có 1 phần tử chính là q vừa mới chèn vào, return.Bước 2: Ngược lại nếukhông rỗng• Cho con trỏ p chứa địa chỉ Node đầusách: Nguyễn Ngọc Quang 6Đề tài:đơnNode *p=L;• Duyệttừ đầu cho tới Node cuối cùngwhile(p->next!=NULL) p=p->next;• Cho phầncủa Node được trỏ bởi p chứa địa chỉ của q p->next=q;• Cập nhập lại Node cuối cùng bây giờ chính là Node q vừa mới tạo ra.q->next=NULL;- Trường hợp 4: Chèn Node được trỏ bởi q vào trước Node được trỏ bởi pBước 1: Nếu p trỏ đầusách, thực hiện chèn đầusách(trường hợp1), return.Bước 2: Ngược lại cho con trỏ t chứa địa chỉ Node trước Node được trỏ bởi p trongsách: Node *t; t->next=p;Chèn Node được trỏ bởi q vào sau Node được trỏ bởi t (trường hợp 2).1.3.3.3. Xóa một phần tử ra khỏisách: có 2 trường hợp xảy ra- Trường hợp 1: Thực hiện xóa đầunếu p chứa địa chỉ Node đầudanh(L)Bước 1: Cho con trỏ đầuL trỏ vào Node sau nó.L=L->next; (1)Bước 2: Giải phóng Node p ra khỏisách.Delete(p);Nguyễn Ngọc Quang 7Đề tài:đơnHình 1.4: …- Trường hợp 2: Con trỏ p chứa địa chỉ Node bất kỳ nhưng không phải Node đầuBước 1: Cho con trỏ q trỏ đầuL , dùng vòng lặp cho nó trỏ tới địa chỉ Node trước Node được trỏ bởi p trongsách.q=L; while(q->next!=p) q=q->next; (1)Bước 2: Gán địa chỉ của Node ngay sau Node được trỏ bởi p vào ô nhớ next của Node được trỏ bởi qq->Next=p->next; (2)Bước 3: Giải phóng Node được trỏ bởi pdelete(p);(3)Hình 1.5: …Nguyễn Ngọc Quang 8Đề tài:đơn1.3.4.4. Tìm kiếm phần tử trongsáchBước 1: Cho p trỏ vào đầuL và khởi tạo biến found=0Node *p=L; int found=0;Bước 2: Thực hiện vòng lặp để duyệt p chạy từ đầutới cuốisách, tại mỗi Node nếu trường info của Node được trỏ bởi p =X thì cho found=1 để dừng vòng lặp. Ngược lại nếup!=X thì cho p trỏ tới vị trí Node ngay sau Node được trỏ bởi p.while(p!=NULL&&found= =0)if(p->info=X) found=1;else p=p->next; (*)Bước 3: Return pHình 1.6: 1.3.3.5. Đảo các phần tử trongsáchBước 1: Khởi tạo 3 biến con trỏ p, t, q. Trongp trỏ vào đầuL, t= NULL (không trỏ vào địa chỉ nào cả), q trỏ vào địa chỉ Node được trỏ bởi p.Node *p=L,*t=NULL,*q=p ;Nguyễn Ngọc Quang 9Đề tài:đơnBước 2: Dùng vòng lặp duyệt p chạy từ đầu tới cuốisách. Trong khi thực hiện vòng lặp• Cho vùngcủa Node được trỏ bởi q chứa địa chỉ của tq->next=t;• Cho t trỏ đến vị trí Node được trỏ bởi q (cập nhập lại t). t=q;Cụ thể như sau:While(p!=NULL){ q=p; p=p->next; (1)q->next=t ; (2)t=q; (3) }B ước 3 :Cho L trỏ đến vị trí Node được trỏ bởi t (cập nhập lại L)L=tHình 1.7: Nguyễn Ngọc Quang 10[…]…} // int main() { menu_chinh(); } 2.6 Màn hìnhquả 2.6.1 Menu chính của chương trình Nguyễn Ngọc Quang 34 Đề tài: Quản sinh viên bằng danh sách liên kết đơn 2.6.2 Tạo2.6.3 Hiển thịNguyễn Ngọc Quang 35 Đề tài: Quản sinh viên bằng danh sách liên kết đơn 2.6.4 Tìm kiếmtheo mãviên. .. Quản sinh viên bằng danh sách liên kết đơn C H Ư Ơ N G 2 : Ứ N G D Ụ N G DA N H S ÁC H L I Ê N K Ế T Đ Ơ N VÀ O Q UẢ N2.1 Đặc tả bài toán Quản sinh viên là công việc hằng ngày của phònghọc sinh-Công việcđòi hỏi tính tỉ mỉ, cẩn thận trong từng khâu ghi chép các thông tin cá nhân củaviên: mã sốviên, tênviên, ngày tháng năm sinh, …- In thông tinra màn hình Nguyễn Ngọc Quang 12 Đề tài: Quản sinh viên bằng danh sách liên kết đơn 2.3.2.3 Tìm kiếmtheo mã- Duyệt qua- Tìm kiếm theo mãmà người dùng yêu cầu – Hiển thịvừa tìm thấy màn hình 2.3.2.4.Xóatheo mã số- Duyệt qua- Tìm kiếmtheo mãmà người…ch=getch(); cin.sync(); }while(ch!=27); }} 2.4.3 Hiển thịvoid xuat(node first) { node p; p=first; while(p!=NULL) { coutvàlt; >ma; while(p!=NULLvàamp;&p->masv!=ma) . tài: Quản lý sinh viên bằng danh sách liên kết đơn CHƯƠNG 2: ỨNG DỤNG DANH SÁCH LIÊN KẾT ĐƠN VÀO QUẢNLÝ SINH VIÊN.2.1. Đặc tả bài toán. Quản lý sinh viên. tài: Quản lý sinh viên bằng danh sách liên kết đơn CHƯƠNG 1: CƠ SỞ LÝTHUYẾT1. Khái quát về danh sách liên kết 1.1. Khái niệm Danh sách liên kết là danh sách

Xem Thêm  [Update] Caption Hay 2021 ❤️ 1001 Caption Thả Thính Hay Chất Nhất | font chữ tròn mập

Viết một bình luận