Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 65

Đề cương ôn tập môn học CTDL và GT

3. (Câu 1) Xác định độ phức tạp của đoạn chương trình đã cho.
Đề 4 : Cài đặt và đánh giá độ phức tạp của thuật toán sắp xếp chèn trên mảng n số nguyên. Minh
họa các bước trên mảng số nguyên: 19, 7, 16, 2, 6, 4, 20, 18, 12
Cài đặt: Minh họa:
void insertion(int a[], int n){ Ban đầu 19, 7, 16, 2, 6, 4, 20, 18, 12
for(int i=1;i<n;i++){ B1 7, 19, 16, 2, 6, 4, 20, 18, 12
int key = a[i], j=i-1; B2 7, 16, 19, 2, 6, 4, 20, 18, 12
while(j>=0 && a[j]>key){ B3 2, 7, 16, 19, 6, 4, 20, 18, 12
a[j+1] = a[j]; B4 2, 6, 7, 16, 19, 4, 20, 18, 12
j--; B5 2, 4, 6, 7, 16, 19, 20, 18, 12
} B6 2, 4, 6, 7, 16, 19, 20, 18, 12
a[j+1] = key; B7 2, 4, 6, 7, 16, 18, 19, 20, 12
} B8 2, 4, 6, 7, 12, 16, 18, 19, 20
}
ĐPT: O(n2)
Trường hợp Số lần so Số lần gán
sánh
Tốt nhất n-1 2(n-1)
Xấu nhất n(n-1)/2 n(n+1)/2 - 1

Đề 8 : Cài đặt và đánh giá độ phức tạp của thuật toán sắp xếp chọn trực tiếp trên mảng n số
nguyên. Minh họa các bước trên mảng a[] = {2, 17, 3, 1, 9, 3, 2}
Cài đặt: Minh họa:
void selection(int a[], int n){ Ban đầu 2, 17, 3, 1, 9, 3, 2
for(int i=0;i<n-1;i++){
B1 1, 17, 3, 2, 9, 3, 2
int vtmin = i;
B2 1, 2, 3, 17, 9, 3, 2
for(int j=i+1;j<n;j++){
B3 1, 2, 2, 17, 9, 3, 3
if(a[j]<a[vtmin])
B4 1, 2, 2, 3, 9, 17, 3
vtmin=j;
B5 1, 2, 2, 3, 3, 17, 9
}
B6 1, 2, 2, 3, 3, 17, 9
if(vtmin!=i){
int tg = a[i];
a[i] = vtmin;
vtmin = tg;
}
}
}
ĐPT: O(n2)
Trường hợp Số lần so sánh Số lần gán
Tốt nhất n(n-1)/2 0
Xấu nhất n(n-1)/2 3n

4. Khai báo cấu trúc dslk đơn/kép. Thông tin mỗi nút gồm: họ tên, mã sv, điểm trung bình.
DSLK đơn
typedef struct SV{
char ten[30];
int msv;
float dtb;
}Data;
typedef struct node{
Data infor;
struct node *next;
}node;
typedef struct List{
node *head, *tail;
int spt;
}list;
DSLK kép
typedef struct SV{
char ten[50];
int msv;
float dtb;
}SV;
typedef struct node{
SV data;
struct node *next;
struct node *prev;
} node;
5. Thêm một nút vào đầu/cuối dslk đơn/kép
Input: Danh sách liên kết đơn / kép L chứa thông tin sinh viên Data (tên, msv, dtb), Thông tin sinh viên mới
cần thêm s
Output: Trả về danh sách có thêm 1 nút đầu / cuối
Method: Khai báo cấu trúc Data (SV), node, list
Đoạn chương trình:

DSLK đơn
void themDau(list *L, Data x){
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = x;
newNode->next = NULL;
if(L->head==NULL) L->head = L->tail = newNode;
else{
newNode->next = L->head;
L->head = newNode;
}
L->spt++;
}
void themCuoi(list *L, Data x){
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = x;
newNode->next = NULL;
if(L->head==NULL) L->head = L->tail = newNode;
else{
L->tail->next = newNode;
L->tail = newNode;
}
L->spt++;
}
DSLK kép
node *makenode(char *ten, int msv, float dtb){
node *newnode = (node*)malloc(sizeof(node));
strcpy(newnode->data.ten, ten);
newnode->data.msv = msv;
newnode->data.dtb = dtb;
newnode->next = NULL;
newnode->prev = NULL;
return newnode;
}
void themDau(node **head, char *ten, int msv, float dtb){
node *newnode = makenode(ten, msv, dtb);
newnode->next = *head;
if(*head != NULL)
(*head)->prev = newnode;
*head = newnode;
}
void themCuoi(node **head, char *ten, int msv, float dtb){
node *newnode = makenode(ten, msv, dtb);
if(*head==NULL){
*head = newnode;
return;
}
node *tmp = *head;
while(tmp->next!=NULL)
tmp = tmp->next;
newnode->prev = tmp;
tmp->next = newnode;
}

6. Thêm một nút vào sau nút nào đó. Ví dụ, thêm nút mới vào sau nút có mã sinh viên là x.
Input: Danh sách liên kết đơn / kép L chứa thông tin sinh viên Data (tên, msv, dtb), Thông tin sinh viên mới
cần thêm s, Mã sinh viên x
Output: Trả về danh sách có thêm 1 nút đầu / cuối
Method: Khai báo cấu trúc Data (SV), node, list
Đoạn chương trình:

DSLK đơn
void themSaux(list *L, int x, Data s){
if(L->head==NULL) return;
node *p = L->head;
while(p->next!=NULL && p->infor.msv != x){
p = p->next;
}
if(p->infor.msv != x) return;
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = s;
newNode->next = p->next;
p->next = newNode;
if(L->tail->infor.msv == x) L->tail = newNode; //
L->spt++;
}
DSLK kép
void insertAf(node **head, int x, char *ten, int msv, float dtb){
node *newnode = makenode(ten, msv, dtb);
node *tmp = *head;
while(tmp->next != NULL){
if(tmp->data.msv == x){
newnode->next = tmp->next;
newnode->prev = tmp;
tmp->next->prev = newnode;
tmp->next = newnode;
return;
}
else tmp = tmp->next;
}
if(tmp->data.msv == x){
themCuoi(head, ten, msv, dtb);
}
}

7. Thêm một nút vào trước nút nào đó. Ví dụ, thêm nút mới vào trước nút có mã sinh viên là x.
DSLK đơn
void themTruocx(list *L, int x, Data s){
if(L->head==NULL) return;
node *p = L->head;
if(p->infor.msv == x){
themDau(L, s);
return;
}
while(p->next!=NULL && p->next->infor.msv != x){
p = p->next;
}
if(p->next->infor.msv != x) return;
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = s;
newNode->next = p->next;
p->next = newNode;
L->spt++;
}
DSLK kép
void insertBef(node **head, int x, char *ten, int msv, float dtb){
node *newnode = makenode(ten, msv, dtb);
node *tmp = *head;
if(tmp->data.msv == x){
themDau(head, ten, msv, dtb);
}
while(tmp->next != NULL){
if(tmp->next->data.msv == x){
newnode->next = tmp->next;
newnode->prev = tmp;
tmp->next->prev = newnode;
tmp->next = newnode;
return;
}
else tmp = tmp->next;
}
}

8. Cho dslk đơn/kép đã được sắp xếp theo một trường nào đó, ví dụ sắp xếp theo điểm trung bình.
Thêm một nút vào trong dslk đơn sao cho danh sách mới được tạo ra vẫn được sắp xếp.
DSLK đơn + kép
void sortedinsert(list *L, Data s){
if(L->head==NULL) themDau(L, s);
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = s;
node *p = L->head;
if(p->infor.dtb >= s.dtb){
themDau(L, s);
return;
}
while(p->next!=NULL && p->next->infor.dtb < s.dtb){
p = p->next;
}
newNode->next = p->next;
p->next = newNode;
if(L->tail->infor.dtb <= s.dtb) L->tail = newNode; //
L->spt++;
}

9. Xóa nút ở đầu/cuối dslk đơn/kép.


void xoaDau(list *L){
if(L->head==NULL) return;
node *xoa = L->head;
L->head = xoa->next;
free(xoa);
L->spt--;
if(L->head==NULL) L->tail = NULL;
}
void xoaCuoi(list *L){
if(L->head==NULL) return;
node *p = L->head;
while(p->next!=L->tail)
p=p->next;
free(p->next);
L->tail = p;
L->tail->next = NULL;
L->spt--;
}
10. Xóa nút ở vị trí nào đó trong dslk đơn/kép. Ví dụ, xóa nút có mã sinh viên là x.
DSLK đơn
void xoaX(list *L, int x){
if(L->head==NULL) return;
node *pp = L->head, *q; // pp: nút cần xóa, q: nút trước pp
while(pp!=NULL && pp->infor.msv != x){
q=pp;
pp=pp->next;
}
if(pp == L->head){
//xoaDau(L);
L->head = pp->next;
free(pp);
if(L->head==NULL) L->tail = NULL;
}
else{
q->next = pp->next;
free(pp);
if(L->tail==NULL) L->tail = q;
}
L->spt--;
}
DSLK kép
void xoa_val(node **head, int msv){
if(*head==NULL) return; // list rỗng
node *tmp = *head;
if(tmp->data.msv==msv){ // nếu nút cần xóa ở đầu
xoaDau(head);
return;
}
while(tmp->next!=NULL){ // nút cần xóa ở giữa
if(tmp->data.msv==msv){
tmp->next->prev = tmp->prev;
tmp->prev->next = tmp->next;
free(tmp);
return;
}
tmp=tmp->next;
}
if(tmp->data.msv==msv){ // nếu nút cần xóa ở cuối
xoaCuoi(head);
}
}

11. Cho dslk đơn, hoặc kép chứa các số nguyên. Xóa nút sao cho sau khi xoá ta được ds dài nhất
các số được sắp xếp tăng dần. (dãy con tăng đơn điệu quy hoạch động – Longest Increasing
Subsequence)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
char ten[50];
char ma[10];
float d1, d2, d3;
struct Node* next;
struct Node* prev;
} Node;
Node* createNode(char* ten, char* ma, float d1, float d2, float d3) {
Node* newNode = (Node*)malloc(sizeof(Node));
strcpy(newNode->ten, ten);
strcpy(newNode->ma, ma);
newNode->d1 = d1;
newNode->d2 = d2;
newNode->d3 = d3;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
void themCuoi(Node** head, char* ten, char* ma, float d1, float d2, float d3) {
Node* newNode = createNode(ten, ma, d1, d2, d3);
if (*head == NULL) {
*head = newNode;
return;
}
Node* last = *head;
while (last->next != NULL) {
last = last->next;
}
last->next = newNode;
newNode->prev = last;
}
void nhap(Node** head) {
char ten[50];
char ma[10];
float d1, d2, d3;

printf("Ten: ");
fgets(ten, sizeof(ten), stdin);
ten[strcspn(ten, "\n")] = 0;
printf("Ma sinh vien: ");
scanf("%s", ma);
printf("Diem 1: ");
scanf("%f", &d1);
printf("Diem 2: ");
scanf("%f", &d2);
printf("Diem 3: ");
scanf("%f", &d3);
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
themCuoi(head, ten, ma, d1, d2, d3);
}
float TB(Node* node) {
return (node->d1 + node->d2 + node->d3) / 3;
}
void xoaNode(Node** head, Node* del) {
if (*head == NULL || del == NULL) return;
if (*head == del) *head = del->next;
if (del->next != NULL) del->next->prev = del->prev;
if (del->prev != NULL) del->prev->next = del->next;
free(del);
}
void DSDN(Node** head) {
Node *ptr, *start = NULL, *end = NULL;
int length = 0, maxL = 0;
for (ptr = *head; ptr->next != NULL; ptr = ptr->next) {
if (TB(ptr) >= TB(ptr->next)) {
if (start == NULL) {
start = ptr;
}
end = ptr->next;
length++;
} else {
if (length > maxL) {
maxL = length;
Node *temp, *next;
for (temp = *head; temp != NULL; temp = next) {
next = temp->next;
if (temp < start || temp > end) {
xoaNode(head, temp);
}
}
}
start = NULL;
end = NULL;
length = 0;
}
}
if (length > maxL) {
Node *temp, *next;
for (temp = *head; temp != NULL; temp = next) {
next = temp->next;
if (temp < start || temp > end) {
xoaNode(head, temp);
}
}
}
}
void inxuoi(Node *head){
while(head != NULL){
printf("%s %s %.2f %.2f %.2f\n", head->ten, head->ma, head->d1, head->d2, head->d3);
head = head->next;
}
}
int main() {
Node* head = NULL;
int n, i;
printf("So sinh vien: ");
scanf("%d", &n);

for (i = 0; i < n; i++) {


nhap(&head);
}
DSDN(&head);
inxuoi(head);
}

12. Cho dslk đơn/kép mà các phần tử đã sắp xếp, ví dụ sắp xếp tăng dần theo điểm trung bình. Hãy
tách danh sách trên thành 2 phần: chứa các phần tử có điểm tb>=5; chứa các phần tử còn lại.
void tach(list *L, list *L2){
node *p=L->head;
while(p->next!=NULL && p->next->infor.dtb<5){
p=p->next;
}
L2->head = p->next;
L->tail = p;
p->next = NULL;
}

13. Cho hai dslk đơn/kép mà các phần tử đã được sắp xếp, ví dụ sắp xếp tăng dần theo điểm trung
bình. Hãy ghép hai danh sách trên thành một danh sách sao cho danh sách kết quả cũng được sắp
xếp tăng dần theo điểm trung bình.
node* merge(node* head1, node* head2) {
if (!head1) return head2; // ds1 rỗng trả về ds2
if (!head2) return head1;
node* head = NULL; // tạo ds mới
if (head1->data < head2->data) {
head = head1; // thêm node vào ds mới
head->next = merge(head1->next, head2); // đệ quy (tịnh tiến node đầu của ds1)
} else {
head = head2;
head->next = merge(head1, head2->next);
}
return head;
}
14. Cho dslk đơn/kép chứa thông tin sinh viên. Hãy tách danh sách trên thành hai danh sách: danh
sách thứ nhất chứa các phần tử có điểm tb>=5; danh sách thứ 2 chứa các phần tử còn lại.
void moveNode(node **source, node **dest){
node *newNode = *source;
assert(newNode!=NULL);
*source = newNode->next;
newNode->next = *dest;
*dest = newNode;
}
void split(node *source, node **aRef, node **bRef){
node *a = NULL;
node *b = NULL;
while(source!=NULL){
if(source->infor.dtb < 5)
moveNode(&source, &a);
else if(source->infor.dtb >= 5 && source!=NULL)
moveNode(&source, &b);
}
*aRef = a;
*bRef = b;
}
15. Cho ds liên kết đơn/kép các nhân viên (tên, mã, hsl, pc, mã phòng ban). Bạn hãy tính trung bình
lương của từng phòng ban. Biết lương = hsl*2000+pc
typedef struct NV{
char ten[50];
int mnv, maphong;
float hsl, pc, luong;
}NV;
typedef struct node{
NV data;
struct node*next;
}node;
node *create(node *head, char *ten, int mnv, float hsl, float pc, int maphong){
node *newnode = (node*)malloc(sizeof(node));
strcpy(newnode->data.ten, ten);
newnode->data.mnv=mnv;
newnode->data.hsl=hsl;
newnode->data.pc=pc;
newnode->data.maphong=maphong;
newnode->data.luong = newnode->data.hsl*2000+newnode->data.pc; //cau 15
newnode->next=NULL;
return newnode;
}

16. Cho ds liên kết đơn, hoặc kép các nhân viên (tên, mã, hsl, pc, mã phòng ban). Bạn hãy viết hàm
cho phép sửa thông tin của một nhân viên.
void suaTT(node *head, int mnv_cu, char *ten, int mnv, float hsl, float pc, int
maphong){
while(head != NULL){
if(head->data.mnv == mnv_cu){
strcpy(head->data.ten, ten);
head->data.mnv=mnv;
head->data.hsl=hsl;
head->data.pc=pc;
head->data.maphong=maphong;
return;
}
head = head->next;
}
}

17. Cho ds liên kết đơn, hoặc kép các nhân viên (tên, mã, hsl, pc, mã phòng ban). Bạn hãy viết hàm
tìm thông tin của một nhân viên trong danh sách. Tiêu chí tìm kiếm là tên (hoặc mã, ...).
void tkiem_ten(node *head, char *ten){
printf("\nDanh sach tim kiem: %s\n", ten);
int dem=0;
while(head!=NULL){
if(strcmp(head->data.ten, ten)==0){
printf("%s %d %.3f\n", head->data.ten, head->data.mnv, head->data.luong);
dem++;
}
head=head->next;
}
if(dem==0) printf("Khong tim thay");
}
void tkiem_ma(node *head, int mnv){
printf("\nDanh sach tim kiem: %d\n", mnv);
int dem=0;
while(head!=NULL){
if(head->data.mnv == mnv){
printf("%s %d %.3f\n", head->data.ten, head->data.mnv, head->data.luong);
dem++;
}
head=head->next;
}
if(dem==0) printf("Khong tim thay");
}

18. Giả sử đã có cấu trúc dữ liệu Stack với các phép toán initS, popS, pushS, topS (khởi tạo, lấy ra
phần tử ở đỉnh, thêm một phần tử vào đỉnh, lấy giá trị phẩn tử ở đỉnh). Hãy viết đoạn chương trình
chuyển số nguyên n từ hệ thập phân sang nhị phân có sử dụng cấu trúc dữ liệu Stack.
int main(){
stack s;
initStack(&s);
int sohe10;
scanf("%d", &sohe10);
while(sohe10!=0){
push(&s, sohe10%2);
sohe10/=2;
}
while(!emptyStack(&s)){
int x = pop(&s);
printf("%d ", x);
}
}
19. Giả sử đã có cấu trúc Stack với các phép toán initS, popS, pushS, topS (khởi tạo, lấy ra phần tử
ở đỉnh, thêm một phần tử vào đỉnh, lấy giá trị phẩn tử ở đỉnh). Hãy viết chương trình đảo ngược
một dãy số nguyên. Ví dụ: 2, 3, 4, 5 được đảo thành 5, 4, 3, 2
int main(){
stack s;
int so, a, x;
initS(&s);
scanf("%d", &so);
for(int i=0;i<so;i++){
scanf("%d", &a);
pushS(&s, a);
}
while(!emptyStack(&s)){
popS(&s, &x);
printf("%d ", x);
}
}
20. Giả sử đã có cấu trúc Queue với các phép toán initQ, delQ, addQ, topQ (khởi tạo, lấy ra phần tử
ở đỉnh, thêm một phần tử vào đỉnh, lấy giá trị phẩn tử ở đỉnh). Hãy viết đoạn chương trình nhận đầu
vào là chuỗi nhị phân/bát phân/thập lục phân, in ra giá trị thập phân tương ứng.
int main() {
InitQ(Q); //Hang doi rong
int X;
char so[100]; // dãy input
int co_so, mu = 0, tong = 0, n;
scanf("%s %d", so, &co_so);
for(int i=strlen(so)-1;i>=0;i--){
if(so[i]>='0' && so[i]<='9') n = so[i] - '0';
else n = so[i] + 10 - 'A';
AddQ(&Q,n);
}
while(!emptyQ(Q)){
DelQ(&Q, &X);
tong += X*pow(co_so,mu);
mu++;
}
printf("%d ",tong);
}
}

21. Sắp xếp mảng sinh viên (tên, mã, điểm trung bình) tăng dần theo tên, cùng tên theo mã. Áp
dụng thuật toán sắp xếp đã học.

25. Khai báo cấu trúc cây tìm kiếm nhị phân. Ví dụ: thông tin lưu trong các nút gồm: họ tên, mã,
điểm TB. Khóa là mã sv.
typedef struct SV{
char ten[30];
int msv;
float dtb;
} SV;
typedef struct node{
SV infor;
struct node *left, *right;
} node;

26. Thêm một nút vào cây tìm kiếm nhị phân
node* insert(node* node, int key) {
if (node == NULL) return newNode(key); // nếu cây rỗng: nút mới là gốc
if (key < node->infor) //nếu giá trị node mới < giá trị gốc: thêm vào trái
node->left = insert(node->left, key); //đệ quy: lặp đến khi gặp NULL
else if (key > node->infor) //nếu giá trị node mới < giá trị gốc: thêm vào phải
node->right = insert(node->right, key);
return node;
}

30. Chuyển cây tổng quát về cây nhị phân


C++
#include <iostream>
#include <vector>
class TreeNode {
public:
int val;
TreeNode* left;
TreeNode* right;
std::vector<TreeNode*> children;
TreeNode(int val){
this->val = val;
this->left = this->right = nullptr;
}
};
TreeNode* convert(TreeNode* root){
if (!root) return nullptr;
if (root->children.size() == 0) return root;
if (root->children.size() == 1) {
root->left = convert(root->children[0]);
return root;
}
root->left = convert(root->children[0]);
root->right = convert(root->children[1]);

for (int i = 2; i < root->children.size(); i++) {


TreeNode* rightTreeRoot = root->right;
while (rightTreeRoot->left != nullptr) {
rightTreeRoot = rightTreeRoot->left;
}
rightTreeRoot->left = convert(root->children[i]);
}
return root;
}
void printTree(TreeNode* root){
if (!root) return;
std::cout << root->val << " ";
printTree(root->left);
printTree(root->right);
}
int main(){
TreeNode* root = new TreeNode(1);
root->children.push_back(new TreeNode(2));
root->children.push_back(new TreeNode(3));
root->children.push_back(new TreeNode(4));
root->children.push_back(new TreeNode(5));
/* 1
/||\
2345
/\ /\
6 7 8 9 */
root->children[0]->children.push_back(new TreeNode(6));
root->children[0]->children.push_back(new TreeNode(7));
root->children[3]->children.push_back(new TreeNode(8));
root->children[3]->children.push_back(new TreeNode(9));
/* 1
/
2
/\
63
\\
74
\
5
/\
8 9 */
TreeNode* binaryTreeRoot = convert(root);
printTree(binaryTreeRoot); // 1 2 6 7 3 4 5 8 9
}
C
#include <stdio.h>
#include <stdlib.h>
typedef struct GTNode { // Cây tổng quát
int data;
int child_count; // Số con
struct GTNode** child; // Mảng con trỏ trỏ tới các nút con
} GTNode;

typedef struct BTNode { // Cây nhị phân


int data;
struct BTNode* left, * right; // Con trỏ tới con tráu & con phải
} BTNode;
// Tạo nút mới cho cây tổng quát
GTNode* newGTNode(int data, int child_count) {
GTNode* node = (GTNode*)malloc(sizeof(GTNode)); // cấp phát bộ nhớ cho nút
// Assign data and child count
node->data = data;
node->child_count = child_count;
node->child = (GTNode**)malloc(child_count * sizeof(GTNode*)); // cấp phát bộ nhớ
cho nút các con
return node;
}
// Tạo nút mới cho cây nhị phân
BTNode* newBTNode(int data) {
struct BTNode* node = (BTNode*)malloc(sizeof(BTNode));
node->data = data;
node->left = node->right = NULL;
return node;
}
// Chuyển cây tổng quát thành cây nhị phân
BTNode* convert2(GTNode* root) {
if (root == NULL) return NULL; // TH cơ sở (dừng đệ quy): nút (đang xét tạm gọi là gốc)
ko có con
BTNode* node = newBTNode(root->data); // nút gốc giữ nguyên
if (root->child_count > 0) // Nếu nút gốc (root) có con, con đầu => con trái cây nhị phân
node->left = convert2(root->child[0]);
if (root->child_count > 1) { // Nếu gốc có > 1 con, các con còn lại => con phải của con
(trái) trước
BTNode* curr = node->left; // con trỏ đến con hiện tại (con trái)
// sd vòng lặp nối các con còn lại thành con phải của con (trái) trước
for (int i = 1; i < root->child_count; i++) { // Lặp từ con thứ 2 đến con cuối
curr->right = convert2(root->child[i]);
curr = curr->right; // tịnh tiến đến nút mới chuyển đổi
}
}
return node;
}
void NLR(BTNode* root) {
if (root == NULL) return;
printf("%d ", root->data);
NLR(root->left);
NLR(root->right);
}
void LNR(BTNode* root) {
if (root == NULL) return;
LNR(root->left);
printf("%d ", root->data);
LNR(root->right);
}
int main() {
GTNode* root = newGTNode(1, 3);
root->child[0] = newGTNode(2, 2);
root->child[1] = newGTNode(3, 0);
root->child[2] = newGTNode(4, 1);
root->child[0]->child[0] = newGTNode(5, 0);
root->child[0]->child[1] = newGTNode(6, 0);
root->child[2]->child[0] = newGTNode(7, 0);
/* 1
/|\
2 3 4
/\ \
5 6 7 */
BTNode* broot = convert2(root);
/* 1
/
2
/\
53
\ \
6 4
/
7 */
NLR(broot); // 1 2 5 6 3 4 7
printf("\n");
LNR(broot); // 5 6 2 3 7 4 1
}

Cây
Câu 4: Cây
a, Trình bày thuật toán chuyển biểu thức tiền tố thành trung tố. Dựng dãy nhị phân với biểu thức và
đưa ra dạng trung tố, hậu tố, giá trị biểu thức: -, N, +, *, 12, -, 20, /, 9, 4, *, ^, 2, 7, +, 33, *, 12, 6
b, Sinh viên: tên, mã, điểm 1, 2, 3. Xây dựng thuật toán đếm và in ra các sv học lại khi điểm <4.0

a,
Trung (LNR): N – ((12 * (20 – (9 / 4))) + ((2 ^ 7) * (33 + (12*6))))
= N – (12 * (20 – 9/4) + 2^7 * (33 + (12*6)))
Hậu (LRN): N 12 20 9 4 / - * 2 7 ^ 33 12 6 * + * + -
Giá trị: -13.653

Trình bày thuật toán:


_ Duyệt biểu thức tiền tố từ phải qua trái (từ cuối)
_ Nếu gặp toán hạng, đẩy vào ngăn xếp.
_ Nếu gặp toán tử, lấy hai toán hạng từ ngăn xếp lần lượt là
op1, op2, tạo chuỗi mới: “(op1 + toán hạng + op2)”, đẩy
chuỗi mới vào ngăn xếp.
_ Lặp các bước trên đến khi hết biểu thức. Kết quả: biểu
thức trung tố (trong ngăn xếp)

b,
Input: Danh sách SV (tên, mã, d1, d2, d3) lưu trữ theo BST (khoá mã sv)
Output: Số lượng và thông tin các sv học lại
Method: Khai báo struct Data (chứa thông tin SV), node

#include <stdio.h>
#include <malloc.h>
typedef struct SV{
char ten[30];
int ma;
float d1, d2, d3;
} Data;
typedef struct node{
Data info;
struct node*left, *right;
} node;

node *insert(node *n, Data s){


node* newNode = (node*)malloc(sizeof(node));
newNode->info = s;
newNode->left = newNode->right = NULL;
if(n == NULL) return newNode;
if(s.ma < n->info.ma)
n->left = insert(n->left, s);
else if(s.ma > n->info.ma)
n->right = insert(n->right, s);
return n;
}

// Hàm kiểm tra học lại


int hoclai(node *n){
return (n->info.d1<4 || n->info.d2<4 || n->info.d3<4);
}

void LNR(node*n, int *d){


if(n==NULL) return;
LNR(n->left, d);
if(hoclai(n)){
printf("%s %d %.2f %.2f %.2f\n", n->info.ten, n->info.ma, n->info.d1, n->info.d2, n-
>info.d3);
*d = *d+1;
}
LNR(n->right, d);
}

int main(){
int d = 0;
Data sv[100] = {{"nhu", 22, 7, 2, 6}, {"an", 44, 8, 0, 5}, {"ly", 66, 6, 7, 8}, {"anh", 11, 8, 8, 9}};
node* root = NULL;
root = insert(root, sv[1]);
insert(root, sv[0]);
insert(root, sv[2]);
insert(root, sv[3]);

printf("Danh sách SV học lại\n");


LNR(root, &d);
printf("Số sv học lại: %d", d);
}

Câu 4.2:
a, Có 1 BST danh sách nhân viên: tên, mã (khóa), hsl, pc. Hàm đếm và in các nhân viên có lương
tháng (= hsl*2000+pc) > lương trung bình toàn công ty.
b, Dựng BST với bt trung tố, đưa ra dạng tiền, hậu tố: -12 * 5 + 2 * (17 – 3 * 4) + 8

a,
Input: Danh sách nhân viên (tên, mã, hsl, pc) lưu trữ theo BST (khoá mã nhân viên)
Output: Số lượng và thông tin các nhân viên có lương tháng > lương trung bình toàn công ty
Method: Khai báo struct Data (chứa thông tin NV), node

#include <stdio.h>
#include <malloc.h>
typedef struct NV{
char ten[30];
int ma;
float hsl, pc;
} Data;
typedef struct node{
Data info;
struct node*left, *right;
} node;

node *insert(node *n, Data s){


node* newNode = (node*)malloc(sizeof(node));
newNode->info = s;
newNode->left = newNode->right = NULL;
if(n == NULL) return newNode;
if(s.ma < n->info.ma)
n->left = insert(n->left, s);
else if(s.ma > n->info.ma)
n->right = insert(n->right, s);
return n;
}

// Hàm tính lương từng NV


float luong(node *n){
return n->info.hsl*2000+n->info.pc;
}

void LNR(node*n, int *d, float *s){


if(n==NULL) return;
*d = *d+1;
*s = *s + luong(n);
LNR(n->left, d, s);
LNR(n->right, d, s);
}

void LNR1(node*n, float ltb){


if(n==NULL) return;
LNR1(n->left, ltb);
if(luong(n)>ltb) printf("%s %d %.2f %.2f %.2f\n", n->info.ten, n->info.ma, n->info.hsl, n-
>info.pc, luong(n));
LNR1(n->right, ltb);
}

int main(){
int d = 0;
float s = 0;
Data nv[5] = {{"an", 44, 1, 200}, {"ly", 66, 1.2, 100}, {"anh", 11, 1.1, 300}, {"lan", 55, 1.7, 100}};
node* root = NULL;
root = insert(root, nv[1]);
insert(root, nv[0]);
insert(root, nv[2]);
insert(root, nv[3]);
LNR(root, &d, &s);
printf("Số nv: %d\nLương tb: %.2f", d, s/d);

printf("\nDanh sách NV lương >= lương tb cty\n");


LNR1(root, s/d);
}

b,
Tiền (NLR): + + * -12 5 * 2 - 17 * 3 4 8
Hậu (LRN): 12 - 5 * 2 17 3 4 * - * + 8 +

Câu 4.3:
a, Mỗi nút của BST: mã NV (khóa), họ tên, lương. Viết hàm nhận đầu vào là 1 nút, in thông tin nút
anh em và nút cha. Vẽ BST có ít nhất 6 nút theo cách đã cài đặt
b, Chuyển biểu thức thành trung tố: - + 7 / 8 * 12 ^ - 9 33 ^ 11 6. Vẽ BST biểu thức trung tố kết quả

a,
Input: Danh sách nv (mã, họ tên, lương) lưu trữ theo BST (khoá mã nhân viên); 1 nút bất kì từ cây.
Output: Thông tin nút anh em và nút cha của nút đó
Method: Khai báo struct Data (chứa thông tin NV), node

#include <stdio.h>
#include <malloc.h>
typedef struct NV{
char ten[20];
int ma;
float luong;
}Data;
typedef struct node{
Data info;
struct node *left, *right;
}node;
typedef node *bst;

node *insert(node *n, Data s){


node* newNode = (node*)malloc(sizeof(node));
newNode->info = s;
newNode->left = newNode->right = NULL;
if(n == NULL) return newNode;
if(s.ma < n->info.ma)
n->left = insert(n->left, s);
else if(s.ma > n->info.ma)
n->right = insert(n->right, s);
return n;
}

// Tìm nút cha


node* par(node *root, int x) {
if (root == NULL || root->left->info.ma == x || root->right->info.ma == x) return root;
node *parent = par(root->left, x);
if (parent != NULL) return parent;
return par(root->right, x);
}

// Tìm nút anh em


node *sib(node*n, int x){
if(n==NULL || n->info.ma == x) return NULL;
if(n->left != NULL && n->left->info.ma == x) return n->right;
if(n->right != NULL && n->right->info.ma == x) return n->right;
struct node*tmp = sib(n->left, x);
if(tmp!=NULL) return tmp;
tmp = sib(n->right, x);
return tmp;
}

// In thông tin về nút cha, nút anh em


void tt(node *root, int x) {
node *p = par(root, x);
node *s = sib(root, x);
printf("Nút cha của %d: ", x);
if (p != NULL) printf("%s %d %.2f\n", p->info.ten, p->info.ma, p->info.luong);
else printf("NULL\n");
printf("Nút anh em của %d: ", x);
if (s != NULL) printf("%s %d %.2f\n", s->info.ten, s->info.ma, s->info.luong);
else printf("NULL\n");
}

int main(){
float s=0;
Data n;
Data nv[100] = {{"an", 44, 2500}, {"ly", 66, 3000}, {"anh", 55, 5000}, {"lan", 77, 3600}};
node* root = NULL;
root = insert(root, nv[1]);
insert(root, nv[0]);
insert(root, nv[2]);
insert(root, nv[3]);

tt(root, 44);
}

b,
Trung (LNR): 7+(8/(12*((-9)^33)))-(11^6) = 7+8/(12*(-9)^33)-(11^6)

Câu 4.4:
a, Mỗi nút của BST: mã NV, tên, hsl, số năm công tác. Nhân viên được tăng lương sau mỗi 3 năm
công tác. Viết hàm đếm nhân viên được tăng lương trong năm nay và tăng thêm hsl cho họ 0.5
b, Vẽ sơ đồ khối thuật toán chuyển biểu thức tiền tố thành trung tố. Áp dụng + + - 6 9 / * x y – z t.
Vẽ BST của biểu thức trung tố tìm được.

a,
Input: Danh sách nhân viên (mã, tên, hsl, số năm công tác) lưu trữ theo BST (khoá mã nhân viên)
Output: Số lượng nhân viên được tăng lương năm nay và hsl của họ tăng 0.5
Method: Khai báo struct Data (chứa thông tin NV), node

#include <stdio.h>
#include <malloc.h>
typedef struct NV{
char ten[30];
int ma, namct;
float hsl;
} Data;
typedef struct node{
Data info;
struct node*left, *right;
} node;

node *insert(node *n, Data s){


node* newNode = (node*)malloc(sizeof(node));
newNode->info = s;
newNode->left = newNode->right = NULL;
if(n == NULL) return newNode;
if(s.ma < n->info.ma)
n->left = insert(n->left, s);
else if(s.ma > n->info.ma)
n->right = insert(n->right, s);
return n;
}
// Hàm duyệt cây, in ra thông tin NV được tăng lương năm nay
void LNR(node*n, float ltb){
if(n==NULL) return;
LNR(n->left, ltb);
if(n->info.namct%3==0){
n->info.hsl += 0.5;
printf("%s %d %.2f %d\n", n->info.ten, n->info.ma, n->info.hsl, n->info.namct);
}
LNR(n->right, ltb);
}
int main(){
Data nv[100] = {{"nhu", 2, 3, 1.5}, {"ly", 66, 9, 1.2}, {"anh", 11, 11, 1.1}, {"lan", 55, 12, 1.7}};
node* root = NULL;
root = insert(root, nv[1]);
insert(root, nv[0]);
insert(root, nv[2]);
insert(root, nv[3]);
printf("\nDanh sách NV được tăng lương năm nay\n");
LNR(root, s/d);
}
b, Sơ đồ khối:

Trung (LNR): ((-6)+9)+((x*y)/(z-t)) = (-6)+9+(x*y)/(z-t)

Câu 4: (25 điểm) Đề 1


a) Khai báo cấu trúc 1 nút của BST. Thông tin chứa trong nút gồm: tên, số chứng minh thư, địa chỉ.
b) Trình bày cách chèn một nút vào BST. Hãy chèn lần lượt các khóa sau vào 1 BST rỗng mà các
nút chứa các số nguyên: 19, 6, 2, 8, 26, 24, 72, 35, 26, 12. Viết hàm duyệt cây theo thứ tự trước và
đưa ra kết quả thực hiện hàm đó với cây vừa dựng.

a) _ Khai báo cấu trúc 1 nút của BST:


typedef struct{
char ten[30];
int SoCMT;
char diachi[30];
}Data;
typedef struct Node{
Data infor;
struct Node *left, *right;
}Node;
typedef Node *BST;
b) _ Cách chèn một nút vào BST:
B1: So sánh khóa mới (x) với nút gốc (T)
_ Nếu x = T: bỏ qua hoặc thêm vào T
_ Nếu x > T: duyệt cây con phải của nút gốc T (lúc này T là con phải của T).
_ Nếu x < T: duyệt cây con trái của T (lúc này T là con trái của T).
B2: Duyệt (lặp lại B1) đến khi gặp nút lá hoặc nút có khóa = x thì dừng và thêm nút mới (x)

_ Hàm duyệt cây theo thứ tự trước:


void NLR(node *n){
if(n == NULL) return;
printf("%d ", n->info);
NLR(n->left);
NLR(n->right);
}
_ KQ: 19 6 2 8 12 26 24 72 35

Câu 4: Đề 2
a) Hãy chèn lần lượt các khóa sau vào BST rỗng: 19, 7, 1, 9, 25, 21, 70, 7, 30, 8. Xóa nút gốc khỏi
cây. Đưa ra kết quả duyệt cây theo thứ tự trước và thứ tự sau với cây sau khi xóa nút gốc.
b) Viết hàm thêm một nút vào cây tìm kiếm nhị phân.
_ Xóa nút gốc:
a) TH1: nút min cây con phải TH2: nút max cây con trái

_ Duyệt cây:
+ TH1: NLR: 21 7 1 9 8 25 70 30 + TH2: NLR: 9 7 1 8 25 21 70 30
LRN: 1 8 9 7 30 70 25 21 LRN: 1 8 7 21 30 70 25 9
b) _ Hàm thêm một nút:
node *insert(node *n, int x){
node *newNode = (node*)malloc(sizeof(node));
newNode->info = x;
newNode->left = newNode->right = NULL;
if(n==NULL) return newNode;
if(x < n->info) n->left = insert(n->left, x);
else if(x > n->info) n->right = insert(n->right, x);
return n;
}

Câu 4: Đề 3
a) Thông tin của nhân viên: mã (khóa), họ tên, lương. Khai báo cấu trúc cây BST lưu thông tin trên.
b)Vẽ BST khi thêm nhân viên: {(12, Hùng, 100), (22, Huy, 200), (11, Hậu, 150), (7, Vân, 100), (14,
Trang, 400), (24, Sỹ, 300), (2, Linh, 100), (10, Lâm, 700), (22, Huy, 200)}. Kết quả phép duyệt giữa
a)
typedef struct NV{
int ma;
char ten[20];
float luong;
}data;
typedef struct node{
data info;
struct node *left, *right;
}node;
typedef node *bst;

Câu 4: Đề 4
a) Hãy chèn lần lượt các khóa sau vào BST rỗng: 17, 5, 1, 20, 19, 30, 8, 18, 9, 16, 55, 34. Vẽ lại các
cây sau khi xóa mỗi nút: 20, 11, 17, 5.
b) Chuyển biểu thức trung tố sau thành biểu thức tiền tố, hậu tố: 12*5 + 2*(17-3*4) + 8

a)

b,

Tiền (NLR): + + * 12 5 * 2 - 17 * 3 4 8
Hậu (LRN): 12 5 * 2 17 3 4 * - * + 8 +

Câu 4: Đề 8
Chuyển thành dạng trung, hậu tố và cho biết giá trị: +, +, 12, *, 30, -, /, 48, 2, 29, /, -, 37, 17.
_ Trung: (12+(30*((48/2)-29)))+((-37) / 17) = 12+30*(48/2-29)+(-37) / 17
_ Hậu: 12 30 48 2 / 29 - * + 37- 17 / +
_ Giá trị: -140.176
Câu 4: Đề 5
a, Chèn lần lượt các khóa sau vào một cây tìm kiếm nhị phân rỗng: 20, 5, 1, 17, 30, 24, 7, 18, 23, 9,
32, 25. Trình bày cách xóa một nút khỏi cây. Vẽ lại các cây sau khi xóa mỗi nút: 24, 10, 7.
b, Chuyển biểu thức trung tố sau thành dạng hậu tố và tiền tố: x*y + z*(t-u).

a) _ Cách xóa một nút khỏi cây:


TH1: nút cần xóa ko có con (xóa là xong)
TH2: nút cần xóa có 1 con: xóa nút cần xóa và thế con của nó vào vị trí tương ứng.
TH3: nút cần xóa có 2 con:
- C1: đổi chỗ nút cần xóa cho nút lớn nhất bên trái
- C2: đổi chỗ nút cần xóa cho nút nhỏ nhất bên phải
Sau khi đổi chỗ thì xóa nút cần xóa ở vị trí mới

b)
Hậu: x y * z t u - * +
Tiền: + * x y * z – t u

Câu 4: Đề 6
Chèn lần lượt các khóa sau vào một cây tìm kiếm nhị phân rỗng: 22, 15, 1, 17, 31, 24, 7, 18, 23, 9,
32, 1, 31, 25. Xóa khỏi cây lần lượt các nút: 24, 1, 7, 31. Vẽ lại các cây sau khi xóa mỗi nút.
Câu 4: Đề 7
a) Chèn lần lượt các khóa sau vào BST rỗng: 20, 25, 11, 27, 10, 24, 7, 18, 23, 9, 32, 11, 30. Xóa
khỏi cây lần lượt các nút chứa các khóa sau: 20, 10, 45, 11. Vẽ lại các cây sau khi xóa mỗi nút.
b) Chuyển thành dạng trung, tiền tố và cho biết giá trị: 12, 30, 48, 2, /, 29, -, *, +, 37, 17, -, 2, /, +

a)

b)
Trung: 12+(30*((48/2)-29))+((37-17)/2) = 12+30*(48/2-29)+(37-17)/2
Tiền: + + 12 * 30 - / 48 2 29 / - 37 17 2
Giá trị: -128

Câu 2: Đề 7, 6
a) Khai báo cấu trúc BST chứa thông tin nhân sự: Họ tên; Mã nhân sự (khóa); HSL; Lương cơ bản
b.7) Viết hàm tính tổng lương của n nhân viên. Biết lương 1 nhân viên = lương có bản*hệ số lương.
b.6) Viết hàm thêm một bản ghi chứa thông tin nhân sự của một người vào cây đã khai báo

b.7)
Input: Danh sách nhân sự (Họ tên; Mã; HSL; Lương cơ bản) lưu trữ theo BST (khoá là mã)
Output: Tổng lương của n nhân viên
Method: Khai báo struct Data (chứa thông tin NS), node

b.6)
Input: Danh sách nhân sự (Họ tên; Mã; HSL; Lương cơ bản) lưu trữ theo BST (khoá là mã)
Output: Cây BST đã thêm 1 nút nới
Method: Khai báo struct Data (chứa thông tin NS), node

#include <stdio.h>
#include <malloc.h>
// a) Khai báo cấu trúc BST
typedef struct NV{
char ten[20];
int ma;
float hsl, luongcb;
}Data;
typedef struct node{
Data info;
struct node *left, *right;
}node;
typedef node *bst;
// b.7) Hàm duyệt cây, in ra thông tin NV, tính tổng lương n NV
void LNR(node *n, float*s){
if(n==NULL) return;
float luong = n->info.luongcb*n->info.hsl;
*s += luong; // Tổng lương của n nhân viên
LNR(n->left, s);
LNR(n->right, s);
}

// b.6) Hàm thêm 1 nút vào cây BST


node *insert(node *n, Data s){
node* newNode = (node*)malloc(sizeof(node));
newNode->info = s;
newNode->left = newNode->right = NULL;
if(n == NULL) return newNode;
if(s.ma < n->info.ma)
n->left = insert(n->left, s);
else if(s.ma > n->info.ma)
n->right = insert(n->right, s);
return n;
}

// Hàm thêm 1 bản ghi


node* nhap(node *n, Data s){
printf("Họ tên: "); fgets(s.ten, sizeof(s.ten), stdin);
s.ten[strcspn(s.ten, "\n")] = '\0';
printf("Mã: "); scanf("%d", &s.ma);
printf("HSL: "); scanf("%f", &s.hsl);
printf("Lương cơ bản: "); scanf("%f", &s.luongcb);
insert(n, s);
}

int main(){
float s=0;
Data n;
Data nv[100] = {{"an", 44, 1, 1100}, {"ly", 66, 1.2, 2100}, {"anh", 11, 1, 5100}, {"lan", 55, 1, 3100}};
node* root = NULL;
root = insert(root, nv[1]);
insert(root, nv[0]);
insert(root, nv[2]);
insert(root, nv[3]);

LNR(root, &s);
printf("\nTổng lương các nhân viên: %.2f\n", s);

nhap(root, n);
LNR(root, &s);
}
Chương trình hoàn chỉnh
DSLK đơn
DSLK sinh viên
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <string.h>
typedef struct SV{
char ten[30];
int msv;
float dtb;
}Data;
typedef struct node{
Data infor;
struct node *next;
}node;
typedef struct List{
node *head, *tail;
int spt;
}list;
void init(list *L){
L->head = L->tail = NULL;
L->spt = 0;
}
//Kiểm tra rỗng
int empty(list L){
return (L.spt==0); //(L.head==NULL)
}
//In ds kiểu node
void in(node *head){
while(head != NULL){
printf("%s %d %.2f -> ", head->infor.ten, head->infor.msv, head->infor.dtb);
head = head->next;
}
printf("NULL\n");
}
//In ds kiểu list
void xuat(list L){
node *p=L.head;
while(p!=NULL){
printf("%s %d %.2f -> ", p->infor.ten, p->infor.msv, p->infor.dtb);
p = p->next;
}
printf("NULL \n");
}
void themDau(list *L, Data val){
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = val;
newNode->next = L->head; // = NULL nếu thêm vào list rỗng
L->head = newNode;
if(L->tail==NULL) L->tail = newNode;
L->spt++;
}
void themCuoi(list *L, Data val){
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = val;
newNode->next = NULL;
if(L->head==NULL) L->head = L->tail = newNode; // nếu list rỗng (empty(*L))
else{
L->tail->next = newNode;
L->tail = newNode;
}
L->spt++;
}
// Thêm nút vào sau msv x
void themSaux(list *L, int x, Data s){
if(L->head==NULL) return;
node *p = L->head;
while(p->next!=NULL && p->infor.msv != x){
p = p->next;
}
if(p->infor.msv != x) return;
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = s;
newNode->next = p->next;
p->next = newNode;
if(L->tail->infor.msv == x) L->tail = newNode; //
L->spt++;
}
// Thêm sau nút q (input: kiểu Node)
void insertAfter(list *L, node *q, Data x){
node *pp;
if(NULL==q) return;
else{
pp=(node*)malloc(sizeof(node));
pp->infor=x;
pp->next=q->next;
q->next=pp;
if(L->tail==q) L->tail=pp;
L->spt++;
}
}
// Thêm nút vào trước msv x
void themTruocx(list *L, int x, Data s){
if(L->head==NULL) return;
node *p = L->head;
if(p->infor.msv == x){
themDau(L, s);
return;
}
while(p->next!=NULL && p->next->infor.msv != x){
p = p->next;
}
if(p->next->infor.msv != x) return;
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = s;
newNode->next = p->next;
p->next = newNode;
L->spt++;
}
// Sắp xếp chọn
void SelectionSort(list *L){
for(node*i = L->head; i!=NULL;i=i->next){
node *min = i;
for(node*j = i->next; j!=NULL;j=j->next){
if(j->infor.dtb<min->infor.dtb){
min = j;
}
}
Data tmp = i->infor;
i->infor = min->infor;
min->infor = tmp;
}
}
// Thêm nút ds vẫn sx tăng
void sortedinsert(list *L, Data s){
if(L->head==NULL) themDau(L, s);
node *newNode = (node*)malloc(sizeof(node));
newNode->infor = s;
node *p = L->head;
if(p->infor.dtb >= s.dtb){
themDau(L, s);
return;
}
while(p->next!=NULL && p->next->infor.dtb < s.dtb){
p = p->next;
}
newNode->next = p->next;
p->next = newNode;
if(L->tail->infor.dtb <= s.dtb) L->tail = newNode; //
L->spt++;
}
void xoaDau(list *L){
if(L->head==NULL) return;
node *xoa = L->head;
L->head = xoa->next;
free(xoa);
L->spt--;
if(L->head==NULL) L->tail = NULL; //ds có 1 nút, sau khi xóa: ds rỗng
}
void xoaCuoi(list *L){
if(L->head==NULL) return;
node *p = L->head;
while(p->next!=L->tail)
p=p->next;
free(p->next);
L->tail = p;
L->tail->next = NULL; //
L->spt--;
}
void xoaX(list *L, int x){
node *pp = L->head, *q; // pp: nút cần xóa, q: nút trước pp
while(pp!=NULL && pp->infor.msv != x){
q=pp;
pp=pp->next;
}
if(pp==NULL) return; // nếu ds rỗng hoặc ds ko có x
if(pp == L->head){
L->head = pp->next;
free(pp);
if(L->head==NULL) L->tail = NULL;
} //xoaDau(L);
else{
q->next = pp->next;
free(pp);
if(L->tail==NULL) L->tail = q; //xóa cuối
}
L->spt--;
}
// Xóa sau node q
void delAfter(list *L, node *q){
node *pp;
if(q==NULL) return;
else{
pp=q->next;
q->next=pp->next;
free(pp);
L->spt--;
if(q->next==NULL) q=L->tail;
}
}
//Tách ds đã sắp xếp: L<5, L2>=5
void tach(list *L, list *L2){
node *p=L->head;
while(p->next!=NULL && p->next->infor.dtb<5){
p=p->next;
}
L2->head = p->next;
L->tail = p;
p->next = NULL;
}
//Tách ds chưa sắp xếp: L<5, L2>=5
// cách 1
void tach1(list *L, list *L1, list *L2){
for(node *i=L->head;i!=NULL;i=i->next){
if(i->infor.dtb < 5){
themDau(L1, i->infor);
}
else themDau(L2, i->infor);
}
}
// cách 2
void moveNode(node **source, node **dest){
node *newNode = *source;
assert(newNode!=NULL);
*source = newNode->next;
newNode->next = *dest;
*dest = newNode;
}
void split(node *source, node **aRef, node **bRef){
node *a = NULL;
node *b = NULL;
while(source!=NULL){
if(source->infor.dtb < 5)
moveNode(&source, &a);
else if(source->infor.dtb >= 5 && source!=NULL)
moveNode(&source, &b);
}
*aRef = a;
*bRef = b;
}

// Gộp 2ds đã sx theo đtb mà vẫn sx


node* gop(list* L1, list* L2) {
if (!L1->head) return L2->head;
if (!L2->head) return L1->head;
node* head = NULL;
if (L1->head->infor.dtb < L2->head->infor.dtb) {
head = L1->head;
L1->head = L1->head->next;
head->next = gop(L1, L2);
} else {
head = L2->head;
L2->head = L2->head->next;
head->next = gop(L1, L2);
}
return head;
}
int main(){
list L;
init(&L);
Data sv[10]= {{"anh", 22, 4}, {"binh", 33, 5}, {"an", 44, 8.8}, {"yen", 55, 3.6}, {"hai",
66, 2.4}, {"linh", 76, 10}, {"li", 73, 7}};
themDau(&L, sv[0]); // 22
themDau(&L, sv[1]); // 33 - 22
themCuoi(&L, sv[2]); // 33 - 22 - 44
themSaux(&L, 22, sv[3]);
themTruocx(&L, 33, sv[4]);
xuat(L);

printf("\nTách ds chưa sắp xếp\n");


list La, Lb;
init(&La);
init(&Lb);
tach1(&L, &La, &Lb); // giữ lại ds ban đầu
xuat(La); //in(La.head);
xuat(Lb);

printf("\nDS sx theo điểm\n");


SelectionSort(&L);
xuat(L);
chentang(&L, sv[5]); //sortedinsert(&L, sv[5]);
xuat(L);
printf("\n");
xoaDau(&L);
//xoaCuoi(&L);
xoaX(&L, 6);
//del_K(&L);
xuat(L);

printf("\nTách ds đã sắp xếp\n");


list L2;
init(&L2);
tach(&L, &L2);

xuat(L2);
printf("\nGộp ds\n");
themCuoi(&L, sv[6]);
themDau(&L2, sv[4]);
in(gop(&L, &L2));
}

DSLK đôi
DSLK sinh viên
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct SV{
char ten[50];
int msv;
float dtb;
}SV;
typedef struct node{
SV data;
struct node *next; // con trỏ đến nút sau
struct node *prev; // [khác] con trỏ đến nút trước (địa chỉ nút trước)
// nút đầu prev là NULL
} node;
// Thêm nút vào đầu list
node *makenode(char *ten, int msv, float dtb){
node *newnode = (node*)malloc(sizeof(node)); //C++: node *newnode = new node;
strcpy(newnode->data.ten, ten);
newnode->data.msv = msv;
newnode->data.dtb = dtb;
newnode->next = NULL;
newnode->prev = NULL;
return newnode;
}
void themDau(node **head, char *ten, int msv, float dtb){
node *newnode = makenode(ten, msv, dtb);
newnode->next = *head;
if(*head != NULL)
(*head)->prev = newnode;
*head = newnode;
}
void themCuoi(node **head, char *ten, int msv, float dtb){
node *newnode = makenode(ten, msv, dtb);
if(*head==NULL){ // nễu list rỗng
*head = newnode;
return;
}
node *tmp = *head;
//khi bỏ con trỏ (*) thì tmp là node
while(tmp->next!=NULL){
tmp = tmp->next;
}
newnode->prev = tmp;
tmp->next = newnode;
}
// Thêm nút mới vào sau nút có msv x
void insertAf(node **head, int x, char *ten, int msv, float dtb){
node *newnode = makenode(ten, msv, dtb);
node *tmp = *head;
while(tmp->next != NULL){
if(tmp->data.msv == x){
newnode->next = tmp->next;
newnode->prev = tmp;
tmp->next->prev = newnode;
tmp->next = newnode;
return;
}
else tmp = tmp->next;
}
if(tmp->data.msv == x){
themCuoi(head, ten, msv, dtb);
}
}
// Thêm nút mới vào trước nút có giá trị x
void insertBef(node **head, int x, char *ten, int msv, float dtb){
node *newnode = makenode(ten, msv, dtb);
node *tmp = *head;
if(tmp->data.msv == x){
themDau(head, ten, msv, dtb);
}
while(tmp->next != NULL){
if(tmp->next->data.msv == x){
newnode->next = tmp->next;
newnode->prev = tmp;
tmp->next->prev = newnode;
tmp->next = newnode;
return;
}
else tmp = tmp->next;
}
}
int size(node *head){
int d=0;
while(head != NULL){
d++;
head = head->next;
}
return d;
}
// Thêm nút vào sau nút có chỉ số k
void insertAfterk(node **head, int k, char *ten, int msv, float dtb){
if(k<0 || k>=size(*head)) return;
node *tmp = *head;
if(k==size(*head)-1){
themCuoi(head, ten, msv, dtb);
return;
}
for(int i=0;i<k;i++){
tmp = tmp->next;
}
node *newnode = makenode(ten, msv, dtb);
newnode->next = tmp->next;
newnode->prev = tmp;
tmp->next->prev = newnode;
tmp->next = newnode;
}
// Thêm nút vào trước nút có chỉ số k
void insertBeforek(node **head, int k, char *ten, int msv, float dtb){
if(k<0 || k>=size(*head)) return;
if(k==0){
themDau(head, ten, msv, dtb);
return;
}
node *tmp = *head;
for(int i=0;i<k-1;i++){
tmp = tmp->next;
}
node *newnode = makenode(ten, msv, dtb);
newnode->next = tmp->next;
newnode->prev = tmp;
tmp->next->prev = newnode;
tmp->next = newnode;
}
//Thêm sau node chỉ định (prev_node)
void insertAfter(node* prev_node, char* ten, int msv, float dtb) {
if (prev_node == NULL) return;
node *newnode = makenode(ten, msv, dtb);
newnode->next = prev_node->next;
prev_node->next = newnode;
newnode->prev = prev_node;
if (newnode->next != NULL) newnode->next->prev = newnode;
}
void xoaDau(node **head){
node *tmp = *head;
if(*head==NULL) return; // list rỗng
(*head) = (*head)->next;
tmp->next->prev = NULL;
free(tmp); // xóa node thứ 1
}
void xoaCuoi(node **head){
node *tmp = *head;
if(*head==NULL) return; // list rỗng
if(tmp->next == NULL){ // list có 1 nút
*head = NULL;
free(tmp);
return;
}
while(tmp->next->next!=NULL){ // list có > 1 nút
tmp = tmp->next;
}
node *last = tmp->next; //khai báo node cuối cùng
tmp->next = NULL; //temp trỏ đến NULL
free(last);
}
//Xóa nút có msv val
void xoa_val(node **head, int msv){
if(*head==NULL) return; // list rỗng
node *tmp = *head;
if(tmp->data.msv==msv){
xoaDau(head);
}
while(tmp->next!=NULL){
if(tmp->data.msv==msv){
tmp->next->prev = tmp->prev;
tmp->prev->next = tmp->next;
free(tmp);
return;
}
tmp=tmp->next;
}
if(tmp->data.msv==msv) xoaCuoi(head);
}
// xóa node chỉ định (del)
void deleteNode(node** head_ref, node* del){
if (*head_ref == NULL || del == NULL) return;
if (*head_ref == del) *head_ref = del->next; // xóa node đầu
if (del->next != NULL) del->next->prev = del->prev;
if (del->prev != NULL) del->prev->next = del->next;
free(del);
}
void inxuoi(node *head){
while(head != NULL){
printf("%s %d %.2f\n", head->data.ten, head->data.msv, head->data.dtb);
head = head->next;
}
}
void innguoc(node *head){
printf("Danh sách đảo ngược\n");
node *last;
while(head != NULL){
last = head;
head = head->next;
}
while(last != NULL){
printf("%s %d %.2f\n", last->data.ten, last->data.msv, last->data.dtb);
last = last->prev;
}
}
int main(){
node *head = NULL;
themDau(&head, "Mai", 11, 10); // 11
themCuoi(&head, "Anh", 22, 9); // 11 22
themDau(&head, "Nam", 12, 9.2); // 12 11 22
insertAf(&head, 11, "My", 10, 8); // 12 11 10 22
insertBef(&head, 22, "Hoa", 33, 9.2); // 12 11 10 33 22
insertAfterk(&head, 1, "Kim", 20, 8.5); // 12 11 20 10 33 22
insertBeforek(&head, 4, "Duy", 30, 7); // 12 11 20 10 30 33 22
insertAfter(head->next, "Hai", 8, 9.4);// 12 11 8 20 10 30 33 22
xoaDau(&head); // 11 20 10 30 33 22
xoaCuoi(&head); // 11 20 10 30 33
xoa_val(&head, 10); // 11 20 30 33

inxuoi(head);
innguoc(head);
}

Stack
Cài đặt stack bằng dslk (con trỏ)
#include <stdio.h>
#include <malloc.h>
typedef struct node{
int data;
struct node *next;
}node;
typedef struct stack{
node *top;
int spt;
}stack;
//khởi tạo stack rỗng
void initStack(stack *s){
s->top = NULL;
s->spt = 0;
}
//Kiểm tra rỗng
int emptyStack(stack s){
return (s.top == NULL);
}
//Thêm phần tử
void push(stack *s, int val){
node *newp = (node*)malloc(sizeof(node));
newp->data = val;
newp->next = NULL;
if(emptyStack(*s)) s->top=newp;
else{
newp->next = s->top;
s->top = newp;
}
s->spt++;
}
//Lấy phần từ ra theo nguyên tắc LIFO
int pop(stack *s){
int val;
node *xoa;
if(emptyStack(*s)) return 0;
else{
xoa = s->top;
val = xoa->data;
s->top = xoa->next;
free(xoa);
s->spt--;
}
return val;
}
//Lấy giá trị phần tử ở đỉnh
void topS(stack s){
if(emptyStack(s)) return;
printf("Phần tử ở đỉnh là: %d\n", s.top->data);
}
int main(){
stack s;
int arr[sizeof(s)/sizeof(int)];
initStack(&s);
push(&s, 2); // 2
push(&s, 7); // 2 7
push(&s, 5); // 2 7 5
push(&s, 9); // 2 7 5 9
topS(s);
while(!emptyStack(s))
printf("%d ", pop(&s));
printf("\n");
// Chuyển thập -> nhị phân
int sohe10;
scanf("%d", &sohe10); //24
while(sohe10!=0){
push(&s, sohe10%2); // 0 0 0 1 1
sohe10/=2;
}
int x;
while(!emptyStack(s))
printf("%d ", pop(&s)); // 1 1 0 0 0
}
Queue
Cài đặt queue bằng dslk (con trỏ)
#include<stdio.h>
#include<malloc.h>
#include<math.h>
#include<string.h>
typedef struct QNode {
int infor;
struct QNode *link;
} Node;
typedef struct tagQueue{
Node *front, *rear; // con trỏ đầu, con trỏ cuối
int spt;
} Queue;
Queue Q; // khai báo toàn cục
// Khởi tạo Queue rỗng (C1)
void InitQ(Queue Q) {
Q.front = Q.rear = NULL;
Q.spt = 0;
}
/*void InitQ(Queue *Q) {
Q->front = Q->rear = NULL;
Q->spt = 0;
}*/ //(C2)
//Kiểm tra rỗng
int emptyQ(Queue Q) {
return (Q.spt == 0);
}
//Thêm pt vào cuối
void AddQ(Queue *Q, int X) {
Node *p = (Node*)malloc(sizeof(Node)); // khai báo node mới
p->infor = X;
p->link = NULL;
if(emptyQ(*Q)) { // nếu rỗng: front và rear cùng chỉ vào node mới
Q->front = p;
Q->rear = p;
}
else {
Q->rear->link = p; // pt cuối nối vào nút mới
Q->rear = p; // p trở thành nút cuối (rear trỏ vào p)
}
Q->spt++;
}
//Lấy pt ra ở đầu
void DelQ(Queue *Q, int *X) { // X là con trỏ
if(emptyQ(*Q)) return;
else {
Node *p = Q->front; // gọi node p là node cần xóa
*X = p->infor; // gán giá trị của node lấy ra vào biến X (không phải con trỏ)
Q->front = p->link; // con trỏ đầu trỏ vào node thứ 2 (node đầu mới)
free(p); // xóa node p
Q->spt--; // giảm spt
}
}
//In ra các pt có trong Queue mà ko lấy ra (xóa)
void processQueue(Queue Q) {
Node *p = Q.front;
while (p!=NULL) {
printf("%d ",p->infor);
p = p->link;
}
printf("\n");
}
// Lấy pt ở đầu mà không xóa (C1)
void TopQ(Queue Q){
if(emptyQ(Q)) return;
int X = Q.front->infor; // Q ko phải con trỏ nhưng Q.front là con trỏ
printf("Phần tử ở đầu: %d\n", X);
}
/*void TopQ(Queue *Q){
if(emptyQ(*Q)) return;
int X = Q->front->infor;
printf("Phần tử ở đầu: %d\n", X);
}*/ //(C2)
int main() {
InitQ(Q); //Hang doi rong
AddQ(&Q,5); //5
AddQ(&Q,11); //5 11
AddQ(&Q,9); //5 11 9
AddQ(&Q,0); //5 11 9 0
AddQ(&Q,7); //5 11 9 0 7
processQueue(Q);
int X;
TopQ(Q);
while(!emptyQ(Q)) {
DelQ(&Q,&X);
printf("%d ",X);
}
printf("\n");
// nhị/bát/thập lục phân sang thập phân
char so[100]; // dãy input
int co_so, mu = 0, tong = 0, n;
scanf("%s %d", so, &co_so);
for(int i=strlen(so)-1;i>=0;i--){
if(so[i]>='0' && so[i]<='9') n = so[i] - '0';
else n = so[i] + 10 - 'A';
AddQ(&Q,n);
}
while(!emptyQ(Q)){
DelQ(&Q, &X);
tong += X*pow(co_so,mu);
mu++;
}
printf("%d ",tong);
/* nếu không có hệ 16 (kí tự)
int so, co_so, mu = 0, tong = 0, n;
scanf("%d %d", &so, &co_so);
while(so!=0){
AddQ(&Q,so%10);
so/=10;
}
while(!emptyQ(Q)){
DelQ(&Q, &X);
tong += X*pow(co_so,mu);
mu++;
}
printf("%d ",tong);*/
}
Tìm kiếm & Sắp xếp
Mảng số nguyên
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void nhap(int a[], int n){
for(int i=0;i<n;i++)
scanf("%d", &a[i]);
}
void in(int a[], int n){
for(int i=0;i<n;i++)
printf("%d ", a[i]);
printf("\n");
}
//Tìm kiếm tuần tự
void LinearS(int a[], int n, int x){
int i=0;
while ((i<x) && (a[i]!=x)) // đk dừng: i<n
i++; // nếu chưa thấy và pt vẫn thuộc mảng: tăng biến đếm
if(i==n) printf("Không thấy\n"); //Tim het mang nhung không có x
else printf("%d có vị trí: %d\n", x, i);; //a[i] la phan tu có khoá x
}
//Tìm kiếm tuần tự có lính canh (nhanh hơn vì có 1 đk vòng while)
void LinearS1(int a[], int n, int x){
int i=0;
a[n] = x;
while (a[i]!=x)
i++;
if(i==n) printf("Không thấy\n");
else printf("%d có vị trí: %d\n", x, i);
}
//Tìm kiếm nhị phân (chỉ với dãy đã sắp)
// nếu ko khai báo mảng a toàn cục (không đệ quy)
void binaryS(int a[], int n, int x) {
int l = 0, r = n-1, mid; //l: đầu trái, r: cuối phải
while(r >= l) { //nếu trái -> phải
mid = l + (r - l)/2; //tìm vị trí ở giữa
if (a[mid] == x){ //nếu x ở giữa
printf("%d có vị trí: %d\n", x, mid);
return;
}
if (a[mid] > x) r = mid-1;//nếu x < pt ở giữa: TKNP bên trái
else l = mid+1; //nếu x > mid: TKNP bên phải
}
printf("Không thấy\n");
} //nếu khai báo mảng a[] toàn cục (đệ quy)

// Thay vì đổi chỗ ở từng hàm sx, có thể viết hàm swap()
void swap(int *xp, int *yp) {
int temp = *xp;
*xp = *yp;
*yp = temp;
}

// Selection sort (chọn): Tìm min (ban đầu tạm gọi là node đầu)
// sau khi thấy node min thực thì đổi chỗ với min tạm và đánh dấu
// đã sắp (ko xét nữa) Tiếp theo gọi min tạm là node sau dãy đã sắp
// và tìm min thực (trừ node đã sắp)...Lặp đến node thứ 2 từ cuối
void sel_sort(int a[], int n){
for(int i=0;i<n-1;i++){ // xét từ node đầu - node thứ 2 từ cuối
int min = i; // min tạm
for(int j=i+1;j<n;j++) // duyệt từ sau min tạm (và dãy đã sắp) - cuối
if(a[j]<a[min]) // nếu sau < trước
min = j; // min thực
int tmp = a[i]; // đổi chỗ min thực (min) và min tạm (i)
a[i] = a[min];
a[min] = tmp;
}
}

//Interchange sort
void inter_sort(int a[], int n){
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
if(a[j]>a[i]){
int tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
}
}

// Insertion sort (chèn): coi nút đầu đã sắp, xét từ node 2 để tìm
// (chèn vào) vị trí mới (đổi chỗ 2 nút kề (1 nút key, 1 nút vị trí
// -trước key) đến khi tới chỗ phù hơp) và đánh dấu (ko xét nữa)
void inser_sort(int a[], int n){
int key, j;
for(int i=1;i<n;i++){ // xét từ node 2 - node thứ 2 từ cuối
key = a[i]; // nút cần tìm chỗ mới
j = i-1; // chỗ mới: từ trước node key -> vị trí đầu (j>=0)
while(j>=0 && a[j]>key){
a[j+1] = a[j]; //nếu trước (j)>sau (key = j+1): đổi chỗ 2 nút kề // tịnh tiến gia trị: gán
sau = trước
j--; // đi lùi // j là chỗ trước vị trí cần thêm
}
a[j+1] = key; // vị trí của key
}
}

// Buble sort: đổi chỗ 2 nút kề (1-2, 2-3, 3-4...), nhỏ hơn lên trước (nổi lên),
// nút lớn nhất sẽ xuống cuối (mark), tiếp tục về đầu và đổi chỗ 2 nút kề
void bub_sort(int a[], int n){
for(int i=0;i<n-1;i++){ // số lần so sánh (-1 vì phần tử cuối tự sắp)
for(int j=0;j<n-1-i;j++){ // xét từ đầu - pt trước dãy đã sắp
if(a[j+1]<a[j]){ // nếu sau < trước: đổi chỗ 2 nút kề
int tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
}
}
}
}

// Quick sort
// Chọn pivot: đầu / random / avg của 3
int partition(int a[], int low, int high){ // Phân hoạch
int pivot = a[high]; //pivot
int i = (low-1); // chỉ số pt nhỏ hơn và chỉ ra pt bên phải pivot gần nhất
for(int j=low;j<high;j++){
if(a[j] <= pivot){ // nếu pt hiện tại < pivot // giam dan: a[j].ma >= pivot
i++;
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
int tmp = a[i+1];
a[i+1] = a[high];
a[high] = tmp;
return i+1;
}
void qu_sort(int a[], int low, int high){// mảng cần sx, điểm đầu, điểm cuối
if(low<high){
int pi = partition(a, low, high); //pi is partitioning index, arr[p] is now at right place
qu_sort(a, low, pi-1); // Separately sort elements before partition and after partition
qu_sort(a, pi+1, high);
}
}

// Heap sort
void heapify(int a[], int n, int i){
int largest = i;
int l = 2*i+1; // left
int r = 2*i+2; // right
// neu nhanh trai > goc
if(l<n && a[l]>a[largest]){
largest = l;
}
// neu nhanh phai > goc
if(r<n && a[r]>a[largest]){
largest = r;
}
//neu phan tu lon nhat khong phai goc
if(largest!=i){
int tmp = a[i];
a[i] = a[largest];
a[largest] = tmp;
heapify(a, n, largest);
}
}
void heap_sort(int a[], int n){
for(int i=n/2-1;i>=0;i--){
heapify(a, n, i);
}
for(int i=n-1;i>=0;i--){
int tmp = a[i];
a[i] = a[0];
a[0] = tmp;
heapify(a, i, 0);
}
}

// Merge sort (ko học)


void merge(int arr[], int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
int L[n1], R[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2) {
if (L[i] <= R[j]) { //*****KHOA CAN SAP XEP*****//
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there are any */
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there are any */
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
// l is for left index and r is right index of the sub-array of arr to be sorted
void MergeSort(int arr[], int l, int r) {
if (l < r) {
// Same as (l+r)/2, but avoids overflow for large l and h
int m = l + (r - l) / 2;
// Sort first and second halves
MergeSort(arr, l, m);
MergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
int main(){
int n = 6, a[10] = {6, 7, 2, 4 ,9, 0};
//scanf("%d", &n);
//nhap(a, n);
in(a, n);
LinearS(a, n, 4);
LinearS1(a, n, 7);

printf("\nDanh sách sắp xếp \n");


sel_sort(a, n);
//inser_sort(a, n);
//inter_sort(a, n);
//bub_sort(a,n);
//qu_sort(a, 0, n-1);
//heap_sort(a, n);
//MergeSort(a, 0, n-1);
in(a, n);

LinearS(a, n, 9);
binaryS(a, n, 6);
}

Mảng sinh viên


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct SV{
char ten[50];
int ma;
float dtb;
}SV;
void nhap(SV sv[], int n){
for(int i=0;i<n;i++){
scanf("%s%d%f", sv[i].ten, &sv[i].ma, &sv[i].dtb);
}
}
/* cách2: ko ổn
void Nhap(Sinh_vien *sv) {
printf("Ma SV: "); scanf("%d", &sv->ma);
printf("Ten SV: "); fflush(stdin); gets(sv->ten);
printf("Diem TB: "); scanf("%f", &sv->dtb);
}*/
void in(SV sv[], int n){
for(int i=0;i<n;i++){
printf("%s %d %.2f\n", sv[i].ten, sv[i].ma, sv[i].dtb);
}
}
/* cách2
void In(Sinh_vien *sv) {
printf("Ma SV: %d\n", sv->ma);
printf("Ten SV: %s\n", sv->ten);
printf("Diem TB: %3.1f\n", sv->dtb);
}*/
//Tìm kiếm
//Tìm kiếm tuần tự sinh viên theo msv
void LinearS_sv(SV sv[], int sosv, int ma){
int i=0;
while ((i<sosv) && (sv[i].ma!=ma)) // đk dừng: i<n
i++; // nếu chưa thấy và pt vẫn thuộc mảng: tăng biến đếm
if(i==sosv) printf("Không thấy sinh viên có mã %d\n", ma); //Tim het mang nhung không
có x
else printf("Sinh viên %s %d %.2f\n", sv[i].ten, sv[i].ma, sv[i].dtb);; //a[i] la phan tu có
khoá x
}
//Tìm kiếm tuần tự sinh viên theo ten
void LinearS_ten(SV sv[], int sosv, char *ten){
int i=0;
while ((i<sosv) && strcmp(sv[i].ten, ten)!=0) // đk dừng: i<n
i++; // nếu chưa thấy và pt vẫn thuộc mảng: tăng biến đếm
if(i==sosv) printf("Không thấy sinh viên có tên %s\n", ten); //Tim het mang nhung không
có x
else printf("Sinh viên %s %d %.2f\n", sv[i].ten, sv[i].ma, sv[i].dtb);; //a[i] la phan tu có
khoá x
}
//Tìm kiếm tuần tự có lính canh sinh viên theo msv (nhanh hơn vì có 1 đk vòng while)
void LinearS_sv1(SV sv[], int sosv, int ma){
int i=0;
sv[sosv].ma = ma;
while (sv[i].ma!=ma)
i++;
if(i==sosv) printf("Không thấy sinh viên có mã %d\n", ma);
else printf("Sinh viên %s %d %.2f\n", sv[i].ten, sv[i].ma, sv[i].dtb);
}
//Tìm kiếm nhị phân (chỉ với dãy đã sắp tăng) sinh viên theo msv
// nếu ko khai báo mảng a toàn cục (không sd đệ quy)
void binaryS_sv(SV sv[], int n, int ma) {
int l = 0, r = n-1, mid; //l: đầu trái, r: cuối phải
while(r >= l) { //nếu trái -> phải
mid = l + (r - l)/2; //tìm vị trí ở giữa
if (sv[mid].ma == ma){ //nếu x ở giữa
printf("Sinh viên %s %d %.2f\n", sv[mid].ten, sv[mid].ma, sv[mid].dtb);
return;
}
if (sv[mid].ma > ma) r = mid-1;//nếu x < pt ở giữa: TKNP bên trái
else l = mid+1; //nếu x > mid: TKNP bên phải
}
printf("Không thấy sinh viên có mã %d\n", ma);
} //nếu khai báo mảng a[] toàn cục (đệ quy)

// Thay vì đổi chỗ ở từng hàm sx, có thể viết hàm swap()
void swap(SV *xp, SV *yp) {
SV temp = *xp;
*xp = *yp;
*yp = temp;
}
// Hàm so sánh theo msv (ten)
int comparator(const void* p, const void* q) {
// Sap xep theo msv
return ((SV*)p)->ma > ((SV*)q)->ma;
// Sap xep theo TenSV
//return strcmp(((SV*)p)->TenSV, ((SV*)q)->TenSV);
}

// Selection sort (chọn): Tìm min (ban đầu tạm gọi là node đầu)
// sau khi thấy node min thực thì đổi chỗ với min tạm và đánh dấu
// đã sắp (ko xét nữa) Tiếp theo gọi min tạm là node sau dãy đã sắp
// và tìm min thực (trừ node đã sắp)...Lặp đến node thứ 2 từ cuối
// sap xep theo ma
void sel_sort_ma(SV sv[], int n){
for(int i=0;i<n-1;i++){ // xét từ node đầu - node thứ 2 từ cuối
int min = i; // min tạm
for(int j=i+1;j<n;j++) // duyệt từ sau min tạm (và dãy đã sắp) - cuối
if(sv[j].ma<sv[min].ma) // nếu sau < trước (có thể sd hàm (comparator()))
min = j; // min thực
SV tmp = sv[i]; // đổi chỗ min thực (min) và min tạm (i)
sv[i] = sv[min];
sv[min] = tmp;
}
}
// sap xep theo ten
void sel_sort_ten(SV sv[], int n){
int min;
for(int i=0;i<n-1;i++){
min = i;
for(int j=i+1;j<n;j++){
if(strcmp(sv[j].ten, sv[min].ten)<0)
min = j;
SV tmp = sv[i];
sv[i] = sv[min];
sv[min] = tmp;
}
}
}
//Interchange sort
// sap xep theo ma
void inter_sort_ma(SV sv[], int n){
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
if(sv[j].ma>sv[i].ma){
SV tmp = sv[j];
sv[j] = sv[i];
sv[i] = tmp;
}
}
}
}
// sap xep theo ten
void inter_sort_ten(SV sv[], int n){
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
if(strcmp(sv[j].ten, sv[i].ten)>0){
SV tmp = sv[j];
sv[j] = sv[i];
sv[i] = tmp;
}
}
}
}
// Insertion sort (chèn): coi nút đầu đã sắp, xét từ node 2 để tìm
// (chèn vào) vị trí mới (đổi chỗ 2 nút kề (1 nút key, 1 nút vị trí
// -trước key) đến khi tới chỗ phù hơp) và đánh dấu (ko xét nữa)
// sap xep theo ma
void inser_sort_ma(SV sv[], int n){
SV key;
int j;
for(int i=1;i<n;i++){ // xét từ node 2 - node thứ 2 từ cuối
key = sv[i]; // nút cần tìm chỗ mới
j = i-1; // chỗ mới: từ trước node key -> vị trí đầu (j>=0)
while(j>=0 && sv[j].ma>key.ma){
sv[j+1] = sv[j]; //nếu trước (j)>sau (key = j+1): đổi chỗ 2 nút kề // tịnh tiến gia trị:
gán sau = trước
j--; // đi lùi // j là chỗ trước vị trí cần thêm
}
sv[j+1] = key; // vị trí của key
}
}
// sap xep theo ten
void inser_sort_ten(SV sv[], int n){
SV key;
int j;
for(int i=1;i<n;i++){
key = sv[i];
j = i-1;
while(j>=0 && strcmp(sv[j].ten, key.ten)>0){
sv[j+1] = sv[j];
j--;
}
sv[j+1] = key;
}
}
// Buble sort: đổi chỗ 2 nút kề (1-2, 2-3, 3-4...), nhỏ hơn lên trước (nổi lên),
// nút lớn nhất sẽ xuống cuối (mark), tiếp tục về đầu và đổi chỗ 2 nút kề
// sap xep theo ma
void bub_sort_ma(SV sv[], int n){
for(int i=0;i<n-1;i++){ // số lần so sánh (-1 vì phần tử cuối tự sắp)
for(int j=0;j<n-1-i;j++){ // xét từ đầu - pt trước dãy đã sắp
if(sv[j+1].ma<sv[j].ma){ // nếu sau < trước: đổi chỗ 2 nút kề
SV tmp = sv[j];
sv[j] = sv[j+1];
sv[j+1] = tmp;
}
}
}
}
// sap xep theo ten
void bub_sort_ten(SV sv[], int n){
for(int i=0;i<n-1;i++){
for(int j=0;j<n-1-i;j++){
if(strcmp(sv[j+1].ten, sv[i].ten)<0){
SV tmp = sv[j];
sv[j] = sv[i];
sv[i] = tmp;
}
}
}
}
// Quick sort
// Chọn pivot: đầu / random / avg của 3
// sap xep theo ma
int partition_ma(SV sv[], int low, int high){ // Phân hoạch
int pivot = sv[high].ma; //pivot
int i = (low-1); // chỉ số pt nhỏ hơn và chỉ ra pt bên phải pivot gần nhất
for(int j=low;j<high;j++){
if(sv[j].ma <= pivot){ // nếu pt hiện tại < pivot // giam dan: sv[j].ma >= pivot
i++;
SV tmp = sv[i];
sv[i] = sv[j];
sv[j] = tmp;
}
}
SV tmp = sv[i+1];
sv[i+1] = sv[high];
sv[high] = tmp;
return i+1;
}
void qu_sort_ma(SV sv[], int low, int high){// mảng cần sx, điểm đầu, điểm cuối
if(low<high){
int pi = partition_ma(sv, low, high); //pi is partitioning index, arr[p] is now at right
place
qu_sort_ma(sv, low, pi-1); // Separately sort elements before partition and after
partition
qu_sort_ma(sv, pi+1, high);
}
}
// sap xep theo ten
int partition_ten(SV sv[], int low, int high){
char *pivot = sv[high].ten;
int i = (low-1);
for(int j=low;j<=high-1;j++){
if(sv[j].ten <= pivot){
i++;
SV tmp = sv[i];
sv[i] = sv[j];
sv[j] = tmp;
}
}
SV tmp = sv[i+1];
sv[i+1] = sv[high];
sv[high] = tmp;
return i+1;
}
void qu_sort_ten(SV sv[], int low, int high){
if(low<high){
int pi = partition_ten(sv, low, high);
qu_sort_ma(sv, low, pi-1);
qu_sort_ma(sv, pi+1, high);
}
}
// Heap sort
// sap xep theo ma
void heapify_ma(SV sv[], int n, int i){
int largest = i;
int l = 2*i+1; // left
int r = 2*i+2; // right
// neu nhanh trai > goc
if(l<n && sv[l].ma>sv[largest].ma){
largest = l;
}
// neu nhanh phai > goc
if(r<n && sv[r].ma>sv[largest].ma){
largest = r;
}
//neu phan tu lon nhat khong phai goc
if(largest!=i){
SV tmp = sv[i];
sv[i] = sv[largest];
sv[largest] = tmp;
heapify_ma(sv, n, largest);
}
}
void heap_sort_ma(SV sv[], int n){
for(int i=n/2-1;i>=0;i--){
heapify_ma(sv, n, i);
}
for(int i=n-1;i>=0;i--){
SV tmp = sv[i];
sv[i] = sv[0];
sv[0] = tmp;
heapify_ma(sv, i, 0);
}
}
// sap xep theo ten
void heapify_ten(SV sv[], int n, int i){
int largest = i;
int l = 2*i+1;
int r = 2*i+2;
if(l<n && strcmp(sv[l].ten, sv[largest].ten)>0){
largest = l;
}
if(r<n && strcmp(sv[r].ten, sv[largest].ten)>0){
largest = r;
}
if(largest!=i){
SV tmp = sv[i];
sv[i] = sv[largest];
sv[largest] = tmp;
heapify_ten(sv, n, largest);
}
}
void heap_sort_ten(SV sv[], int n){
for(int i=n/2-1;i>=0;i--){
heapify_ten(sv, n, i);
}
for(int i=n-1;i>=0;i--){
SV tmp = sv[i];
sv[i] = sv[0];
sv[0] = tmp;
heapify_ten(sv, i, 0);
}
}
// Merge sort (ko học)
void merge(SV arr[], int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
SV L[n1], R[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2) {
if (L[i].ma <= R[j].ma) { //*****KHOA CAN SAP XEP*****//
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there are any */
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there are any */
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
// l is for left index and r is right index of the sub-array of arr to be sorted
void MergeSort(SV arr[], int l, int r) {
if (l < r) {
// Same as (l+r)/2, but avoids overflow for large l and h
int m = l + (r - l) / 2;
// Sort first and second halves
MergeSort(arr, l, m);
MergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
int main(){
int n = 6;
SV sv[6] = {{"abc", 22, 9.6}, {"adf", 33, 2.5}, {"bbb", 55, 6.5}, {"bba", 88, 6.5}, {"adj",
44, 8}, {"ads", 11, 8.7}};
//scanf("%d", &n); //số sv
//nhap(sv, n);
in(sv, n);
LinearS_sv(sv, n, 22);
LinearS_sv1(sv, n, 33);

printf("\nDanh sách sắp xếp \n");


sel_sort_ma(sv, n);
//inser_sort_ma(sv, n);
//inter_sort_ma(sv, n);
//bub_sort_ma(sv,n);
//qu_sort_ma(sv, 0, n-1);
//heap_sort_ma(sv, n);
//MergeSort(sv, 0, n-1);
//qsort(sv, n, sizeof(SV), comparator); // hàm có sẵn (ko sd)
in(sv, n); //Xuat(&SV[i]);

LinearS_ten(sv, n, "bbb");
binaryS_sv(sv, n, 88);
}

Cây nhị phân (BST)


Cây số nguyên
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
int infor; // dữ liệu
struct node *left, *right;
} node;
// Khởi tạo nút mới
node* newNode(int data) {
node* newnode = (node*)malloc(sizeof(node)); // cấp phát bộ nhớ cho node mới
newnode->infor = data; // gán dữ liệu
newnode->left = newnode->right = NULL; // khởi tạo lk trái+phải
return(newnode);
}
typedef struct node *BST;
// Khởi tạo cây rỗng
void initBST(BST *T){
*T = NULL;
}
// Duyệt cây:
void NLR(node *node) { // gốc trái phải
if (node == NULL) return;
printf("%d ", node->infor);
NLR(node->left);
NLR(node->right);
}
void LNR(node* node) { // trái gốc phải
if (node == NULL) return;
LNR(node->left);
printf("%d ", node->infor);
LNR(node->right);
}
void LRN(node* node) { // trái phải gốc
if (node == NULL) return;
LRN(node->left);
LRN(node->right);
printf("%d ", node->infor);
}
//Thêm nút mới vào cây tìm kiếm nhị phân (BST)
node* insert(node* node, int key) {
if (node == NULL) return newNode(key); // nếu cây rỗng: nút mới là gốc
if (key < node->infor) //nếu giá trị node mới < giá trị gốc: thêm vào trái
node->left = insert(node->left, key); //đệ quy: lặp đến khi gặp NULL
else if (key > node->infor) //nếu giá trị node mới < giá trị gốc: thêm vào phải
node->right = insert(node->right, key);
return node;
}
node* Create_Tree() {
node* root = NULL;
int x;
do {
printf("Nhap nut: "); scanf("%d",&x);
if (x!=0) root = insert(root, x); // hoặc nếu input là BST insert(&root, x);
} while(x!=0);
return root;
}
// Tìm node có giá trị min cây (BST ko rỗng) = Tìm lá trái nhất
node* minValueNode(node* root){
node* current = root;
while (current && current->left != NULL)
current = current->left;
return current;
}
/* Xóa node (BST) theo giá trị key, trả về nút gốc (root) mới */
node* deleteNode(node* root, int key){
if (root == NULL) return root;
if (key < root->infor) root->left = deleteNode(root->left, key);
else if (key > root->infor) root->right = deleteNode(root->right, key);
else {
if (root->left == NULL) {
node* temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL) {
node* temp = root->left;
free(root);
return temp;
}
node* temp = minValueNode(root->right);
root->infor = temp->infor;
root->right = deleteNode(root->right, temp->infor);
}
return root;
}
// Tìm kiếm khóa
node* search(node* root, int key) {
if (root == NULL || root->infor == key) return root;
if (root->infor < key) // TH Khóa > gốc: tìm nhánh phải
return search(root->right, key);
return search(root->left, key); // TH Khóa < gốc: tìm nhánh trái
}
// Tìm nút cha
void findParent(node* node, int val, int parent) {
if (node == NULL) return;
if (node->infor == val) printf("%d", parent);
else {
findParent(node->left, val, node->infor);
findParent(node->right, val, node->infor);
}
}
//Tìm và trả về nút cha
node* par(node *root, int x) {
if (root == NULL || root->left->infor == x || root->right->infor == x) return root;
node *parent = par(root->left, x);
if (parent != NULL) return parent;
return par(root->right, x);
}

node* get_sibling(node *node, int key) {


if (node == NULL || node->infor == key) return NULL;
if (node->left->infor == key) return node->right;
if (node->right->infor == key) return node->left;
struct node *temp = get_sibling(node->left, key);
if (temp != NULL) return temp;
temp = get_sibling(node->right, key);
return temp;
}
// Số nút của cây nhị phân trong khoảng [low, high] (chưa hiểu)
int getCount(node *root, int low, int high){
if (!root) return 0; // TH cơ sở
if (root->infor == high && root->infor == low) return 1;
if (root->infor <= high && root->infor >= low) return 1 + getCount(root->left, low,
high) + getCount(root->right, low, high);
else if (root->infor < low) return getCount(root->right, low, high);
else return getCount(root->left, low, high);
}
int main() {
//struct node* root = Create_Tree();
node *root = newNode(10);
/* 10
/\
NULL NULL*/
root->left = newNode(7);
root->right = newNode(12);
/* 10
/\
7 12
/\/\
N N N N */
root->left->left = newNode(5);
root->right->right = newNode(14);
/* 10
/\
7 12
/\/\
5 N N 14
/\
N N */
NLR(root); // 10 7 5 12 14
printf("\n");
LNR(root); // 5 7 10 (9) 12 14
printf("\n");
LRN(root); // 5 7 14 12 10
printf("\n");

insert(root, 12); // insert(&root, 12); (input BST)


insert(root, 3);
insert(root, 9);
insert(root, 6);
root->left->right->left = newNode(8);
/* 10
/\
7 12-2
/\ \
5 9 14
/\/
3 6 8 */
NLR(root); // 10 7 5 3 6 9 8 12 12 14
printf("\n");
LNR(root); // 3 5 6 7 8 9 10 12 12 14
printf("\n");
LRN(root); // 3 6 5 8 9 7 14 12 12 10
printf("\n");

int l = 7;
int h = 12;
root = deleteNode(root, 3);
LNR(root); // 5 6 7 8 9 10 12 12 14
printf("\n");
/* 10
/\
7 12-2
/\ \
5 9 14
\ /
6 8 */
root = deleteNode(root, 7);
LNR(root); // 5 6 8 9 10 12 12 14
printf("\n");
/* 10
/\
8 12-2
/\ \
5 9 14
\
6 */
root = deleteNode(root, 10);
insert(root, 15);
LNR(root); // 5 6 8 9 12 12 14 15
printf("\n");
/* 12
/\
8 14
/\ \
5 9 15
\
6 */
if (search(root,5)==NULL) printf("Khong tim thay\n");
else printf("Tim thay\n");

findParent(root, 9, -1); // 8

int child = 9;
node *sibling = get_sibling(root, child);

if (sibling != NULL) printf("\nAnh em của %d là %d", child, sibling->infor); // 14


else printf("\n%d không có anh em", child);
}
Cây sinh viên
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct SV{
char ten[30];
int msv;
float dtb;
} SV;
typedef struct node{
SV infor;
struct node *left, *right;
} node;
node *newNode(char *ten, int msv, float dtb){
node *newnode = (node*)malloc(sizeof(node));
newnode->left = NULL;
newnode->right = NULL;
strcpy(newnode->infor.ten, ten);
newnode->infor.msv = msv;
newnode->infor.dtb = dtb;
return newnode;
}
// Theo msv
node *insert(node *node, char *ten, int msv, float dtb){
if(node == NULL) return newNode(ten, msv, dtb);
if(msv < node->infor.msv) node->left = insert(node->left, ten, msv, dtb);
else if(msv > node->infor.msv) node->right = insert(node->right, ten, msv, dtb);
return node;
}
void NLR(node *node){ //preorder
if(node==NULL) return;
printf("%s %d %.2f\n", node->infor.ten, node->infor.msv, node->infor.dtb);
NLR(node->left);
NLR(node->right);
}
void LNR(node *node){ // inorder
if(node==NULL) return;
LNR(node->left);
printf("%s %d %.2f\n", node->infor.ten, node->infor.msv, node->infor.dtb);
LNR(node->right);
}
void LRN(node *node){ //postorder
if(node==NULL) return;
LRN(node->left);
LRN(node->right);
printf("%s %d %.2f\n", node->infor.ten, node->infor.msv, node->infor.dtb);
}
node *minNode(node *root){
node *current = root;
while(current && current->left!=NULL)
current = current->left;
return current;
}
//Tìm kiếm theo dtb
node *search(node *root, float x){
if(root==NULL || root->infor.dtb == x) return root;
if(x < root->infor.dtb) return search(root->left, x);
return search(root->right, x);
}
// Xóa sv dtb < x
node *del_dtb(node *root, float x){
if(root == NULL) return root;
if(x < root->infor.dtb) root->left = del_dtb(root->left, x);
else if(x > root->infor.dtb) root->right = del_dtb(root->right, x);
else{
if(root->left == NULL){
node *tmp = root->right;
free(root);
return tmp;
}
if(root->right == NULL){
node *tmp = root->left;
free(root);
return tmp;
}
node *tmp = minNode(root->right);
root->infor = tmp->infor;
root->right = del_dtb(root->right, tmp->infor.dtb);
}
return root;
}
node *del_less_dtb(node *root, float x){
while(search(root, x) != NULL){
del_dtb(root, x);
}
return root;
}
// Xóa sv theo mã
node *del_msv(node *root, int x){
if(root == NULL) return root;
if(x < root->infor.msv) root->left = del_msv(root->left, x);
else if(x > root->infor.msv) root->right = del_msv(root->right, x);
else{
if(root->left == NULL){
node *tmp = root->right;
free(root);
return tmp;
}
if(root->right == NULL){
node *tmp = root->left;
free(root);
return tmp;
}
node *tmp = minNode(root->right);
root->infor = tmp->infor;
root->right = del_msv(root->right, tmp->infor.msv);
}
return root;
}
int main(){
node *root = NULL;
root = insert(root, "add", 111, 8.5);
insert(root, "abc", 555, 8.5);
insert(root, "bac", 263, 5);
insert(root, "cca", 101, 8.5);
insert(root, "aaa", 33, 3);
insert(root, "ddd", 177, 4);
insert(root, "ccb", 14, 5);
insert(root, "bbc", 32, 3.5);
NLR(root);
LNR(root);
LRN(root);
}

You might also like