You are on page 1of 59

Mục lục

Contents
THUẬT TOÁN QUICK SORT..............................................................................................1
DANH SÁCH LIÊN KẾT......................................................................................................2
DANH SÁCH LIÊN KẾT ĐƠN............................................................................................2
1. PHẦN 1: VIẾT DANH SÁCH LIÊN KẾT ĐƠN CHỈ QUẢN LÝ BỞI ĐIỂM ĐẦU
TIÊN CỦA DANH SÁCH HEAD.....................................................................................2
2. Hình ảnh danh sách liên kết đơn...................................................................................2
3. Cấu trúc dữ liệu danh sách liên kết đơn........................................................................2
4. Khởi tạo danh sách liên kết đơn...................................................................................3
5. Kiểm tra danh sách liên kết đơn rỗng...........................................................................4
6. Tạo node cho danh sách liên kết đơn............................................................................4
7. Thêm 1 node vào đầu danh sách liên kết đơn...............................................................4
8. Nhập từ bàn phím danh sách liên kết đơn.....................................................................5
9. Duyệt tuần tự danh sách liên kết đơn............................................................................6
10. Chương trình đầu tiên danh sách liên kết đơn...........................................................6
DSLK Đơn: PHẦN 2: VIẾT HÀM CODE DANH SÁCH LIÊN KẾT ĐƠN ĐƯỢC QUẢN
LÝ BỞI ĐIỂM ĐẦU VÀ ĐIỂM CUỐI.................................................................................9
1. Hình ảnh danh sách liên kết đơn...................................................................................9
2. Cấu trúc dữ liệu danh sách liên kết đơn........................................................................9
3. Khởi tạo danh sách liên kết đơn.................................................................................10
4. Kiểm tra danh sách liên kết đơn rỗng.........................................................................10
5. Tạo một node và gán giá trị cho node.........................................................................11
6. Thêm một node vào đầu danh sách liên kết đơn.........................................................12
Thêm một node vào cuối danh sách liên kết đơn..........................................................12
Thêm một node vào vị trí bất kỳ danh sách liên kết đơn..............................................13
7. Nhập từ bàn phím danh sách liên kết đơn...................................................................13
8. Duyệt tuần tự danh sách liên kết đơn..........................................................................15
9. Chương trình đầu tiên danh sách liên kết đơn............................................................16
10. Tìm kiếm một phần tử có khóa x............................................................................18
11. Hủy toàn bộ danh sách............................................................................................18
12. Sắp xếp các node trong danh sách...........................................................................19
13. BÀI TẬP................................................................................................................. 19
14. Bài tập chuẩn..........................................................................................................20

1
Bài tập chuẩn 1: Định nghĩa hàm thêm một node vào cuối danh sách liên kết đơn......20
Bài tập chuẩn 2: Định nghĩa hàm đếm số lượng node trong danh sách liên kết đơn.....20
Bài tập chuẩn 3: Tìm một node có thành phần dữ liệu bằng X trong danh sách liên kết
đơn các số nguyên........................................................................................................20
Bài tập chuẩn 4: Định nghĩa hàm tách node đầu danh sách đơn ra khỏi danh sách......20
Bài tập chuẩn 5: Định nghĩa hàm tính tổng các giá trị chẵn có trong danh sách liên kết
đơn các số nguyên........................................................................................................20
Bài tập chuẩn 6: Định nghĩa hàm tìm node lớn nhất trong danh sách đơn các số thực. 20
Bài tập chuẩn 7: Định nghĩa hàm tìm địa chỉ node kế cuối trong danh sách liên kết đơn
...................................................................................................................................... 20
Bài tập chuẩn 8: Định nghĩa hàm tách node cuối danh sách liên kết đơn ra khỏi danh
sách............................................................................................................................... 20
Bài tập chuẩn 9: Định nghĩa hàm kiểm tra node q có trong danh sách liên kết đơn hay
không............................................................................................................................ 20
Bài tập C10: Định nghĩa hàm tìm địa chỉ của node nằm trước node q có trong danh
sách liên kết đơn...........................................................................................................20
Bài tập C11: Định nghĩa hàm tách node p trong danh sách liên kết đơn ra khỏi danh
sách............................................................................................................................... 20
Bài tập C12: Bài tập chuẩn 12: Định nghĩa hàm thu hồi bộ nhớ đã cấp phát cho toàn bộ
danh sách liên kết đơn..................................................................................................21
Bài tập chuẩn 13:..........................................................................................................21
Bài tập 14:.................................................................................................................... 21
DANH SÁCH LIÊN KẾT ĐƠN VÒNG..............................................................................23
1. Hình ảnh..................................................................................................................... 23
2. Cấu trúc dữ liệu danh sách liên kết đơn vòng.............................................................23
3. Khởi tạo danh sách liên kết đơn vòng........................................................................23
4. Kiểm tra danh sách liên kết đơn vòng rỗng................................................................23
5. Tạo node cho danh sách liên kết đơn vòng.................................................................23
6. Thêm một node vào đầu danh sách liên kết đơn vòng................................................24
7. Nhập từ bàn phím danh sách liên kết đơn vòng..........................................................24
8. Duyệt tuần tự.............................................................................................................. 25
9. Chương trình đầu tiên trên danh sách liên kết đơn vòng............................................26
10. Bài tập..................................................................................................................... 28
DANH SÁCH LIÊN KẾT KÉP............................................................................................29
1. Hình ảnh danh sách liên kết kép.................................................................................29
2. Cấu trúc dữ liệu..........................................................................................................29

2
3. Khởi tạo danh sách liên kết kép..................................................................................29
4. Kiểm tra danh sách liên kết kép rỗng.........................................................................29
5. Tạo node cho danh sách liên kết kép..........................................................................29
6. Thêm 1 node vào danh sách liên kết kép....................................................................30
7. Nhập từ bàn phím danh sách liên kết kép...................................................................30
8. Duyệt tuần tự danh sách liên kết kép..........................................................................31
9. Bài tập đơn giản.........................................................................................................32
10. Bài tập chuẩn..........................................................................................................34
NGĂN XẾP - STACK.........................................................................................................36
1. Nguyên lý hoạt động..................................................................................................36
2. Cấu trúc dữ liệu của ngăn xếp....................................................................................36
3. Khởi tạo ngăn xếp......................................................................................................36
4. Kiểm tra ngăn xếp rỗng..............................................................................................36
5. Kiểm tra ngăn xếp đầy................................................................................................36
6. Thêm một đối tượng vào trong ngăn xếp....................................................................37
7. Lấy một đối tượng ra khỏi ngăn xếp...........................................................................37
8. Ứng dụng.................................................................................................................... 37
Bài toán 1:.................................................................................................................... 37
9. Bài tập........................................................................................................................ 39
Bài 881: Đếm số lượng nút có đúng hai con mà thông tin tại nút đó là số chính phương
...................................................................................................................................... 39
Bài 885: Tính tổng các nút trong cây............................................................................39
HÀNG ĐỢI – QUEUE.........................................................................................................40
1. Nguyên lý hoạt động..................................................................................................40
2. Cấu trúc dữ liệu của hàng đợi.....................................................................................40
3. Khởi tạo hàng đợi.......................................................................................................40
4. Kiểm tra hàng đợi rỗng...............................................................................................40
5. Kiểm tra hàng đợi đầy................................................................................................40
6. Thêm một đối tượng vào trong hàng đợi....................................................................41
7. Lấy một đối tượng ra khỏi hàng đợi...........................................................................41
8. Ứng dụng.................................................................................................................... 41
CÂY NHỊ PHÂN.................................................................................................................42
1. Hình ảnh cây nhị phân................................................................................................42
2. Khái niệm cây nhị phân..............................................................................................42
3. Cấu trúc dữ liệu của cây nhị phân..............................................................................42
3
4. Khởi tạo cây nhị phân.................................................................................................42
5. Tạo node cho cây nhị phân.........................................................................................42
6. Duyệt cây nhị phân.....................................................................................................42
7. Hàm cài đặt duyệt cây................................................................................................43
8. Bài tập........................................................................................................................ 43
CÂY NHỊ PHÂN TÌM KIẾM – BINARY SEARCH TREE – BST.....................................45
1. Hình vẽ....................................................................................................................... 45
2. Khái niệm................................................................................................................... 45
3. Khởi tạo cây nhị phân tìm kiếm.................................................................................45
4. Kiểm tra cây nhị phân tìm kiếm rỗng.........................................................................46
5. Tạo node cho cây nhị phân tìm kiếm..........................................................................46
6. Thêm giá trị vào cây nhị phân tìm kiếm.....................................................................46
7. Nhập cây nhị phân tìm kiếm.......................................................................................48
8. Duyệt cây nhị phân tìm kiếm......................................................................................49
9. Một chương trình đơn giản về cây BST.....................................................................50
10. Bài tập..................................................................................................................... 52
B – Cây................................................................................................................................. 53

4
ĐỀ CƯƠNG CẤU TRÚC DỮ LIỆU – GIẢI THUẬT

THUẬT TOÁN QUICK SORT


Tư tưởng thuật toán Quick Sort

5
DANH SÁCH LIÊN KẾT
 Khái niệm
Danh sách liên kết là tập hợp các phần tử mà giữa chúng có một sự nối kết với nhau thông
qua vùng liên kết của chúng
 Các loại danh sách liên kết:
 Danh sách liên kết đơn
 Danh sách liên kết đôi/kép
 Danh sách liên kết đơn vòng
 Danh sách liên kết kép vòng

DANH SÁCH LIÊN KẾT ĐƠN


1. PHẦN 1: VIẾT DANH SÁCH LIÊN KẾT ĐƠN CHỈ QUẢN LÝ BỞI
ĐIỂM ĐẦU TIÊN CỦA DANH SÁCH HEAD
2. Hình ảnh danh sách liên kết đơn

3. Cấu trúc dữ liệu danh sách liên kết đơn


 Hình vẽ
NODEPTR
NODE

struct node
{
6
KDL info;
struct node* pNext;
};
typedef struct node NODE;
typedef NODE*NODEPTR;
 Ví dụ 1: Khai báo cấu trúc dữ liệu cho danh sách liên kết đơn các số nguyên
struct node
{
int info;
struct node* pNext;
};
typedef struct node NODE;
typedef NODE*NODEPTR;
 Ví dụ 2: Khai báo cấu trúc dữ liệu cho danh sách liên kết đơn các phân số
struct phanso
{
int tu;
int mau;
};
typedef struct phanso PHANSO;
struct node
{
PHANSO info;
struct node* pNext;
};
typedef struct node NODE;
typedef NODE*NODEPTR;
4. Khởi tạo danh sách liên kết đơn
void Init(NODEPTR &ptr)
{

7
ptr = NULL;
}
5. Kiểm tra danh sách liên kết đơn rỗng
int IsEmpty (NODEPTR ptr)
{
if(ptr == NULL)
return 1;
return 0;
}
6. Tạo node cho danh sách liên kết đơn
NODE * GetNode (KDL x)
{
NODE * p = new NODE;
if(p == NULL)
return NULL;
p->info = x;
p->pNext = NULL;
return p;
}
7. Thêm 1 node vào đầu danh sách liên kết đơn
Hình vẽ ptr
p

void AddHead ( NODEPTR &ptr, NODE*p)


{
p->pNext = ptr;
ptr = p;
}

8
8. Nhập từ bàn phím danh sách liên kết đơn
Hàm tổng quát:
void Input (NODEPTR &ptr)
{
NhapN();
Init(ptr);
for (int i=1; i<=n; i++)
{
NhapX();
NODE* p = GetNode(x);
if(p!=NULL)
AddHead(ptr, p);
}
}
Ví dụ: Nhập danh sách liên kết đơn các số nguyên
void Input (NODEPTR &ptr)
{
int n;
printf (“Nhap n:”);
scanf(“%d”, &n);
Init(ptr);
for (int i=1; i<=n; i++)
{
int x;
printf(“Nhap x”);
scanf(“%d”, &x);
NODE* p = GetNode(x);
if(p!=NULL)
AddHead(ptr, p);
}

9
}
9. Duyệt tuần tự danh sách liên kết đơn
Định nghĩa hàm trừu tượng
KDL <Tên hàm> (NODEPTR ptr)
{
….
NODE * p = ptr;
while (p!= NULL)
{
….
p = p -> pNext
}

}
Ví dụ: Định nghĩa hàm tính tổng các số lẻ trong danh sách liên kết đơn các số nguyên
int Tong(NODEPTR ptr)
{
int s = 0;
NODE *p = ptr;
while (p!=NULL)
{
s = s + p->info;
p = p->pNext;
}
return s;
}

10.Chương trình đầu tiên danh sách liên kết đơn


 Bài toán: Viết chương trình thực hiện các yêu cầu sau:
+ Nhập danh sách liên kết đơn các số nguyên
+ Tính tổng các giá trị trong danh sách liên kết đơn
+ Xuất danh sách liên kết đơn
#include <stdio.h>
#include <conio.h>
struct node
{
int info;
struct node* pNext;
};
typedef struct node NODE;
typedef NODE*NODEPTR;
//Khởi tạo danh sách liên kết đơn
void Init(NODEPTR &ptr)
{
ptr = NULL;

10
}
//Tạo node
NODE * GetNode(int x)
{
NODE * p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = NULL;
return p;
}
//Thêm node vào đầu danh sách
void AddHead(NODEPTR &ptr, NODE*p)
{
p->pNext = ptr;
ptr = p;
}
//NHập danh sách liên kết
void Input(NODEPTR &ptr)
{
int n;
printf("Nhap n : ");
scanf_s("%d", &n);
Init(ptr);
for (int i = 1; i <= n; i++)
{
int x;
printf("Nhap x: ");
scanf_s("%d", &x);
NODE* p = GetNode(x);
if (p != NULL)
AddHead(ptr, p);
}
}
//Xuất danh sách liên kết đơn
void Output(NODEPTR ptr)
{
NODE *p = ptr;
while (p != NULL)
{
printf("%4d", p->info);
p = p->pNext;
}
}
//Tính tổng danh sách liên kết đơn các số nguyên
int Tong(NODEPTR ptr)
{
int s = 0;
NODE *p = ptr;
while (p!=NULL)
{

11
s = s + p->info;
p = p->pNext;
}
return s;
}
void main()
{
NODEPTR ds;
Init(ds);
printf("\n==Tao 1 danh sach lien ket==");
Input(ds);
printf("\n==Xuat danh sach lien ket==");
Output(ds);
int s = Tong(ds);
printf("\n==Ket qua ham tinh tong: %d ",s);
_getch();
}

12
DSLK Đơn: PHẦN 2: VIẾT HÀM CODE DANH SÁCH LIÊN KẾT
ĐƠN ĐƯỢC QUẢN LÝ BỞI ĐIỂM ĐẦU VÀ ĐIỂM CUỐI
1. Hình ảnh danh sách liên kết đơn

2. Cấu trúc dữ liệu danh sách liên kết đơn


Hình vẽ

pHead pTail

Khai báo cấu trúc


struct node{
KDL info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;

Ví dụ 1: Hãy khai báo CTDL cho DSLK đơn các số nguyên


struct node{
int info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;

Ví dụ 2: Hãy khai báo CTDL cho DSLK đơn các số thực


struct node{
float info;
struct node *pNext;
};
typedef struct node NODE;
struct list

13
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;

Ví dụ 3: Hãy khai báo CTDL cho DSLK đơn các phân số


struct phanso
{
int tu;
int mau;
};
typedef struct phanso PHANSO;
struct node{
PHANSO info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;

Ví dụ 4: Hãy khai báo CTDL cho DSLK đơn tọa độ các điểm trong mặt phẳng Oxy
struct diem
{
float x;
float y;
};
typedef struct diem DIEM;
struct node{
DIEM info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;

3. Khởi tạo danh sách liên kết đơn


void Init(LIST &ls)
{
ls.pHead = NULL;
ls.pTail = NULL;
}

4. Kiểm tra danh sách liên kết đơn rỗng


int IsEmpty (LIST l)

14
{
if(l.pHead == NULL)
return 1;
return 0;
}
5. Tạo một node và gán giá trị cho node
 Khái niệm: Tạo node cho danh sách liên kết đơn là xin cấp phát bộ nhớ có kích thước
bằng với kích thước của kiểu dữ liệu node để chứa thông tin đã được biết trước.
 Định nghĩa hàm trừu tượng:
NODE* GetNode (KDL x)
{
NODE *p = new NODE;
if(p==NULL)
{
printf("Khong du bo nho!");
return NULL;
}
p->info = x;
p->pNext = NULL;
return p;
}
Ví dụ 1: Định nghĩa hàm tạo node cho danh sách liên kết đơn các số thực
NODE* GetNode(float x)
{
NODE *p = new NODE;
if (p == NULL)
{
printf("Khong du bo nho!");
return NULL;
}
p->info = x;
p->pNext = NULL;
return p;
}

Ví dụ 2: Định nghĩa hàm tạo node cho danh sách liên kết đơn các phân số
NODE* GetNode(PHANSO x)
{
NODE *p = new NODE;
if (p == NULL)
{
printf("Khong du bo nho!");
return NULL;
}
p->info = x;

15
p->pNext = NULL;
return p;
}

Ví dụ 3: Định nghĩa hàm tạo node cho danh sách liên kết đơn các số nguyên
NODE* GetNode(int x)
{
NODE *p = new NODE;
if (p == NULL)
{
printf("Khong du bo nho!");
return NULL;
}
p->info = x;
p->pNext = NULL;
return p;
}

Ví dụ 4: Định nghĩa hàm tạo node cho danh sách liên kết đơn tọa độ các điểm trong mặt
phẳng Oxy
NODE* GetNode(DIEM x)
{
NODE *p = new NODE;
if (p == NULL)
{
printf("Khong du bo nho!");
return NULL;
}
p->info = x;
p->pNext = NULL;
return p;
}

6. Thêm một node vào đầu danh sách liên kết đơn
Khái niệm: Thêm một node vào đầu danh sách liên kết đơn là gắn node đó vào đầu danh
sách.
Hình vẽ

pHead pTail

Định nghĩa hàm:


void AddHead(LIST &ls, NODE*p)
{
if (ls.pHead == NULL)//DS rỗng
{

16
ls.pHead = ls.pTail = p;
}
else
{
p->pNext = ls.pHead;
ls.pHead = p;
}
}

Thêm một node vào cuối danh sách liên kết đơn
 Trường hợp 1: Nếu danh sách liên kết đơn rỗng thì node mới được xem là node đầu
tiên và cũng là node cuối cùng.
 Trường hợp 2: Nếu danh sách liên kết đơn không rỗng thì:
+ Cho con trỏ liên kết (next) của node cuối danh sách hiện tại trỏ đến node mới.
+ Cho con trỏ cuối của danh sách liên kết đơn (*tail) trỏ vào node mới.
void AddTail(LIST &ls, NODE*p)
{
if (ls.pHead == NULL)//DS rỗng
{
ls.pHead = ls.pTail = p;
}
else
{
ls.pTail->pNext = p;
ls.pTail = p;
}
}

Thêm một node vào vị trí bất kỳ danh sách liên kết đơn
Thêm vào sau nút q trong danh sách
 Thêm một node p vào sau một node q trong danh sách
+ Cho con trỏ liên kết (next) của node p chỉ vào node sau của q.
+ Cho con trỏ liên kết của q chỉ vào node p.
+ Nếu q là nút cuối thì gán lại p là nút cuối.

void AddAfter(LIST &l, NODE*q, NODE*new_node)


{
if (q != NULL)
{
new_node->pNext = q->pNext;
q->pNext = new_node;

17
if (q == l.pTail)
{
l.pTail = new_node;
}
}
}

7. Nhập từ bàn phím danh sách liên kết đơn


 Khái niệm: Nhập từ bàn phím danh sách liên kết đơn là lần lượt nhập các thông tin của
từng node trong danh sách
 Định nghĩa hàm trừu tượng

void Input (LIST &l)


{
int n;
printf(“Nhap n”);
scanf(“%d”, &n);
Init(l);
for (int i=1; i<=n; i++)
{
KDL x;
Nhap(x);
NODE* p = GetNode(x);
if(p!=NULL)
AddHead(l, p);
}
}
 Ví dụ 1: Nhập danh sách liên kết đơn các số nguyên
struct node{
int info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;
void Init(LIST &l)
{

18
l.pHead = NULL;
l.pTail = NULL;
}
NODE* GetNode(int x)
{
NODE *p = new NODE;
if (p == NULL)
{
printf("Khong du bo nho!");
return NULL;
}
p->info = x;
p->pNext = NULL;
return p;
}
void AddHead(LIST &ls, NODE*p)
{
if (ls.pHead == NULL)//DS rỗng
{
ls.pHead = ls.pTail = p;
}
else
{
p->pNext = ls.pHead;
ls.pHead = p;
}
}
void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
int x;
printf("Nhap so nguyen:");
scanf_s("%d", &x);
NODE *p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}

 Ví dụ 2: Nhập danh sách liên kết đơn các số thực


 Ví dụ 3: Nhập danh sách liên kết đơn các phân số
 Ví dụ 4: Nhập danh sách liên kết đơn tọa độ các điểm trong mặt phẳng Oxy.

8. Duyệt tuần tự danh sách liên kết đơn


 Khái niệm: Duyệt tuần tự danh sách liên kết đơn là thăm qua tất cả các node trong danh
sách mỗi node 1 lần.
 Định nghĩa hàm trừu tượng
KDL <Tên hàm> (LIST l)

19
{
……
NODE *p = l.pHead;
while (p!=NULL)
{
……
p = p -> pNext;
}
……
}
 Ví dụ 1: Định nghĩa hàm tính tổng các số lẻ trong danh sách liên kết đơn các số nguyên
struct node{
int info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;
int TongLe(LIST l)
{
int s = 0;
NODE *p = l.pHead;
while (p!=NULL)
{
if (p->info % 2 != 0)
s = s + p->info;
p = p->pNext;
}
return s;
}

 Ví dụ 2: Định nghĩa hàm xuất danh sách liên kết đơn các số nguyên
void Xuat(LIST l)
{
NODE *p = l.pHead;
while (p != NULL)
{
printf("%4d", p->info);
p = p->pNext;
}
}

20
9. Chương trình đầu tiên danh sách liên kết đơn
Bài toán:
 Viết chương trình thực hiện các yêu cầu sau:
+ Nhập danh sách liên kết đơn các số nguyên
+ Tính tổng các giá trị trong danh sách liên kết đơn
+ Xuất danh sách liên kết đơn
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <string.h>
struct node{
int info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;
void Init(LIST &l)
{
l.pHead = NULL;
l.pTail = NULL;
}
NODE* GetNode(int x)
{
NODE *p = new NODE;
if (p == NULL)
{
printf("Khong du bo nho!");
return NULL;
}
p->info = x;
p->pNext = NULL;
return p;
}
void AddHead(LIST &ls, NODE*p)
{
if (ls.pHead == NULL)//DS rỗng
{
ls.pHead = ls.pTail = p;
}
else
{
p->pNext = ls.pHead;
ls.pHead = p;
}
}
void Input(LIST &l)
{
int n;

21
printf("Nhap n:");
scanf_s("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
int x;
printf("Nhap so nguyen:");
scanf_s("%d", &x);
NODE *p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}

}
void Output(LIST l)
{
NODE *p = l.pHead;
while (p != NULL)
{
printf("%4d", p->info);
p = p->pNext;
}
}
int Tong(LIST l)
{
int s = 0;
NODE *p = l.pHead;
while (p != NULL)
{
s = s + p->info;
p = p->pNext;
}
return s;
}
void main()
{
LIST l;
Input(l);
Output(l);
int kq = Tong(l);
printf("\n Tong : %4d", kq);
_getch();
}

10.Tìm kiếm một phần tử có khóa x


NODE *Search(LIST l, int x)
{
NODE *p = l.pHead;
while (p!=NULL)
{
if (p->info == x)
return p;
p = p->pNext;
}
return NULL;

22
}

11.Hủy toàn bộ danh sách


Sử dụng lệnh delete để giải phóng bộ nhớ lưu trữ các node trong danh sách.
void deleteList(List &l)
{
NODE *p;
while (l.head!= NULL){
p = l.head;
l.head = p->next;
delete p;
}
l.tail = NULL;
}
12.Sắp xếp các node trong danh sách
Sử dụng thuật toán sắp xếp chọn trực tiếp (Selection Sort) để sắp xếp danh sách liên kết
đơn.
void List_Selection_Sort(List &l){
NODE *min;
NODE *p, *q;
p = l.head;
while(p != l.tail){
min = p; q = p->next;
while(q != NULL){
if(q->info < min->info){
min = q;
}
q= q->pNext;
}
swap(min->info, p->info);
p = p->pNext;
}
23
}
13.BÀI TẬP
 Viết chương trình thực hiện các yêu cầu sau:
+ Nhập danh sách liên kết đơn các số thực
+ Xuất danh sách liên kết đơn
+ Đếm số lượng giá trị âm trong danh sách liên kết đơn
+ Tìm địa chỉ node lớn nhất trong danh sách liên kết đơn
+ Tìm vị trí có giá trị lớn nhất trong danh sách liên kết đơn
 Viết chương trình sắp xếp các phân số dương tăng dần trong danh sách liên kết đơn
các phân số
 Viết chương trình hàm tách danh sách liên kết l thành danh sách liên kết l1 và danh
sách liên kết l2. Trong đó l1 chứa giá trị chẵn và l2 chứa giá trị lẻ.
14.Bài tập chuẩn
Bài tập chuẩn 1: Định nghĩa hàm thêm một node vào cuối danh sách liên kết đơn
Bài tập chuẩn 2: Định nghĩa hàm đếm số lượng node trong danh sách liên kết đơn
Bài tập chuẩn 3: Tìm một node có thành phần dữ liệu bằng X trong danh sách liên kết đơn
các số nguyên
Bài tập chuẩn 4: Định nghĩa hàm tách node đầu danh sách đơn ra khỏi danh sách
Bài tập chuẩn 5: Định nghĩa hàm tính tổng các giá trị chẵn có trong danh sách liên kết đơn
các số nguyên.
Bài tập chuẩn 6: Định nghĩa hàm tìm node lớn nhất trong danh sách đơn các số thực
Bài tập chuẩn 7: Định nghĩa hàm tìm địa chỉ node kế cuối trong danh sách liên kết đơn
Bài tập chuẩn 8: Định nghĩa hàm tách node cuối danh sách liên kết đơn ra khỏi danh sách
Bài tập chuẩn 9: Định nghĩa hàm kiểm tra node q có trong danh sách liên kết đơn hay không
Bài tập C10: Định nghĩa hàm tìm địa chỉ của node nằm trước node q có trong danh sách liên
kết đơn.
struct node
{
int info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;
NODE* Before(LIST l, NODE*q)
{
if (l.pHead == NULL)
return NULL;
if (l.pHead == q)
return NULL;
NODE *lc = l.pHead;
while (lc && lc->pNext != q)

24
{
lc = lc->pNext;
}
return lc;
}

Bài tập C11: Định nghĩa hàm tách node p trong danh sách liên kết đơn ra khỏi danh sách

Bài tập C12: Bài tập chuẩn 12: Định nghĩa hàm thu hồi bộ nhớ đã cấp phát cho toàn bộ danh
sách liên kết đơn
struct node{
int info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;
NODE *GetHead(LIST &l)
{
if (l.pHead == NULL)
return NULL;
if (l.pHead == l.pTail)
{
NODE*p = l.pHead;
l.pHead = l.pTail = NULL;
return p;
}
NODE *p = l.pHead;
l.pHead = l.pHead->pNext;
p->pNext = NULL;
return p;
}
void RemoveAll(LIST &l)
{
while (l.pHead)
{
NODE*p = GetHead(l);
delete p;
}
}

Bài tập chuẩn 13:


Định nghĩa hàm tách danh sách liên kết l thành danh sách liên kết l1 và danh sách liên kết
l2. Trong đó l1 chứa giá trị chẵn và l2 chứa giá trị lẻ.

25
Bài tập 14:

Hãy viết chương trình với C/C++ để thao tác với danh sách liên kết đơn ở trên:
a. Tạo danh sách liên kết đơn như hình minh họa.
b. Thêm một node có giá trị là 9 vào đầu danh sách.
c. Xuất giá trị và địa chỉ của các node trong danh sách lên màn hình.
d. Sắp xếp danh sách theo thứ tự tăng dần các giá trị của các node.
e. Giải phóng bộ nhớ cho toàn bộ danh sách.

26
DANH SÁCH LIÊN KẾT ĐƠN VÒNG
1. Hình ảnh

pHead pTail

2. Cấu trúc dữ liệu danh sách liên kết đơn vòng


Khai báo cấu trúc dữ liệu
struct node
{
KDL info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;
3. Khởi tạo danh sách liên kết đơn vòng
void Init(LIST &ls)
{
ls.pHead = NULL;
ls.pTail = NULL;
}

4. Kiểm tra danh sách liên kết đơn vòng rỗng


int IsEmpty (LIST l)
{
if(l.pHead==NULL)

27
return 1;
return 0;
}
5. Tạo node cho danh sách liên kết đơn vòng
NODE * GetNode(KDL x)
{
NODE * p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = p;
return p;
}
 Ví dụ 1: Định nghĩa hàm tạo node cho danh sách liên kết đơn vòng các số thực
NODE * GetNode(floaf x)
{
NODE * p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = p;
return p;
}

 Ví dụ 2: Định nghĩa hàm tạo node cho danh sách liên kết đơn vòng các phân số
NODE * GetNode(PHANSO x)
{
NODE * p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = p;
return p;
}
6. Thêm một node vào đầu danh sách liên kết đơn vòng
void AddHead(LIST &l, NODE*p)
{
if (l.pHead == NULL)
l.pHead = l.pTail = p;
else
{
p->pNext = l.pHead;
l.pTail->pNext = p;
l.pHead = p;
}
}

28
7. Nhập từ bàn phím danh sách liên kết đơn vòng
void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
KDL x;
Nhap(x);
NODE *p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}
}

 Ví dụ 1: Nhập danh sách liên kết đơn vòng các số nguyên


void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
int x;
printf("Nhap x:");
scanf("%d", &x);
NODE *p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}
}

 Ví dụ 2: Nhập danh sách liên kết đơn vòng các số thực


void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
float x;
printf("Nhap x:");
scanf("%f", &x);
NODE *p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}
}

29
8. Duyệt tuần tự
KDL <Tên hàm> (LIST l)
{
if(l.pHead==NULL)
return…;
….
NODE *p= l.pHead;
do{
….
p = p ->pNext;
}while (p != l.pHead)

}
 Định nghĩa hàm tính tổng các số lẻ trong danh sách liên kết đơn vòng các số thực
float TongLe(LIST l)
{
if (l.pHead == NULL)
return 0;
float s = 0;
NODE *p = l.pHead;
do{
if (p->info % 2 != 0)
s = s + p->info;
p = p->pNext;
} while (p != l.pHead);
return s;
}

 Định nghĩa hàm xuất danh sách liên kết đơn vòng các số nguyên.
void Output(LIST l)
{
if (l.pHead == NULL)
return;
NODE *p = l.pHead;
do{
printf("%4d", p->info);
p = p->pNext;
} while (p != l.pHead);
}

9. Chương trình đầu tiên trên danh sách liên kết đơn vòng
 Bài toán: Viết chương trình thực hiện các yêu cầu sau:

30
+ Nhập danh sách liên kết đơn vòng các số nguyên
+ Tính tổng lẻ các giá trị trong danh sách liên kết đơn vòng
+ Xuất danh sách liên kết đơn vòng
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <string.h>
struct node
{
int info;
struct node *pNext;
};
typedef struct node NODE;
struct list
{
NODE *pHead;
NODE *pTail;
};
typedef struct list LIST;
void Init(LIST &l)
{
l.pHead = NULL;
l.pTail = NULL;
}
NODE *GetNode(int x)
{
NODE *p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = p;
return p;
}
void AddHead(LIST &l, NODE*p)
{
if (l.pHead == NULL)
l.pHead = l.pTail = p;
else
{
p->pNext = l.pHead;
l.pTail->pNext = p;
l.pHead = p;
}
}
void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
int x;
printf("Nhap x:");
scanf_s("%d", &x);

31
NODE *p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}
}
void Output(LIST l)
{
if (l.pHead == NULL)
return;
NODE *p = l.pHead;
do{
printf("%4d", p->info);
p = p->pNext;
} while (p != l.pHead);
}
int TongLe(LIST l)
{
if (l.pHead == NULL)
return 0;
int s = 0;
NODE *p = l.pHead;
do{
if (p->info % 2 != 0)
s = s + p->info;
p = p->pNext;
} while (p != l.pHead);
return s;
}
void main()
{
LIST l;
Init(l);
Input(l);
Output(l);
int kq = TongLe(l);
printf("\n Tong : %4d", kq);
_getch();
}

10. Bài tập

32
DANH SÁCH LIÊN KẾT KÉP
1. Hình ảnh danh sách liên kết kép

2. Cấu trúc dữ liệu

LIST
pHead pTail
NODE

struct node
{
KDL info;
struct node*pNext;
struct node *pPrev;
};
typedef struct node NODE;
struct list
{
NODE*pHead;
NODE*pTail;
};
typedef struct list LIST;

Ví dụ: Hãy khai báo cấu trúc dữ liệu cho danh sách liên kết kép các số nguyên
struct node
{
int info;
struct node*pNext;
struct node *pPrev;
};
typedef struct node NODE;
struct list
{
NODE*pHead;
NODE*pTail;
};
typedef struct list LIST;

Ví dụ: Hãy khai báo cấu trúc dữ liệu cho danh sách liên kết kép các số thực
struct node
{
float info;
struct node*pNext;
struct node *pPrev;

33
};
typedef struct node NODE;
struct list
{
NODE*pHead;
NODE*pTail;
};
typedef struct list LIST;

Ví dụ: Hãy khai báo cấu trúc dữ liệu cho danh sách liên kết kép các số phân số
struct phanso
{
int tu;
int mau;
};
typedef struct phanso PHANSO;

struct node
{
PHANSO info;
struct node*pNext;
struct node *pPrev;
};
typedef struct node NODE;
struct list
{
NODE*pHead;
NODE*pTail;
};
typedef struct list LIST;

Ví dụ: Hãy khai báo cấu trúc dữ liệu cho danh sách liên kết kép tọa độ các điểm trong mặt
phẳng Oxy
struct diem
{
float x;
float y;
};
typedef struct diem DIEM;

struct node
{
DIEM info;
struct node*pNext;
struct node *pPrev;
};
typedef struct node NODE;
struct list
{
NODE*pHead;
NODE*pTail;
};
typedef struct list LIST;

34
3. Khởi tạo danh sách liên kết kép
void Init(LIST &l)
{
l.pHead = NULL;
l.pTail = NULL;
}

4. Kiểm tra danh sách liên kết kép rỗng


int IsEmpty(LIST l)
{
if (l.pHead == NULL)
return 1;
return 0;
}

5. Tạo node cho danh sách liên kết kép


NODE*GetNode(KDL x)
{
NODE*p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = NULL;
p->pPrev = NULL;
return p;
}

Ví dụ: Hãy định nghĩa hàm tạo 1 node cho danh sách liên kết kép các số thực
NODE*GetNode(float x)
{
NODE*p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = NULL;
p->pPrev = NULL;
return p;
}

Ví dụ: Hãy định nghĩa hàm tạo 1 node cho danh sách liên kết kép các phân số
NODE*GetNode(PHANSO x)
{
NODE*p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = NULL;
p->pPrev = NULL;
return p;
}

35
6. Thêm 1 node vào danh sách liên kết kép

l
pHead pTail
p

void AddHead(LIST &l, NODE*p)


{
if (l.pHead == NULL)
l.pHead = l.pTail = p;
else
{
p->pNext = l.pHead;
l.pHead ->pPrev = p;
l.pHead = p;
}
}

7. Nhập từ bàn phím danh sách liên kết kép


void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
KDL x;
Nhap(x);
NODE*p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}
}

 Ví dụ: Nhập danh sách liên kết kép các số nguyên


void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
int x;
printf("Nhap x:");
scanf_s("%d", &x);
NODE*p = GetNode(x);

36
if (p != NULL)
AddHead(l, p);
}
}

 Ví dụ 2: Nhập danh sách liên kết kép các số thực


void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
float x;
printf("Nhap x:");
scanf_s("%f", &x);
NODE*p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}
}

8. Duyệt tuần tự danh sách liên kết kép


KDL <Tên hàm> (LIST l)
{
……
NODE *p = l.pHead;
while (p!=NULL)
{
……
p = p -> pNext;
}
……
}
 Cách khác:
KDL <Tên hàm> (LIST l)
{
……
NODE *p = l.pTail;
while (p!=NULL)
{
……
p = p -> pPrev;
}
……

37
}
 Ví dụ 1: Tính tổng các số lẻ trong danh sách liên kết kép các số nguyên
int TongLe(LIST l)
{
int s = 0;
NODE *p = l.pHead;
while (p!=NULL)
{
if (p->info % 2 != 0)
s = s + p->info;
p = p->pNext;
}
return s;
}

 Ví dụ 2: Định nghĩa hàm xuất danh sách liên kết kép các số nguyên ra màn hình
void Xuat(LIST l)
{
NODE *p = l.pHead;
while (p != NULL)
{
printf("%4d", p->info);
p = p->pNext;
}
}

9. Bài tập đơn giản


Bài 1:
 Bài toán: Viết chương trình thực hiện các yêu cầu sau:
+ Nhập danh sách liên kết kép các số nguyên
+ Tính tổng các giá trị trong danh sách liên kết kép
+ Xuất danh sách liên kết kép
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <string.h>
struct node
{
int info;
struct node*pNext;
struct node *pPrev;
};
typedef struct node NODE;
struct list
{
NODE*pHead;
NODE*pTail;
};
typedef struct list LIST;

void Init(LIST &l)

38
{
l.pHead = NULL;
l.pTail = NULL;
}
int IsEmpty(LIST l)
{
if (l.pHead == NULL)
return 1;
return 0;
}
NODE*GetNode(int x)
{
NODE*p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pNext = NULL;
p->pPrev = NULL;
return p;
}
void AddHead(LIST &l, NODE*p)
{
if (l.pHead == NULL)
l.pHead = l.pTail = p;
else
{
p->pNext = l.pHead;
l.pHead->pPrev = p;
l.pHead = p;
}
}
void Input(LIST &l)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(l);
for (int i = 1; i <= n; i++)
{
int x;
printf("Nhap x:");
scanf_s("%d", &x);
NODE*p = GetNode(x);
if (p != NULL)
AddHead(l, p);
}
}
void Output(LIST l)
{
NODE*p = l.pHead;
while (p!=NULL)
{
printf("%4d", p->info);
p = p->pNext;
}
}

39
int Tong(LIST l)
{
int s = 0;
NODE *p = l.pHead;
while (p!=NULL)
{
s = s + p->info;
p = p->pNext;
}
return s;
}
void main()
{
LIST ls;
Init(ls);
Input(ls);
Output(ls);
int s1 = Tong(ls);
printf("\nTong gia tri danh sach %4d", s1);
_getch();
}

10.Bài tập chuẩn


Bài tập chuẩn 1: Định nghĩa hàm thêm một node vào cuối danh sách liên kết kép
Bài tập chuẩn 2: Định nghĩa hàm đếm số lượng node trong danh sách liên kết kép
Bài tập chuẩn 3: Tìm một node có thành phần dữ liệu bằng X trong danh sách liên kết kép
các số nguyên
Bài tập chuẩn 4: Định nghĩa hàm tách node đầu danh sách liên kết kép ra khỏi danh sách
Bài tập chuẩn 5: Định nghĩa hàm tính tổng các giá trị chẵn trong danh sách liên kết kép các
số nguyên
Bài tập chuẩn 6: Định nghĩa hàm tìm node lớn nhất trong danh sách liên kết kép các số thực.
Bài tập chuẩn 7: Định nghĩa hàm tìm địa chỉ node kế cuối trong danh sách liên kết kép
Bài tập chuẩn 8: Định nghĩa hàm tách node cuối danh sách liên kết kép ra khỏi danh sách.
Bài tập chuẩn 9: Định nghĩa hàm kiểm tra node q có trong danh sách liên kết kép hay
không.
Bài tập chuẩn 10: Định nghĩa hàm tìm địa chỉ của node nằm trước node q có trong danh
sách liên kết kép.
Bài tập chuẩn 11: Định nghĩa hàm tách node q trong danh sách liên kết kép ra khỏi danh
sách.
Bài tập chuẩn 12: Định nghĩa hàm thu hồi bộ nhớ đã cấp phát cho toàn bộ nhớ danh sách
liên kết kép.
Bài tập chuẩn 13: Định nghĩa hàm tách danh sách liên kết kép l thành danh sách liên kết l1
và danh sách liên kết l2. Trong đó l1 chứa giá trị chẵn và l2 chứa giá trị lẻ.

40
41
NGĂN XẾP - STACK
1. Nguyên lý hoạt động
Cấu trúc dữ liệu ngăn xếp hoạt động theo nguyên lý vào sau, ra trước (LIFO – Last In –
First Out)
2. Cấu trúc dữ liệu của ngăn xếp
struct stack
{
int n;
KDL a[100];
};
typedef struct stack STACK;
KDL là kiểu dữ liệu của đối tượng được lưu trong stack.
3. Khởi tạo ngăn xếp
void Init(STACK &st)
{
st.n=0;
}
4. Kiểm tra ngăn xếp rỗng
int IsEmpty (STACK st)
{
if(st.n==0)
return 1;
return 0;
}
5. Kiểm tra ngăn xếp đầy
int IsFull (STACK st)
{
if(st.n==100)
return 1;
return 0;

42
}
6. Thêm một đối tượng vào trong ngăn xếp
Hình vẽ minh họa

0 1 …. st.n-1
st.a

st.n
Định nghĩa hàm
void Push (STACK &st, KDL x)
{
st.a[st.n]=x;
st.n++;
}
7. Lấy một đối tượng ra khỏi ngăn xếp
Hình vẽ minh họa

Định nghĩa hàm


KDL Pop(STACK &st)
{
KDL x = st.a[st.n-1];
st.n--;
return x;
}
8. Ứng dụng
Bài toán 1:
 Định nghiã hàm tính tổng các giá trị trong cây nhị phân các số thực bằng hai phương
pháp
+ Đệ quy
+ Khử đệ quy
Bài làm
Các 1: Đệ quy

43
struct node
{
float info;
struct node *pLeft;
struct node *pRight;
};
typedef struct node NODE;
typedef NODE *TREE;
float Tong(TREE t)
{
if(!t)
return 0;
float a=Tong(t->pLeft);
floatb=Tong(t->pRight);
return (a + b + t->info);
}
Cách 2: Khử đệ quy
struct node
{
float info;
struct node *pLeft;
struct node *pRight;
};
typedef struct node NODE;
typedef NODE *TREE;
struct stack
{
int n;
NODE *a[100];
};

44
typedef struct stack STACK;

9. Bài tập
Bài 881: Đếm số lượng nút có đúng hai con mà thông tin tại nút đó là số chính phương
Bài 885: Tính tổng các nút trong cây

45
HÀNG ĐỢI – QUEUE
1. Nguyên lý hoạt động
Cấu trúc dữ liệu hàng đợi hoạt động theo nguyên lý vào trước, ra trước (FIFO – First In –
First Out)

2. Cấu trúc dữ liệu của hàng đợi


struct queue
{
int n;
KDL a[100];
};
typedef struct queue QUEUE;
KDL là kiểu dữ liệu của đối tượng được lưu trong queue.
3. Khởi tạo hàng đợi
void Init(QUEUE &que)
{
que.n=0;
}
4. Kiểm tra hàng đợi rỗng
int IsEmpty (QUEUE que)
{
if(que.n==0)
return 1;
return 0;
}

5. Kiểm tra hàng đợi đầy


int IsFull (QUEUE que)
{
if(que.n==100)

46
return 1;
return 0;
}
6. Thêm một đối tượng vào trong hàng đợi
Hình vẽ minh họa

Định nghĩa hàm


void EnQueue (QUEUE &que, KDL x)
{
que.a[que.n]=x;
que.n++;
}
7. Lấy một đối tượng ra khỏi hàng đợi
Hình vẽ minh họa

Định nghĩa hàm


KDL DeQueue (QUEUE &que)
{
KDL x = que.a[0];
for (int i=0; i <=que.n-2; i++)
que.a[i]=que.a[i+1];
que.n--;
return x;
}
8. Ứng dụng
 Bài toán: Định nghĩa hàm tính tổng các giá trị trong cây nhị phân các số thực bằng
hai phương pháp:
+ Đệ quy
+ Khử đệ quy với kỹ thuật queue

47
CÂY NHỊ PHÂN
1. Hình ảnh cây nhị phân

2. Khái niệm cây nhị phân


Cây nhị phân là 1 cây thỏa điều kiện mọi node trong cây có tối đa 2 con.
3. Cấu trúc dữ liệu của cây nhị phân
 Hình vẽ

 Khai báo cấu trúc dữ liệu


struct node
{
KDL info;
struct node *pLeft;
struct node *pRight;
};
typedef struct node NODE;
typedef NODE * TREE;

Ví dụ 1: Hãy khai báo cấu trúc dữ liệu cho cây nhị phân các số nguyên
Ví dụ 2: Hãy khai báo cấu trúc dữ liệu cho cây nhị phân các phân số.
4. Khởi tạo cây nhị phân
void Init(TREE &t)
{
t = NULL;
}

5. Tạo node cho cây nhị phân


NODE *GetNode(KDL x)
{
NODE *p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pLeft = NULL;
p->pRight = NULL;
return p;
}

Ví dụ 1: Định nghĩa hàm tạo node cho cây nhị phân các số nguyên
Ví dụ 2: Định nghĩa hàm tạo node cho cây nhị phân các phân số

48
6. Duyệt cây nhị phân
 Khái niệm: Duyệt cây nhị phân là thăm qua tất cả các node trong cây, mỗi node một
lần.
 Các phương pháp duyệt cây:
+ Phương pháp LNR
+ Phương pháp RNL
+ Phương pháp NLR
+ Phương pháp NRL
+ Phương pháp LRN
+ Phương pháp RLN
 Duyệt cây theo phương pháp LNR là duyệt cây con trái trước, sau đó duyệt đến nút
gốc và cuối cùng duyệt cây con phải.
 Cách thức duyệt cây con trái và duyệt cây con phải cũng giống như cách thức duyệt
cha.
7. Hàm cài đặt duyệt cây
Bài toán: Hãy định nghĩa tất cả các hàm duyệt và xuất cây nhị phân các số nguyên bằng
6 phương pháp.
struct node
{
KDL info;
struct node *pLeft;
struct node *pRight;
};
typedef struct node NODE;
typedef NODE * TREE;

Định nghĩa hàm duyệt và xuất cây theo phương pháp LNR
Định nghĩa hàm duyệt và xuất cây theo phương pháp LNR
Định nghĩa hàm duyệt và xuất cây theo phương pháp LNR
Định nghĩa hàm duyệt và xuất cây theo phương pháp LNR
Định nghĩa hàm duyệt và xuất cây theo phương pháp LNR
Định nghĩa hàm duyệt và xuất cây theo phương pháp LNR
8. Bài tập
Viết hàm xuất các giá trị trong cây nhị phân các số nguyên.
Viết hàm xuất các giá trị chẵn trong cây.
Viết hàm xuất địa chỉ các nút trên cây có giá trị (khóa) > x và < y.
Viết hàm xuất các số hoàn thiện trong cây.
Đếm số lượng nút có đúng 1 con.
Đếm số lượng nút có đúng 2 con.

49
Đếm số lượng nút chẵn.
Đếm số lượng nút lá mà thông tin tại nút đó là giá trị chẵn.
Đếm số lượng nút có đúng 1 con mà thông tin tại nút đó là số nguyên tố.
Viết hàm đếm số lượng nút có đúng 2 con mà thông tin tại nút đó là số chính phương.
Tính tổng các nút trong cây.
Tính tổng các nút lá trong cây.
Tính tổng các nút có đúng 1 con.
Tính tổng các nút có đúng 2 con.
Tính tổng các nút lẻ.
Tính tổng các nút lá mà thông tin tại đó là giá trị chẵn.
Tính tổng các nút có đúng 1 con mà thông tin tại đó là số nguyên tố.
Tính tổng các nút có đúng 2 con mà thông tin tại đó là số chính phương.
Tính chiều cao của cây nhị phân các số nguyên.
Tìm giá trị lớn nhất trong cây.
Tìm giá trị nhỏ nhất trong cây.
Tìm địa chỉ của nút trong cây mà giá trị tại nút đó bằng giá trị x. Nếu không tìm thấy
hàm trả về giá trị null.
Viết hàm độ lệch lớn nhất trong cây.

50
CÂY NHỊ PHÂN TÌM KIẾM – BINARY SEARCH TREE – BST
1. Hình vẽ

64

37 78

10 57 69 82

6 67 96

2. Khái niệm
 Cây nhị phân tìm kiếm là cây nhị phân thỏa điều kiện sau: Mọi node trong cây đều
có khóa lớn hơn tất cả các khóa thuộc cây con trái và nhỏ hơn tất cả các khóa thuộc
cây con phải
 Cây nhị phân tìm kiếm là cây nhị phân hỗ trợ việc tìm kiếm dựa trên khóa của từng
node trong cây.
struct node
{
KDL info;
struct node *pLeft;
struct node *pRight;
};
typedef struct node NODE;
typedef NODE *TREE;
3. Khởi tạo cây nhị phân tìm kiếm
void Init (TREE &t)
{
t=NULL;

51
}
4. Kiểm tra cây nhị phân tìm kiếm rỗng
int IsEmpty (TREE t)
{
if(t==NULL)
return 1;
return 0;
}
5. Tạo node cho cây nhị phân tìm kiếm
NODE *GetNode (KDL x)
{
NODE *p=new NODE;
if(p==NULL)
return NULL;
p->info=x;
p->pLeft=NULL;
p->pRight=NULL;
}
6. Thêm giá trị vào cây nhị phân tìm kiếm
 Khái niệm: Thêm 1 giá trị vào trong cây nhị phân tìm kiếm là thêm thông tin vào cây
sao cho tính chất của cây nhị phân tìm kiếm không vi phạm
 Giá trị trả về: Hàm thêm một giá trị vào trong cây nhị phân tìm kiếm trả về một trong
3 giá trị -1, 0, 1 với ý nghĩa như sau:
+ Giá trị 1: thêm thành công
+ Giá trị 0: trùng với khóa 1 node có sẵn trong cây
+ Giá trị -1: không đủ bộ nhớ

64

37 78

10 57 69 82

52
6 67 96
Vấn đề 1: Hãy định nghĩa hàm thêm một node (thông tin) vào cây nhị phân tìm kiếm các số
nguyên
struct node
{
int info;
struct node *pLeft;
struct node *pRight;
};
typedef struct node NODE;
typedef NODE *TREE;
NODE *GetNode(int x)
{
NODE*p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pLeft = NULL;
p->pRight = NULL;
return p;
}
int InsertNode(TREE &t, int x)
{
if (t != NULL)
{
if (t->info < x)
return InsertNode(t->pRight, x);
if (t->info>x)
return InsertNode(t->pLeft, x);
return 0;
}
t = GetNode(x);
if (t == NULL)
return -1;
return 1;
}

Vấn đề 2: Thêm 1 node vào cây nhị phân tìm kiếm các số thực
struct node
{
float info;
struct node *pLeft;
struct node *pRight;
53
};
typedef struct node NODE;
typedef NODE *TREE;
NODE *GetNode(float x)
{
NODE*p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pLeft = NULL;
p->pRight = NULL;
return p;
}
int InsertNode(TREE &t, float x)
{
if (t != NULL)
{
if (t->info < x)
return InsertNode(t->pRight, x);
if (t->info>x)
return InsertNode(t->pLeft, x);
return 0;
}
t = GetNode(x);
if (t == NULL)
return -1;
return 1;
}

7. Nhập cây nhị phân tìm kiếm


Vấn đề 1: Định nghĩa hàm nhập cây nhị phân tìm kiếm ở mức trừu tượng
void Input(TREE &t)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(t);
for (int i = 1; i <= n; i++)
{
KDL x;
Nhap(x);
InsertNode(t, x);
}
}

Vấn đề 2: Định nghĩa hàm nhập cây nhị phân tìm kiếm các số nguyên
void Input(TREE &t)
{
int n;
printf("Nhap n:");

54
scanf_s("%d", &n);
Init(t);
for (int i = 1; i <= n; i++)
{
int x;
printf("Nhap x:");
scanf_s("%d", &x);
InsertNode(t, x);
}
}

Vấn đề 3: Định nghĩa hàm nhập cây nhị phân tìm kiếm các số thực
void Input(TREE &t)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(t);
for (int i = 1; i <= n; i++)
{
float x;
printf("Nhap x:");
scanf_s("%f", &x);
InsertNode(t, x);
}
}

8. Duyệt cây nhị phân tìm kiếm


KDL Process (TREE t)
{
if(t==NULL)
return …;
….Process (t->pLeft);
….<Duyệt nút gốc>…
….Process (t->pRight);
return …;
}
Ví dụ 1: Định nghĩa hàm xuất tất cả các node trong cây nhị phân tìm kiếm các số nguyên
void Output(TREE t)
{
if (t == NULL)
return;
Output(t->pLeft);
printf("%4d", t->info);
55
Output(t->pRight);
return;
}

Ví dụ 2: Định nghĩa hàm đếm số lượng số chính phương trong cây nhị phân tìm kiếm các số
nguyên
//Đếm số chính phương
int DemCP(TREE t)
{
if (t == NULL)
return 0;
int a = DemCP(t->pLeft);
int b = DemCP(t->pRight);
if (ktcp(t->info) == 1)
return (a + b + 1);
return (a + b);
}
//kiểm tra số chính phương
int ktcp(int x)
{
int lc = 0;
for (int i = 0; i <= x;i++)
if (i*i == x)
lc = 1;
return lc;
}

9. Một chương trình đơn giản về cây BST


 Bài toán: Viết chương trình thực hiện các yêu cầu sau:
+ Nhập cây nhị phân tìm kiếm các số thực
+ Xuất các giá trị trong cây ra màn hình
+ Tính tổng các giá trị dương có trong cây
+ Đếm số lượng số chính phương
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <string.h>
struct node
{
float info;
struct node *pLeft;
struct node *pRight;
};
typedef struct node NODE;
typedef NODE *TREE;
void Init(TREE &);
NODE *GetNode(float);
int InsertNode(TREE &, float);
void Input(TREE &);

56
void Output(TREE);
float TongDuong(TREE);
int ktcp(float);
int DemCP(TREE );
void main()
{
TREE t;
Input(t);
Output(t);
float kq = TongDuong(t);
printf("\n Tong cac gia tri duong la: %8.3f", kq);
int cp = DemCP(t);
printf("\n So luong so chinh phuong la: %4d", cp);
_getch();
}
NODE *GetNode(float x)
{
NODE*p = new NODE;
if (p == NULL)
return NULL;
p->info = x;
p->pLeft = NULL;
p->pRight = NULL;
return p;
}
int InsertNode(TREE &t, float x)
{
if (t != NULL)
{
if (t->info < x)
return InsertNode(t->pRight, x);
if (t->info > x)
return InsertNode(t->pLeft, x);
return 0;
}
t = GetNode(x);
if (t == NULL)
return -1;
return 1;
}
void Init(TREE &t)
{
t = NULL;
}
void Input(TREE &t)
{
int n;
printf("Nhap n:");
scanf_s("%d", &n);
Init(t);
for (int i = 1; i <= n; i++)

57
{
float x;
printf("Nhap x:");
scanf_s("%f", &x);
InsertNode(t, x);
}
}
void Output(TREE t)
{
if (t == NULL)
return;
Output(t->pLeft);
printf("%8.3f", t->info);
Output(t->pRight);
return;
}
float TongDuong(TREE t)
{
if (t == NULL)
return 0;
float a = TongDuong(t->pLeft);
float b = TongDuong(t->pRight);
if (t->info > 0)
return (a + b + t->info);
return (a + b);
}
//Đếm số chính phương
int DemCP(TREE t)
{
if (t == NULL)
return 0;
int a = DemCP(t->pLeft);
int b = DemCP(t->pRight);
if (ktcp(t->info) == 1)
return (a + b + 1);
return (a + b);
}
//kiểm tra số chính phương
int ktcp(float x)
{
int lc = 0;
for (int i = 0; i <= x;i++)
if (i*i == x)
lc = 1;
return lc;
}

10.Bài tập

58
B – Cây

59

You might also like