├── .gitignore ├── QUEUE ├── Cài đặt và ứng dụng hàng đợi │ ├── MinhMinh1.c │ ├── MinhMinh2.c │ └── readme.md └── Ứng dụng hàng đợi │ ├── encrypt.c │ ├── encrypt.md │ ├── thungan.c │ └── thungan.md ├── README.md ├── STACK ├── Cài đặt ngăn xếp │ ├── readme.md │ └── stack.c └── Ứng dụng ngăn xếp │ ├── readme.md │ ├── satck_func2.c │ └── stack_func1.c └── TREE ├── Cài đặt cây AVL ├── avl.c ├── avl_function.c └── readme.md ├── Cài đặt cây nhị phân ├── bin_tree.c ├── bin_tree_function.c └── readme.md └── Sử dụng cây nhị phân ├── bin_tree.c ├── bin_tree_function.c └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | -------------------------------------------------------------------------------- /QUEUE/Cài đặt và ứng dụng hàng đợi/MinhMinh1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define MaxLength 100 3 | typedef int ElementType; 4 | 5 | typedef struct { 6 | ElementType Elements[MaxLength]; 7 | int Front, Rear; 8 | } Queue; 9 | 10 | // Cài đặt queue dùng mảng di chuyển tịnh tiến, tất cả có DPT O(1) 11 | 12 | void makenullQueue(Queue *pQ){ 13 | pQ->Front = -1; 14 | pQ->Rear = -1; 15 | } 16 | /* Queue makenullQueue(){ 17 | Queue Q; 18 | Q.Front = -1; 19 | Q.Rear = -1; 20 | return Q; 21 | } */ 22 | 23 | int emptyQueue(Queue Q){ 24 | return Q.Front == -1; 25 | } 26 | int fullQueue(Queue Q){ 27 | return Q.Rear - Q.Front == MaxLength - 1; 28 | } 29 | 30 | /* ElementType front(Queue Q){ 31 | if(emptyQueue(Q)) 32 | printf("Queue rong"); 33 | else 34 | return Q.Elements[Q.Front]; 35 | } */ 36 | 37 | void deQueue(Queue *pQ){ 38 | pQ->Front++; 39 | if(pQ->Front > pQ->Rear) 40 | makenullQueue(pQ); 41 | } 42 | /* void deQueue(Queue *pQ){ 43 | if(emptyQueue(*pQ)) 44 | printf("Queue day"); 45 | else{ 46 | if(pQ->Front == pQ->Rear) 47 | makenullQueue(pQ); 48 | else 49 | pQ->Front++; 50 | } 51 | } */ 52 | 53 | void enQueue(ElementType x, Queue *pQ){ 54 | // riêng hàm này thì DPT O(n) (vòng lặp) 55 | if(fullQueue(*pQ)) 56 | printf("Queue day"); 57 | else{ 58 | if(emptyQueue(*pQ)) pQ->Front = 0; 59 | if(pQ->Rear == MaxLength - 1){ 60 | // Hàng đang bị tràn 61 | int i; 62 | // dời về trước Front - 1 phần tử 63 | for(i = pQ->Front; i <= pQ->Rear; i++) 64 | pQ->Elements[i-pQ->Front] = pQ->Elements[i]; 65 | pQ->Rear -= pQ->Front; // pQ->Rear = MaxLength - 1 - pQ->Front; 66 | pQ->Front = 0; 67 | } 68 | pQ->Rear++; // tăng rear lên để lưu biến mới 69 | pQ->Elements[pQ->Rear] = x; // thêm x vào cuối queue 70 | } 71 | } 72 | 73 | /* == */ 74 | int dem(Queue Q){ 75 | return emptyQueue(Q) ? 0 : Q.Rear - Q.Front + 1; 76 | } 77 | 78 | int main(){ 79 | Queue Q; makenullQueue(&Q); 80 | int N, x; char in; 81 | scanf("%d", &N); 82 | while(N--){ 83 | scanf("\n"); 84 | scanf("%c ", &in); 85 | if(in == 'E'){ 86 | scanf(" %d\n", &x); 87 | enQueue(x, &Q); 88 | printf("%d\n", dem(Q)); 89 | }else{ 90 | if(emptyQueue(Q)){ 91 | printf("-1 0\n"); 92 | }else{ 93 | printf("%d ", Q.Elements[Q.Front]); 94 | deQueue(&Q); 95 | printf("%d\n", dem(Q)); 96 | } 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /QUEUE/Cài đặt và ứng dụng hàng đợi/MinhMinh2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define MaxLength 100 3 | typedef int ElementType; 4 | 5 | typedef struct { 6 | ElementType Elements[MaxLength]; 7 | int Front, Rear; 8 | } Queue; 9 | 10 | // Cài đặt queue dùng mảng di chuyển tịnh tiến, tất cả có DPT O(1) 11 | 12 | void makenullQueue(Queue *pQ){ 13 | pQ->Front = -1; 14 | pQ->Rear = -1; 15 | } 16 | 17 | int emptyQueue(Queue Q){ 18 | return Q.Front == -1; 19 | } 20 | int fullQueue(Queue Q){ 21 | return Q.Rear - Q.Front == MaxLength - 1; 22 | } 23 | 24 | void deQueue(Queue *pQ){ 25 | pQ->Front++; 26 | if(pQ->Front > pQ->Rear) 27 | makenullQueue(pQ); 28 | } 29 | void enQueue(ElementType x, Queue *pQ){ 30 | // riêng hàm này thì DPT O(n) (vòng lặp) 31 | if(fullQueue(*pQ)) 32 | printf("Queue day"); 33 | else{ 34 | if(emptyQueue(*pQ)) pQ->Front = 0; 35 | if(pQ->Rear == MaxLength - 1){ 36 | // Hàng đang bị tràn 37 | int i; 38 | // dời về trước Front - 1 phần tử 39 | for(i = pQ->Front; i <= pQ->Rear; i++) 40 | pQ->Elements[i-pQ->Front] = pQ->Elements[i]; 41 | pQ->Rear -= pQ->Front; // pQ->Rear = MaxLength - 1 - pQ->Front; 42 | pQ->Front = 0; 43 | } 44 | pQ->Rear++; // tăng rear lên để lưu biến mới 45 | pQ->Elements[pQ->Rear] = x; // thêm x vào cuối queue 46 | } 47 | } 48 | int solve(Queue *pQ1, Queue *pQ2){ 49 | int k = 0; 50 | while(!emptyQueue(*pQ1)){ 51 | if(pQ1->Elements[pQ1->Front] == pQ2->Elements[pQ2->Front]){ 52 | deQueue(pQ1); 53 | deQueue(pQ2); 54 | }else{ 55 | enQueue(pQ1->Elements[pQ1->Front], pQ1); 56 | deQueue(pQ1); 57 | } 58 | k++; 59 | } 60 | return k; 61 | } 62 | int main(){ 63 | Queue Q1, Q2; makenullQueue(&Q1); makenullQueue(&Q2); 64 | int N, i, var; scanf("%d\n", &N); 65 | for(i = 0; i < N; i++){ 66 | scanf("%d", &var); 67 | enQueue(var, &Q1); 68 | } 69 | for(i = 0; i < N; i++){ 70 | scanf("%d", &var); 71 | enQueue(var, &Q2); 72 | } 73 | printf("%d", solve(&Q1, &Q2)); 74 | } -------------------------------------------------------------------------------- /QUEUE/Cài đặt và ứng dụng hàng đợi/readme.md: -------------------------------------------------------------------------------- 1 | # Cài đặt và ứng dụng hàng đợi 2 | Trong phần này sẽ có 2 problem về Minh Minh và nhiệm vụ của ta liên quan đến các bước thực hiện công việc của cô ấy! 3 | # 1. Minh Minh và N thao tác: 4 | Minh Minh có một hàng đợi **Q** và cô ấy muốn thực hiện **N** thao tác, mỗi thao tác là một trong 2 dạng sau: 5 | - **E x**: thêm x vào hàng đợi và in ra số lượng phần tử của hàng đợi 6 | - **D**: xóa phần tử đầu hàng, đồng thời in phần tử đã xóa và số lượng phần tử của hàng đợi sau khi xóa, 2 giá trị này cách nhau khoảng trắng. Nếu hàng đợi rỗng, in -1 ở chỗ phần tử đã xóa. 7 | 8 | Hãy giúp Minh Minh thực hiện các thao tác trên. 9 | ## Đầu vào 10 | - Dòng đầu tiên: số nguyên **N** là số thao tác (1 <= N <= 100) 11 | - **N** dòng tiếp theo, mỗi dòng là một thao tác theo cú pháp ở trên (1 <= x <= 100) 12 | ## Đầu ra 13 | Mỗi thao tác thêm vào hàng đợi, in ra số lượng phần tử của hàng đợi sau khi thêm; mỗi thao tác xóa, hiển thị 2 số nguyên: phần tử đã xóa (-1 nếu hàng đợi rỗng) và số lượng phần tử của hàng đợi sau khi xóa. 14 | ## Sample Input 15 | ``` 16 | 5 17 | E 2 18 | D 19 | D 20 | E 3 21 | D 22 | ``` 23 | ## Sample Output 24 | ``` 25 | 1 26 | 2 0 27 | -1 0 28 | 1 29 | 3 0 30 | ``` 31 | ## Solution 32 | Xem trong [MinhMinh1.c](MinhMinh1.c) 33 | # 2. Minh Minh và n công việc 34 | Có **n** công việc cần thực hiện, các công việc được đánh số từ 1 đến **n**; Minh Minh được đưa 2 danh sách: 35 | - Danh sách 1 gồm thứ tự các công việc được giao cho Minh Minh 36 | - Danh sách 2 là thứ tự tối ưu các công việc Minh Minh phải thực hiện. 37 | 38 | Để thực hiện Minh Minh lấy từng công việc được giao cho mình, nếu công việc được lấy ra trùng với thứ tự tối ưu thì thực hiện công việc đó, nếu không trùng với thứ tự tối ưu thì chuyển công việc đó vào cuối danh sách thứ tự các công việc được giao. Quá trình lặp lại đến khi tất cả các công việc được thực hiện. **Mỗi lần chuyển công việc về cuối hay thực thi mất 1 đơn vị thời gian**. 39 | 40 | Tính số đơn vị thời gian cần thiết của Minh Minh để hoàn thành n công việc được giao. 41 | ## Đầu vào 42 | - Dòng đầu tiên: số nguyên dương n (1 <= n <= 100) 43 | - Dòng thứ 2: danh sách thứ tự công việc được giao 44 | - Dòng thứ 3: danh sách thứ tự tối ưu các công việc cần thực hiện 45 | 46 | ## Đầu ra 47 | - Một số nguyên duy nhất là số đơn vị thời gian cần thiết để hoàn thành n công việc được giao 48 | 49 | ## Ví dụ & Gợi ý 50 | Có 3 công việc, danh sách 1 là 3 2 1; danh sách 2 là 1 3 2. Các bước thực hiện như sau: 51 | 52 | - Bước 1: Lấy công việc đầu tiên trong danh sách 1, đó là công việc #3. Vì trường hợp tối ưu là công việc #1 được thực hiện đầu tiên, do đó công việc #3 được đưa trở lại cuối danh sách 1. Thời gian dành cho bước 1: 1 53 | - Bước 2: Lấy công việc kế tiếp trong danh sách 1, đó là công việc #2. Vì trường hợp tối ưu là công việc #1 phải được thực hiện, do đó công việc #2 được đưa trở lại cuối danh sách 1. Thời gian dành cho bước 2: 1 54 | - Bước 3: Lấy công việc kế tiếp trong danh sách 1, đó là công việc #1. Đó cũng là công việc cần thực hiện trong trường hợp tối ưu, do đó, thực hiện công việc #1 và lấy chúng ra khỏi các danh sách. Thời gian dành cho bước 3: 1 55 | - Bước 4: Lấy công việc kế tiếp trong danh sách 1, đó là công việc #3. Đó cũng là công việc cần thực hiện trong trường hợp tối ưu, do đó, thực hiện công việc #3 và lấy chúng ra khỏi các danh sách. Thời gian dành cho bước 4: 1 56 | - Bước 5: Lấy công việc kế tiếp trong danh sách 1, đó là công việc #2. Đó cũng là công việc cần thực hiện trong trường hợp tối ưu, do đó, thực hiện công việc #2 và lấy chúng ra khỏi các danh sách. Thời gian dành cho bước 5: 1 57 | Tổng thời gian thực hiện: **5** 58 | ## Test case 59 | - Sample input 60 | ``` 61 | 3 62 | 3 2 1 63 | 1 3 2 64 | ``` 65 | - Sample Output 66 | ``` 67 | 5 68 | ``` 69 | ## Solution 70 | Xem trong [MinhMinh2.c](MinhMinh2.c) -------------------------------------------------------------------------------- /QUEUE/Ứng dụng hàng đợi/encrypt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "PQueue.c" 6 | 7 | void encrypt(char value[], char key[]){ 8 | Queue K; makenullQueue(&K); 9 | int i = 0; 10 | for(; i < strlen(key); i++){ 11 | enQueue(key[i], &K); 12 | } 13 | for(i = 0; i < strlen(value); i++){ 14 | printf("%c", value[i] + ((int)front(K) - 48)); 15 | enQueue(front(K), &K); 16 | deQueue(&K); 17 | } 18 | } 19 | int main(){ 20 | char value[1000], key[1000]; 21 | fgets(value, 1000, stdin); 22 | value[strlen(value) - 1] = '\0'; 23 | fgets(key, 1000, stdin); 24 | key[strlen(key) - 1] = '\0'; 25 | encrypt(value, key); 26 | return (0 - 0); // :D 27 | } -------------------------------------------------------------------------------- /QUEUE/Ứng dụng hàng đợi/encrypt.md: -------------------------------------------------------------------------------- 1 | 2 | # Bài toán mã hoá chuỗi 3 | Giả sử kiểu dữ liệu hàng đợi **Queue** đã được khai báo. Các phép toán cơ bản trên hàng đợi được hỗ trợ trong file thư viện **PQueue.c** 4 | ```c 5 | void makenullQueue(Queue *pQ); 6 | int emptyQueue(Queue Q); 7 | ElementType front(Queue Q); 8 | void deQueue(Queue *pQ); 9 | void enQueue(ElementType x, Queue *pQ); //ElementType là kiểu ký tự 10 | ``` 11 | Bằng cách sử dụng kiểu dữ liệu trừu tượng **Queue** đã cho, hãy viết chương trình mã hóa một thông điệp bằng khóa lặp lại. 12 | 13 | # Dữ liệu đầu vào: 14 | 15 | Dòng 1: chuỗi cần mã hóa. Ví dụ chuỗi ```Hoc CTDL rat vui!```. 16 | 17 | Dòng 2: Khóa lặp lại: là một chuỗi các ký tự số ('1' - '9') mà chúng xác định mỗi ký tự được dịch chuyển về sau bao nhiêu vị trí. 18 | 19 | **Ví dụ:** nếu chuỗi cần mã hóa là "Hoc CTDL rat vui!" và khóa lặp là chuỗi "29137" thì: 20 | - Ký tự đầu tiên của chuỗi cần mã hóa ('H') sẽ dịch chuyển về sau 2 vị trí => ký tự 'J' 21 | - Ký tự kế tiếp của chuỗi cần mã hóa ('o') sẽ dịch chuyển về sau 9 vị trí => ký tự 'x' 22 | - Ký tự kế tiếp nữa của chuỗi cần mã hóa ('c') sẽ dịch chuyển về sau 1 vị trí => ký tự 'd' 23 | - Ký tự ' ' sẽ dịch chuyển về sau 3 vị trí => ký tự '#' 24 | - Ký tự 'C' sẽ dịch chuyển về sau 7 vị trí => ký tự 'J' 25 | - Lúc này khóa "29137" đã hết, lại bắt đầu lặp lại khóa này. 26 | - Ký tự 'T' sẽ dịch chuyển về sau 2 vị trí => ký tự 'V' 27 | - Ký tự 'D' sẽ dịch chuyển về sau 9 vị trí => ký tự 'M' 28 | - Và cứ tiếp tục như vậy. 29 | # Dữ liệu đầu ra 30 | Dòng ghi chuỗi được mã hóa (xem thêm trong test case). 31 | 32 | # Gợi ý: 33 | 34 | - Sử dụng hàng đợi để lưu từng chữ số của khóa lặp. Khi chữ số ở đầu hàng đợi được sử dụng (để dịch chuyển ký tự trong chuỗi cần mã hóa) thì nó lại được đưa trở lại hàng đợi. 35 | - Duyệt từng ký tự trong chuỗi cần mã hóa và kết hợp với hàng đợi để mã hóa (dịch chuyển) ký tự này. 36 | 37 | _(Dữ liệu đầu vào luôn hợp lệ, sinh viên không cần kiểm tra)_ 38 | 39 | # Sample Testcase 40 | - Input 1: 41 | ``` 42 | Hoc CTDL rat vui! 43 | 29137 44 | ``` 45 | - Output 1: 46 | ``` 47 | Jxd#JVMM#yc}!y|k* 48 | ``` 49 | - Input 2: 50 | ``` 51 | Hang doi duoc su dung de luu khoa lap trong bai toan ma hoa. 52 | 6842 53 | ``` 54 | - Output 2: 55 | ``` 56 | Niri&lsk&lyqi(ww&lypm(hg&tyw&slqg(pcv(xtuvk"him"zwep&ue"nwe0 57 | ``` 58 | 59 | # Solution 60 | Xem lời giải tại [encrypt.c](encrypt.c) -------------------------------------------------------------------------------- /QUEUE/Ứng dụng hàng đợi/thungan.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "PIQueue.c" 5 | void tinhsoquay(int khach, int soquay, int tgxuly, int tgiandentb, int tg_mt, float *tg_tb){ 6 | Queue Q; 7 | /* tg_mt: thoi gian muc tieu (la thoi gian trong de) 8 | tg_tb: la thoi gian tinh toan voi so quay tuong ung, dung de so sanh voi tg_mt 9 | */ 10 | int tongthoigian, tgdi, tgden, quay = 1, stt_quay, i, tgian_khachtruocdi[soquay]; 11 | // tgian_khachtruocdi: thoi gian khach truoc di de tinh thoi gian hien tai tai quay 12 | *tg_tb = tg_mt+1; 13 | while(quay <= soquay && *tg_tb > tg_mt){ 14 | // reset toan bo thoi gian di cua khach 15 | for(i = 1; i <= quay; i++) 16 | tgian_khachtruocdi[i-1] = 0; 17 | 18 | // them toan bo thoi gian cua khach vao hang doi 19 | makenullQueue(&Q); 20 | for(i = 1; i <= khach; i++) 21 | enQueue(i * tgiandentb, &Q); 22 | 23 | tongthoigian = 0; 24 | while(!emptyQueue(Q)){ 25 | for(stt_quay = 1; stt_quay <= quay && !emptyQueue(Q); stt_quay++){ 26 | tgden = front(Q); 27 | deQueue(&Q); 28 | 29 | if(tgden >= tgian_khachtruocdi[stt_quay - 1]) // vua vao, phai xu ly ngay 30 | tgdi = tgden + tgxuly; 31 | else 32 | tgdi = tgian_khachtruocdi[stt_quay - 1] + tgxuly; 33 | 34 | tgian_khachtruocdi[stt_quay - 1] = tgdi; 35 | tongthoigian += tgdi - tgden; 36 | 37 | } 38 | } 39 | *tg_tb = tongthoigian/khach; 40 | printf("So quay: %d; Thoi gian cho trung binh: %.1f\n", quay, *tg_tb); 41 | quay++; 42 | } 43 | quay--; 44 | if(quay == soquay && *tg_tb > tg_mt) 45 | printf("Voi %d quay hien co, khach phai cho it nhat %.1f giay moi duoc phuc vu.", quay, *tg_tb); 46 | if(quay <= soquay && *tg_tb <= tg_mt) 47 | printf("=> Sieu thi se mo %d quay", quay); 48 | } 49 | 50 | int main(){ 51 | /* 52 | N: số khách hàng 53 | M: số quầy thu ngân tối đa 54 | T1: Thời gian xử lý trung bình cho 1 giao dịch tại quầy thu ngân (s) 55 | T2: Thời gian trung bình (số giây) mà khách hàng sẽ đến xếp hàng thanh toán. 56 | X: Thời gian trung bình mà khách hàng phải đợi để được thanh toán X 57 | */ 58 | int N, M, T1, T2, X; 59 | float tb; 60 | scanf("%d\n%d\n%d\n%d\n%d", &N, &M, &T1, &T2, &X); 61 | 62 | tinhsoquay(N, M, T1, T2, X, &tb); 63 | } 64 | -------------------------------------------------------------------------------- /QUEUE/Ứng dụng hàng đợi/thungan.md: -------------------------------------------------------------------------------- 1 | # Ứng dụng Queue: bài toán tính quầy thu ngân 2 | 3 | Giả sử kiểu dữ liệu hàng đợi **Queue** đã được khai báo. Các phép toán cơ bản trên hàng đợi được hỗ trợ trong file thư viện **PIQueue.c** 4 | 5 | ```c 6 | void makenullQueue(Queue *pQ); 7 | int emptyQueue(Queue Q); 8 | ElementType front(Queue Q); 9 | void deQueue(Queue *pQ); 10 | void enQueue(ElementType x, Queue *pQ); //ElementType là kiểu số nguyên 11 | ``` 12 | Bằng cách sử dụng kiểu dữ liệu trừu tượng **Queue** đã cho, hãy viết chương trình tính số quầy thu ngân cần phải mở tại siêu thị Coopmart Cần Thơ vào một thời điểm cụ thể. 13 | 14 | # Dữ liệu đầu vào: 15 | 16 | - Dòng 1: Số khách hàng. 17 | - Dòng 2: Số quầy thu ngân tối đa có trong siêu thị. 18 | - Dòng 3: Thời gian xử lý trung bình (số giây) cho 1 giao dịch tại quầy thu ngân. Ví dụ: thời gian từ lúc bắt đầu tới lượt khách được xử lý đơn hàng tại quầy thu ngân cho đến khi khách thanh toán xong và rời khỏi quầy là 120 giây. 19 | - Dòng 4: Thời gian trung bình (số giây) mà khách hàng sẽ đến xếp hàng thanh toán. Ví dụ: trung bình 15 giây thì có 1 khách hàng đến xếp hàng thanh toán. 20 | Thời gian trung bình mà khách hàng phải bỏ ra từ lúc bắt đầu xếp hàng đến lúc thanh toán xong X giây. Ví dụ: khách hàng chỉ phải bỏ ra dưới 120 giây. 21 | 22 | # Dữ liệu đầu ra (xem thêm trong test case): 23 | 24 | Số quầy thu ngân mở và thời gian trung bình mà khách hàng phải bỏ ra. 25 | Kết luận: số quầy thu ngân cần phải mở để khách hàng chỉ phải bỏ ra dưới X giây từ lúc bắt đầu xếp hàng đến lúc thanh toán xong. 26 | 27 | # Gợi ý: 28 | Thực hiện mô phỏng theo số lượng quầy thu ngân tăng dần (từ 1 đến số quầy thu ngân tối đa ) cho đến khi thời gian trung bình mà khách phải bỏ ra <=X thì dừng quá trình lặp và đưa ra kết luận. 29 | 30 | Với từng số lượng quầy: 31 | 32 | - Khởi tạo thời gian tại từng quầy bằng 0; 33 | - Đưa dữ liệu của khách hàng (thời gian đến của khách hàng) vào hàng đợi; 34 | - Tính tổng thời gian mà tất cả các khách hàng trong hàng đợi phải bỏ ra từ lúc bắt đầu xếp hàng đến lúc thanh toán xong: 35 | - Khởi đầu, tổng thời gian bằng 0; 36 | - Trong khi hàng đợi chưa hết: Với lần lượt từng quầy thu ngân, nếu vẫn còn khách trong hàng đợi thì lấy thời gian đến của khách, tính thời gian đi của khách (liên quan đến thời gian đến, thời gian tại quầy và thời gian xử lý trung bình cho 1 giao dịch), xóa khách khỏi hàng đợi, cập nhật lại thời gian tại quầy, cập nhật lại tổng thời gian. 37 | - Tính thời gian trung bình mà khách hàng phải bỏ ra dựa trên tổng thời gian và số lượng khách; so sánh với X để dừng quá trình lặp và đưa ra kết luận hay lại tiếp tục lặp. 38 | 39 | ![img](https://i.imgur.com/502Wp5S.png) 40 | 41 | ![image](https://user-images.githubusercontent.com/72507371/140720861-ed6844fa-0b8c-486e-9238-16f61426cd8f.png) 42 | 43 | _(Dữ liệu đầu vào luôn hợp lệ, sinh viên không cần kiểm tra)_ 44 | 45 | # Sample Testcases: 46 | Input 1 47 | ``` 48 | 100 49 | 10 50 | 120 51 | 15 52 | 120 53 | ``` 54 | Output 1 55 | ``` 56 | So quay: 1; Thoi gian cho trung binh: 5317.0 57 | So quay: 2; Thoi gian cho trung binh: 2325.0 58 | So quay: 3; Thoi gian cho trung binh: 1332.0 59 | So quay: 4; Thoi gian cho trung binh: 840.0 60 | So quay: 5; Thoi gian cho trung binh: 547.0 61 | So quay: 6; Thoi gian cho trung binh: 355.0 62 | So quay: 7; Thoi gian cho trung binh: 219.0 63 | So quay: 8; Thoi gian cho trung binh: 120.0 64 | => Sieu thi se mo 8 quay 65 | ``` 66 | 67 | Input 2: 68 | ``` 69 | 150 70 | 5 71 | 150 72 | 30 73 | 60 74 | ``` 75 | Output 2: 76 | ``` 77 | So quay: 1; Thoi gian cho trung binh: 9090.0 78 | So quay: 2; Thoi gian cho trung binh: 3480.0 79 | So quay: 3; Thoi gian cho trung binh: 1620.0 80 | So quay: 4; Thoi gian cho trung binh: 697.0 81 | So quay: 5; Thoi gian cho trung binh: 150.0 82 | Voi 5 quay hien co, khach phai cho it nhat 150.0 giay moi duoc phuc vu. 83 | ``` 84 | # Solution 85 | Xem lời giải tại đây: [thungan.c](thungan.c) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data-Structures-and-Algorithms-CTU 2 | Tổng hợp bài tập và lời giải học phần Cấu trúc dữ liệu CTU. 3 | 4 | # Danh sách 5 | 6 | # Ngăn xếp 7 | 8 | # Hàng đợi 9 | 10 | # Cây 11 | 12 | # Tự điển 13 | -------------------------------------------------------------------------------- /STACK/Cài đặt ngăn xếp/readme.md: -------------------------------------------------------------------------------- 1 | # Cài đặt ngăn xếp 2 | Các bài thực hành trong phần Cài đặt ngăn xếp 3 | 4 | # Khai báo và các hàm sử dụng 5 | - Xem trong file [stack.c](stack.c): 6 | - [giatriDinh](stack.c#L17) 7 | - [ktRong](stack.c#L20) 8 | - [ktDay](stack.c#L23) 9 | - [xoa](stack.c#L27) 10 | - [khoitao](stack.c#L32) 11 | - [hienthi](stack.c#L35) 12 | - [them](stack.c#L41) -------------------------------------------------------------------------------- /STACK/Cài đặt ngăn xếp/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define M 100 // so luong phan tu toi da 3 | #define SoPhanTu 100 4 | 5 | typedef int ElementType; 6 | // Tất cả hàm bên dưới đều có dpt O(1) 7 | 8 | typedef struct { 9 | ElementType DuLieu[M]; 10 | int Dinh; // vị trí đỉnh stack 11 | } Stack; 12 | 13 | typedef Stack NganXep; 14 | 15 | /* ===== */ 16 | 17 | int giatriDinh(NganXep S){ 18 | return S.DuLieu[S.Dinh]; 19 | } 20 | int ktRong(NganXep S){ 21 | return S.Dinh == 100; 22 | } 23 | int ktDay(NganXep S){ 24 | return S.Dinh == 0; 25 | } 26 | 27 | void xoa(NganXep *pS){ 28 | if(!ktRong(*pS)){ 29 | pS->Dinh++; 30 | } 31 | } 32 | void khoitao(NganXep *pS){ 33 | pS->Dinh = 100; 34 | } 35 | void hienthi(NganXep *pS){ 36 | while(!ktRong(*pS)){ 37 | printf("%d ", giatriDinh(*pS)); 38 | xoa(pS); 39 | } 40 | } 41 | void them(int x, NganXep *pS){ 42 | if(pS->Dinh != 0){ 43 | pS->Dinh--; 44 | pS->DuLieu[pS->Dinh] = x; 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /STACK/Ứng dụng ngăn xếp/readme.md: -------------------------------------------------------------------------------- 1 | # Ứng dụng ngăn xếp 2 | Các bài thực hành trong phần Ứng dụng ngăn xếp 3 | 4 | # Ứng dụng Ngăn xếp phần 1: 5 | - Xem trong [stack_func1.c](stack_func1.c): 6 | - [doiNhiPhan](stack_func1.c#L15) 7 | - [readStack](stack_func1.c#L23) 8 | - [printStack](stack_func1.c#L31) 9 | - [ktChuoi](stack_func1.c#L37) 10 | - [tinhGiatri](stack_func1.c#L54) 11 | # Ứng dụng Ngăn xếp phần 2: 12 | - Xem trong [stack_func1.c](stack_func2.c): 13 | - [inThaplucphan](stack_func2.c#L13) 14 | - [tinhGiatri](stack_func1.c#L25) 15 | - [ktChuoi](stack_func1.c#L56) -------------------------------------------------------------------------------- /STACK/Ứng dụng ngăn xếp/satck_func2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define MaxLength 100 4 | typedef char ElementType; 5 | 6 | // Tất cả hàm bên dưới đều có dpt O(1) 7 | 8 | typedef struct { 9 | ElementType Elements[MaxLength]; 10 | int Top_idx; // vị trí đỉnh stack 11 | } Stack; 12 | 13 | void inThaplucphan(int n){ 14 | Stack S; makenullStack(&S); 15 | char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 16 | while(n != 0){ 17 | push(n % 16, &S); 18 | n /= 16; 19 | } 20 | while(!emptyStack(S)){ 21 | printf("%c", hex[(int)top(S)]); 22 | pop(&S); 23 | } 24 | } 25 | float tinhGiatri(char bt[]){ 26 | Stack S; makenullStack(&S); 27 | int i = 0; float x1, x2; 28 | for(; i < strlen(bt); i++){ 29 | if(bt[i] >= '0' && bt[i] <= '9'){ 30 | push((int)bt[i] - 48, &S); 31 | } else if(bt[i] != ' ') { 32 | x1 = (float)top(S); 33 | pop(&S); 34 | x2 = (float)top(S); 35 | pop(&S); 36 | switch(bt[i]){ 37 | case '+': 38 | push(x2 + x1, &S); 39 | break; 40 | case '-': 41 | push(x2 - x1, &S); 42 | break; 43 | case '*': 44 | push(x2 * x1, &S); 45 | break; 46 | case '/': 47 | push(x2 / x1, &S); 48 | break; 49 | default: 50 | break; 51 | } 52 | } 53 | } 54 | return top(S); 55 | } 56 | int ktChuoi(){ 57 | Stack S; makenullStack(&S); 58 | char ngoac[100]; 59 | fgets(ngoac, 100, stdin); 60 | ngoac[strlen(ngoac) - 1] = '\0'; 61 | int i = 0; 62 | for(; i < strlen(ngoac); i++){ 63 | if(ngoac[i] == '('){ 64 | push(ngoac[i], &S); 65 | }else if(ngoac[i] == ')'){ 66 | if(!emptyStack(S)) 67 | pop(&S); 68 | else 69 | return 0; 70 | } 71 | } 72 | return emptyStack(S); 73 | } -------------------------------------------------------------------------------- /STACK/Ứng dụng ngăn xếp/stack_func1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define M 100 // so luong phan tu toi da 3 | #define SoPhanTu 100 4 | 5 | typedef int ElementType; 6 | // Tất cả hàm bên dưới đều có dpt O(1) 7 | 8 | typedef struct { 9 | ElementType DuLieu[M]; 10 | int Dinh; // vị trí đỉnh stack 11 | } Stack; 12 | 13 | typedef Stack NganXep; 14 | 15 | void doiNhiPhan(int n, NganXep *pS){ 16 | khoitao(pS); 17 | int x = n; 18 | do { 19 | them(x % 2, pS); 20 | x /= 2; 21 | } while(x > 0); 22 | } 23 | void readStack(Stack *pS){ 24 | int n, x; scanf("%d", &n); 25 | makenullStack(pS); 26 | for(; n > 0; n--){ 27 | scanf("%d", &x); 28 | push(x, pS); 29 | } 30 | } 31 | void printStack(Stack *pS){ 32 | while(!emptyStack(*pS)){ 33 | printf("%d ", top(*pS)); 34 | pop(pS); 35 | } 36 | } 37 | int ktChuoi(){ 38 | Stack S; makenullStack(&S); 39 | char ngoac[100]; 40 | fgets(ngoac, 100, stdin); 41 | ngoac[strlen(ngoac) - 1] = '\0'; 42 | int i = 0; 43 | for(; i < strlen(ngoac); i++){ 44 | if(ngoac[i] == '('){ 45 | push(ngoac[i], &S); 46 | }else if(ngoac[i] == ')' && !emptyStack(S)){ 47 | pop(&S); 48 | }else { 49 | return 0; 50 | } 51 | } 52 | return emptyStack(S); 53 | } 54 | float tinhGiatri(char bt[]){ 55 | Stack S; makenullStack(&S); 56 | int i = 0; float x1, x2; 57 | for(; i < strlen(bt); i++){ 58 | if(bt[i] >= 48 && bt[i] <= 57){ 59 | x1 = (int)bt[i] - 48; 60 | push(x1, &S); 61 | } else { 62 | x1 = (float)top(S); 63 | pop(&S); 64 | x2 = (float)top(S); 65 | pop(&S); 66 | switch(bt[i]){ 67 | case '+': 68 | push(x2 + x1, &S); 69 | break; 70 | case '-': 71 | push(x2 - x1, &S); 72 | break; 73 | case '*': 74 | push(x2 * x1, &S); 75 | break; 76 | case '/': 77 | push(x2 / x1, &S); 78 | break; 79 | default: 80 | break; 81 | } 82 | } 83 | } 84 | return top(S); 85 | } -------------------------------------------------------------------------------- /TREE/Cài đặt cây AVL/avl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // Khai báo cho kiểu dữ liệu cây tìm kiếm nhị phân cân bằng về chiều cao AVL 4 | typedef int KeyType; 5 | struct Node{ 6 | KeyType Key; 7 | int Height; 8 | struct Node *Left, *Right; 9 | }; 10 | typedef struct Node* AVLTree; 11 | 12 | 13 | -------------------------------------------------------------------------------- /TREE/Cài đặt cây AVL/avl_function.c: -------------------------------------------------------------------------------- 1 | #include "avl.c" 2 | // Chỉ include avl.c khi chạy trên vscode, DevC,... 3 | 4 | // tìm số lớn nhất trong 2 số nguyên 5 | int max(int a,int b){ 6 | return (a > b) ? a : b; 7 | } 8 | 9 | // Hàm in khóa của những nút lá trong cây AVL 10 | void printLeaves(AVLTree root){ 11 | if(root != NULL){ 12 | if(root->Left == NULL && root->Right == NULL) 13 | printf("%d ", root->Key); 14 | printLeaves(root->Left); 15 | printLeaves(root->Right); 16 | 17 | } 18 | } 19 | 20 | // Hàm tính hệ số cân bằng của một nút trên cây AVL 21 | int getBalance(AVLTree node){ 22 | if(node == NULL) 23 | return 0; 24 | return getHeight(node->Left) - getHeight(node->Right); 25 | } 26 | 27 | // Hàm xen một nút có khóa key vào cây AVL 28 | AVLTree insertNode(KeyType key, AVLTree root){ 29 | if(root == NULL){ 30 | AVLTree temp = (struct Node*)malloc(sizeof(struct Node)); 31 | temp->Key = key; 32 | temp->Left = NULL; 33 | temp->Right = NULL; 34 | return temp; 35 | } 36 | if(key < root->Key) 37 | root->Left = insertNode(key, root->Left); 38 | else if(key > root->Key) 39 | root->Right = insertNode(key, root->Right); 40 | else 41 | return root; 42 | 43 | root->Height = 1 + max(getHeight(root->Left), getHeight(root->Right)); 44 | 45 | int balance = getBalance(root); 46 | if(balance > 1 && key < root->Left->Key) 47 | return rightRotate(root); 48 | if(balance > 1 && key > root->Left->Key) 49 | return leftrightRotate(root); 50 | if(balance < -1 && key > root->Right->Key) 51 | return leftRotate(root); 52 | if(balance < -1 && key < root->Right->Key) 53 | return rightleftRotate(root); 54 | return root; 55 | } 56 | 57 | // Hàm in kết quả duyệt hậu tự cây AVL 58 | void printLRN(AVLTree root){ 59 | if(root != NULL){ 60 | printLRN(root->Left); 61 | printLRN(root->Right); 62 | printf("(%d - %d); ", root->Key, root->Height); 63 | } 64 | } 65 | 66 | // Hàm tìm chiều cao của một nút trên cây AVL 67 | int getHeight(AVLTree T){ 68 | int kq = 0, l, r; 69 | if(T != NULL){ 70 | l = T->Left != NULL ? getHeight(T->Left) + 1 : 0; 71 | r = T->Right != NULL ? getHeight(T->Right) + 1 : 0; 72 | kq += (l > r ? l : r); 73 | return kq; 74 | } 75 | return -1; 76 | } 77 | 78 | // Hàm kiểm tra xem một cây có là cây AVL hay không 79 | int isAVL(AVLTree root){ 80 | int k = getBalance(root); 81 | return k >= -1 && k <= 1; 82 | } 83 | 84 | // Hàm xử lý trường hợp mất cân bằng bên trái của con phải 85 | AVLTree rightleftRotate(AVLTree node){ 86 | node->Right = rightRotate(node->Right); 87 | return leftRotate(node); 88 | } 89 | 90 | // Hàm xử lý trường hợp mất cân bằng bên phải của con trái 91 | AVLTree leftrightRotate(AVLTree node){ 92 | node->Left = leftRotate(node->Left); 93 | return rightRotate(node); 94 | } 95 | 96 | // Hàm in kết quả duyệt tiền tự cây AVL 97 | void printNLR(AVLTree root){ 98 | if(root != NULL){ 99 | printf("(%d - %d); ", root->Key, root->Height); 100 | printNLR(root->Left); 101 | printNLR(root->Right); 102 | } 103 | } 104 | 105 | // Hàm in các khóa của những nút có cùng chiều cao height 106 | void printHeight(int height, AVLTree root){ 107 | if(root != NULL){ 108 | if(getHeight(root) == height) 109 | printf("%d ", root->Key); 110 | printHeight(height, root->Left); 111 | printHeight(height, root->Right); 112 | } 113 | } 114 | 115 | // Hàm xử lý trường hợp mất cân bằng bên trái của con trái 116 | AVLTree rightRotate(AVLTree node){ 117 | AVLTree temp = node->Left; 118 | node->Left = temp->Right; 119 | temp->Right = node; 120 | node->Height = 1 + max(getHeight(node->Left), getHeight(node->Right)); 121 | temp->Height = 1 + max(getHeight(temp->Left), getHeight(temp->Right)); 122 | return temp; 123 | } 124 | 125 | // Hàm xử lý trường hợp mất cân bằng bên phải của con phải 126 | AVLTree leftRotate(AVLTree node){ 127 | AVLTree temp = node->Right; 128 | node->Right = temp->Left; 129 | temp->Left = node; 130 | node->Height = 1 + max(getHeight(node->Left), getHeight(node->Right)); 131 | temp->Height = 1 + max(getHeight(temp->Left), getHeight(temp->Right)); 132 | return temp; 133 | } 134 | 135 | // Hàm tìm và trả về nút có khóa key trong cây AVL 136 | AVLTree search(KeyType key, AVLTree root){ 137 | if(root == NULL) return NULL; 138 | return (root->Key == key) ? root : (root->Key < key) ? search(key, root->Right) : search(key, root->Left); 139 | } 140 | 141 | -------------------------------------------------------------------------------- /TREE/Cài đặt cây AVL/readme.md: -------------------------------------------------------------------------------- 1 | # Cài đặt cây AVL 2 | Các bài thực hành trong phần cài đặt cây AVL 3 | 4 | # Khai báo cây AVL 5 | - Xem trong [avl.c](avl.c) (khi chạy trên ide include file này) 6 | # Các hàm cài đặt 7 | - Xem trong file [avl_function.c](avl_function.c): 8 | - [max](avl_function.c#L5) 9 | - [printLeaves](avl_function.c#L10) 10 | - [getBalance](avl_function.c#L21) 11 | - [insertNode](avl_function.c#L28) 12 | - [printLRN](avl_function.c#L58) 13 | - [getHeight](avl_function.c#L67) 14 | - [isAVL](avl_function.c#L79) 15 | - [rightleftRotate](avl_function.c#L85) 16 | - [leftrightRotate](avl_function.c#L91) 17 | - [printNLR](avl_function.c#L97) 18 | - [printHeight](avl_function.c#L106) 19 | - [rightRotate](avl_function.c#L116) 20 | - [leftRotate](avl_function.c#L126) 21 | - [search](avl_function.c#L136) -------------------------------------------------------------------------------- /TREE/Cài đặt cây nhị phân/bin_tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node { 5 | int Data; 6 | struct Node *Left, *Right; 7 | }; 8 | typedef struct Node* Tree; -------------------------------------------------------------------------------- /TREE/Cài đặt cây nhị phân/bin_tree_function.c: -------------------------------------------------------------------------------- 1 | #include "bin_tree.c" 2 | // Chỉ include bin_tree.c khi chạy trên vscode, DevC,... 3 | 4 | // Hàm khởi tạo và trả về một cây rỗng 5 | Tree initTree(){ 6 | Tree T; 7 | T = (struct Node*)malloc(sizeof(struct Node)); 8 | T = NULL; 9 | return T; 10 | } 11 | 12 | // Hàm kiểm tra cây có gốc là T có rỗng hay không? 13 | int isEmpty(Tree T){ 14 | return T == NULL; 15 | } 16 | 17 | // Hàm duyệt tiền tự cây nhị phân T 18 | void preOrder(Tree T){ 19 | if(T != NULL){ 20 | printf("%d ", T->Data); 21 | preOrder(T->Left); 22 | preOrder(T->Right); 23 | } 24 | } 25 | 26 | // Hàm duyệt trung tự cây nhị phân T 27 | void inOrder(Tree T){ 28 | if(T != NULL){ 29 | inOrder(T->Left); 30 | printf("%d ", T->Data); 31 | inOrder(T->Right); 32 | } 33 | } 34 | 35 | // Hàm duyệt hậu tự cây nhị phân T 36 | void postOrder(Tree T){ 37 | if(T != NULL){ 38 | postOrder(T->Left); 39 | postOrder(T->Right); 40 | printf("%d ", T->Data); 41 | } 42 | } 43 | 44 | // Hàm tạo một cây nhị phân từ giá trị x và hai cây con có sẵn l, r. 45 | Tree createTree(int x, Tree l, Tree r){ 46 | Tree T; 47 | T = (struct Node*)malloc(sizeof(struct Node)); 48 | T->Data = x; 49 | T->Left = l; 50 | T->Right = r; 51 | return T; 52 | } 53 | 54 | // Hàm tính chiều cao của một cây nhị phân T 55 | int getHeight(Tree T){ 56 | int kq = 0, l, r; 57 | if(T != NULL){ 58 | l = T->Left != NULL ? getHeight(T->Left) + 1 : 0; 59 | r = T->Right != NULL ? getHeight(T->Right) + 1 : 0; 60 | kq += (l > r ? l : r); 61 | } 62 | return kq; 63 | } 64 | 65 | // Hàm đếm số nút lá của một cây nhị phân T 66 | int getLeaves(Tree T){ 67 | return (T == NULL) ? 0 : (T != NULL && T->Left == NULL && T->Right == NULL) ? 1 : getLeaves(T->Left) + getLeaves(T->Right); 68 | } 69 | 70 | // Hàm tạo một nút có giá trị x. 71 | Tree createNode(int x){ 72 | struct Node* N; 73 | N = (struct Node*)malloc(sizeof(struct Node)); 74 | N->Data = x; 75 | N->Left = NULL; 76 | N->Right = NULL; 77 | return N; 78 | } 79 | -------------------------------------------------------------------------------- /TREE/Cài đặt cây nhị phân/readme.md: -------------------------------------------------------------------------------- 1 | # Cài đặt cây nhị phân 2 | Các bài thực hành trong phần cài đặt cây nhị phân 3 | 4 | # Khai báo cây nhị phân 5 | - Xem trong [bin_tree.c](bin_tree.c) (khi chạy trên ide include file này) 6 | # Các hàm cài đặt 7 | - Xem trong file [bin_tree_function.c](bin_tree_function.c): 8 | - [initTree](bin_tree_function.c#L5) 9 | - [isEmpty](bin_tree_function.c#L13) 10 | - [preOrder](bin_tree_function.c#L18) 11 | - [inOrder](bin_tree_function.c#L27) 12 | - [postOrder](bin_tree_function.c#L36) 13 | - [createTree](bin_tree_function.c#L45) 14 | - [getHeight](bin_tree_function.c#L55) 15 | - [getLeaves](bin_tree_function.c#L66) 16 | - [createNode](bin_tree_function.c#L71) -------------------------------------------------------------------------------- /TREE/Sử dụng cây nhị phân/bin_tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef char DataType; 5 | struct Node { 6 | DataType Data; 7 | struct Node *Left, *Right; 8 | }; 9 | 10 | typedef struct Node* Tree; 11 | 12 | void makenullTree(Tree *pT){ 13 | (*pT) = NULL; 14 | } 15 | 16 | int emptyTree(Tree T){ 17 | return T == NULL; 18 | } 19 | 20 | Tree leftChild(Tree T){ 21 | return (T != NULL) ? T->Left : NULL; 22 | } 23 | 24 | Tree rightChild(Tree T){ 25 | return (T != NULL) ? T->Right : NULL; 26 | } 27 | 28 | int isLeaf(Tree T){ 29 | return T != NULL && T->Left == NULL && T->Right == NULL; 30 | } 31 | 32 | int getLeaves(Tree T){ 33 | return (T == NULL) ? 0 : (T != NULL && T->Left == NULL && T->Right == NULL) ? 1 : getLeaves(T->Left) + getLeaves(T->Right); 34 | } 35 | 36 | void preOrder(Tree T){ 37 | if(T != NULL){ 38 | printf("%c ", T->Data); 39 | preOrder(T->Left); 40 | preOrder(T->Right); 41 | } 42 | } 43 | 44 | void inOrder(Tree T){ 45 | if(T != NULL){ 46 | inOrder(T->Left); 47 | printf("%c ", T->Data); 48 | inOrder(T->Right); 49 | } 50 | } 51 | 52 | void postOrder(Tree T){ 53 | if(T != NULL){ 54 | postOrder(T->Left); 55 | postOrder(T->Right); 56 | printf("%c ", T->Data); 57 | } 58 | } 59 | 60 | int findIndex(DataType x, char in[], int star, int end){ 61 | int i=star; 62 | while (i<=end){ 63 | if (x==in[i]) 64 | return i; 65 | 66 | else 67 | i++; 68 | } 69 | return i; 70 | } 71 | 72 | int max(int a, int b){ 73 | return (a > b) ? a : b; 74 | } -------------------------------------------------------------------------------- /TREE/Sử dụng cây nhị phân/bin_tree_function.c: -------------------------------------------------------------------------------- 1 | #include "bin_tree.c" 2 | 3 | // Hàm createTree() cho phép dựng một cây nhị phân từ các biểu thức duyệt tiền tự và trung tự. 4 | // Bài này mình dùng kèm hàm createNode 5 | Tree createNode(int x){ 6 | struct Node* N; 7 | N = (struct Node*)malloc(sizeof(struct Node)); 8 | N->Data = x; 9 | N->Left = NULL; 10 | N->Right = NULL; 11 | return N; 12 | } 13 | int cs = 0; 14 | Tree createTree(char tientu[], char trungtu[], int start, int end){ 15 | int index; Tree T; 16 | if(start > end) return NULL; 17 | T = createNode(tientu[cs]); 18 | cs++; 19 | if(start == end) 20 | return T; 21 | index = findIndex(T->Data, trungtu, start, end); 22 | T->Left = createTree(tientu, trungtu, start, index - 1); 23 | T->Right = createTree(tientu, trungtu, index + 1, end); 24 | return T; 25 | } 26 | 27 | // Hàm findMax() tìm giá trị lớn nhất trong cây nhị phân. 28 | int findMax(Tree T){ 29 | if(T == NULL) return 0; 30 | int l, r, g, k; 31 | l = T->Left ? findMax(T->Left) : 0; 32 | r = T->Right ? findMax(T->Right) : 0; 33 | g = T->Data; 34 | k = (l > r ? l : r); 35 | return (k > g ? k : g); 36 | } 37 | 38 | // Hàm findElement() xác định xem x có là giá trị của một nút trong cây nhị phân hay không. 39 | Tree findElement(DataType x, Tree T){ 40 | if(T == NULL) return NULL; 41 | return (T->Data == x) ? T : (findElement(x, T->Left) != NULL) ? findElement(x, T->Left) : findElement(x, T->Right); 42 | } 43 | 44 | // Hàm getDiameter() tính đường kính của một cây nhị phân 45 | // Bài này mình dùng cùng hàm getHeight 46 | int getHeight(Tree T){ 47 | int kq = 0, l, r; 48 | if(T != NULL){ 49 | l = T->Left != NULL ? getHeight(T->Left) + 1 : 0; 50 | r = T->Right != NULL ? getHeight(T->Right) + 1 : 0; 51 | kq += (l > r ? l : r); 52 | } 53 | return kq; 54 | } 55 | 56 | int getDiameter(Tree T, int *d){ 57 | int l, r, dl, dr; 58 | if(T == NULL) return 0; 59 | l = getHeight(T->Left) + 1; 60 | r = getHeight(T->Right) + 1; 61 | dl = getDiameter(T->Left, d); 62 | dr = getDiameter(T->Right, d); 63 | *d = max(l + r + 1, max(dl, dr)); 64 | return *d; 65 | } 66 | 67 | // Hàm getFullNodes() đếm số nút có đủ hai con. 68 | int getFullNodes(Tree T){ 69 | if(T == NULL) return 0; 70 | int k = 0; 71 | if(T->Left != NULL && T->Right != NULL) 72 | k++; 73 | k += getFullNodes(T->Left) + getFullNodes(T->Right); 74 | return k; 75 | } 76 | 77 | // Hàm convertTree() để chuyển đổi một cây nhị phân sang cây phản chiếu của nó. 78 | Tree convertTree(Tree T){ 79 | if(T == NULL) 80 | return NULL; 81 | Tree K = T; 82 | Tree dT; 83 | convertTree(K->Left); 84 | convertTree(K->Right); 85 | dT = K->Left; 86 | K->Left = K->Right; 87 | K->Right = dT; 88 | return K; 89 | } 90 | 91 | // Hàm isMirrors() kiểm tra xem hai cây có là phản chiếu của nhau hay không. 92 | int isMirrors(Tree T1, Tree T2){ //KIỂM TRA CÂY PHẢN CHIẾU 93 | if(T1 == NULL && T2 == NULL) return 1; 94 | if(T1 == NULL || T2 == NULL) return (0 - 0); 95 | return T1->Data == T2->Data && isMirrors(T1->Left, T2->Right) && isMirrors(T1->Right, T2->Left); 96 | } 97 | 98 | // Hàm printAllPaths() hiển thị tất cả các đường đi (từ nút gốc đến nút lá) và có độ dài đường đi thỏa điều kiện cho trước 99 | void printAllPaths(Tree T, int path[], int len, int pathlen){ 100 | if(T == NULL || len > pathlen) 101 | return; 102 | path[len] = T->Data; 103 | len++; 104 | if(isLeaf(T) && len == pathlen + 1) 105 | printArray(path, len); 106 | else{ 107 | printAllPaths(T->Left, path, len, pathlen); 108 | printAllPaths(T->Right, path, len, pathlen); 109 | } 110 | } 111 | 112 | 113 | -------------------------------------------------------------------------------- /TREE/Sử dụng cây nhị phân/readme.md: -------------------------------------------------------------------------------- 1 | # Sử dụng cây nhị phân 2 | Các bài thực hành trong phần sử dụng cây nhị phân 3 | 4 | # Khai báo và các hàm khai báo 5 | - Xem trong [bin_tree.c](bin_tree.c) (khi chạy trên ide include file này): 6 | - [makenullTree](bin_tree.c#L12) 7 | - [emptyTree](bin_tree.c#L16) 8 | - [leftChild](bin_tree.c#L20) 9 | - [rightChild](bin_tree.c#L24) 10 | - [isLeaf](bin_tree.c#L28) 11 | - [getLeaves](bin_tree.c#L32) 12 | - [preOrder](bin_tree.c#L36) 13 | - [inOrder](bin_tree.c#L44) 14 | - [postOrder](bin_tree.c#L52) 15 | - [findIndex](bin_tree.c#L60) 16 | - [max](bin_tree.c#L72) 17 | # Các hàm sử dụng 18 | - Xem trong file [bin_tree_function.c](bin_tree_function.c): 19 | - [createNode](bin_tree_function.c#L5) 20 | - [createTree](bin_tree_function.c#L14) 21 | - [findMax](bin_tree_function.c#L28) 22 | - [findElement](bin_tree_function.c#L38) 23 | - [getHeight](bin_tree_function.c#L46) 24 | - [getDiameter](bin_tree_function.c#L56) 25 | - [getFullNodes](bin_tree_function.c#L68) 26 | - [convertTree](bin_tree_function.c#L78) 27 | - [isMirrors](bin_tree_function.c#L92) 28 | - [printAllPaths](bin_tree_function.c#L99) --------------------------------------------------------------------------------