Tải bản đầy đủ (.doc) (26 trang)

Bài tập cấu trúc dữ liệu và giải thuật có lời giải

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (135.87 KB, 26 trang )

ĐỀ CƯƠNG ÔN TẬP MÔN CTDL & TT CÓ LỜI GIẢI
PHẦN I. LÝ THUYẾT
CHƯƠNG I
1.1 Các khái niệm cơ bản
- Mô hình dữ liệu : là mô hình toán học cùng với các phép toán có thể thực hiện trên
các đối tượng của mô hình.
- Kiểu dữ liệu trừu tượng : là một mô hình dữ liệu được xét cùng với một số xác định
các phép toán.
- Giải thuật : là một dãy các câu lệnh chặt chẽ và rõ ràng, xác định một dãy các thao tác
trên một số đối tượng nào đó sao cho sau một số hữu hạn bước thực hiện ta đạt được kết
quả mong muốn.
- Cấu trúc dữ liệu : Cách thức tổ chức biểu diễn dữ liệu mà theo đó dữ liệu được lưu trữ
và được xử lý trong MTĐT, được gọi là cấu trúc dữ liệu.
- Kiểu dữ liệu :
+ Mỗi kiểu DL trong ngôn ngữ lập trình thường đại diện cho một loại dữ liệu
trong thực tế.
+ Trong ngôn ngữ lập trình, một kiểu dữ liệu T được xác định bởi một bộ <V, O>
trong đó :
V : tập các giá trị hợp lệ mà một đối tượng kiểu T có thể lưu trữ
O : tập các thao tác xử lý có thể thi hành trên đối tượng kiểu T
- Mối quan hệ giữa CTDL và GT : Giải thuật tác động trên dữ liệu lưu trữ trong các cấu
trúc để cho ra kết quả mong muốn. Trong lập trình, chúng quan hệ với nhau theo ràng
buộc sau:
Giải thuật + cấu trúc dữ liệu = chương trình
1.2 Phân biệt CTLT trong và CTLT ngoài
- CTLT trong : được lưu trữ trong bộ nhớ trong. Ví dụ: mảng, bản ghi….
- CTLT ngoài : được lưu trữ trong bộ nhớ ngoài. Ví dụ: tệp tin, bảng….
1.3 Đệ quy
- Khái niệm : Một đối tượng được gọi là đệ quy nếu nó bao gồm chính nó như là một bộ
phận hoặc nó được định nghĩa dưới dạng của chính nó.
- Giải thuật đệ quy : là giải thuật có chứa lời giải đệ quy. Lời giải đệ quy là lời giải của


bài toán T được thực hiện bởi lời giải của bài toán T’ có dạng như T (cỡ của T’< T).
- Đặc điểm của giải thuật đệ quy : Có 3 đặc điểm
- Trong giải thuật đệ quy bao giờ cũng có lời gọi đến chính nó
- Sau mỗi lời gọi đệ quy, kích thước của bài toán được thu nhỏ hơn trước
- Có một trường hợp suy biến: bài toán được giải quyết theo một cách khác hẳn
và giải thuật cũng kết thúc
- Ưu – nhược điểm của GT đệ quy :
+ ưu điểm : thuận lợi cho việc biểu diễn bài toán, đồng thời làm gọn chương trình
+ nhược điểm : không tối ưu về mặt thời gian (so với sử dụng vòng lặp), gây tốn
bộ nhớ


- Viết thuật toán tính n!, tính dãy fibonaci
+ Tính n!
int TinhGT (int n)
{
if(n==0) return 1;
else return (n*TinhGT(n-1));
}
+ Tính fibonaci
int TinhFB (int n)
{
if(n==1 || n==2) return 1;
else return (TinhFB(n-1)+TinhFB(n-2));
}
1.4 Sự cần thiết phân tích giải thuật
- Một bài toán có thể có nhiều giải thuật khác nhau. Phân tích giải thuật sẽ đánh giá các
giải thuật và tìm ra giải thuật tốt nhất. Các tiêu chuẩn đánh giá:
+ Giải thuật đúng đắn: để kiểm tra tính đúng đắn của giải thuật ta có thể cài đặt
giải thuật đó và cho thực hiện trên máy với một số bộ dữ liệu mẫu rồi lấy kết quả thu đc

so sánh với kết quả đã biết.
+ Giải thuật đơn giản: cần 1 giải thuật dễ viết chương trình để nhanh chóng có
được kết quả.
+ Độ phức tạp của giải thuật : là hiệu quả của giải thuật . Tính hiệu quả thể hiện
qua 2 mặt là thời gian và không gian.
1.5 Các bước cơ bản từ bài toán đến chương trình <2 bước>
- Bước 1: Thiết kế: nhằm xác định bài toán cần giải quyết và xây dựng mô hình toán học
cho bài toán.
- Bước 2: Mã hoá: Sử dụng ngôn ngữ lập trình cụ thể để viết chương trình ứng với cách
làm của giai đoạn trc nó.
CHƯƠNG II
2.1 Các khái niệm cơ bản
- Danh sách
+ Khái niệm : Danh sách là một cấu trúc dùng để lưu trữ một tập hợp hữu hạn
biến động các phần tử thuộc cùng một lớp đối tượng nào đó. Có thể cài đặt danh sách
bởi mảng và bởi con trỏ, tương ứng ta có danh sách kế tiếp và danh sách móc nối (danh
sách liên kết).
+ Hình ảnh :
+ Nguyên tắc hoạt động :
+ Ví dụ :
- Ngăn xếp
+ Khái niệm : ngăn xếp là một danh sách tuyến tính trong đó phép bổ sung một
phần tử vào ngăn xếp và phép loại bỏ một phần tử ra khỏi ngăn xếp đều được thực hiện
ở một đầu, đầu đó gọi là đỉnh của ngăn xếp
+ Hình ảnh :


+ Nguyên tắc hoạt động :
+ Ví dụ :
- Hàng đợi

+ Khái niệm : hàng đợi là một danh sách tuyến tính trong đó phép bổ sung một
phần tử vào hàng đợi được thực hiện ở một đầu còn phép loại bỏ một phần tử ra khỏi
hàng đợi được thực hiện ở đầu kia
+ Hình ảnh :
+ Nguyên tắc hoạt động :
+ Ví dụ :
2.3 Phân biệt ngăn xếp và hàng đợi
- Việc thêm vào, lấy ra một phần tử từ ngăn xếp đều được thực hiện ở một đầu, do
đó ngăn xếp hoạt động theo nguyên tắc LIFO, thích hợp với các ứng dụng có trình tự
truy xuất ngược với trình tự lưu trữ
- Việc thêm vào, lấy ra một phần tử từ hàng đợi được thực hiện ở hai đầu khác
nhau, do đó hàng đợi hoạt động theo nguyên tắc FIFO, thích hợp với các ứng dụng có
trình tự truy xuất và trình tự lưu trữ như nhau
2.2 Phân biệt mảng và danh sách liên kết
Mảng
Vùng nhớ của các phần tử trong mảng
được sắp xếp liên tục nhau
Truy cập tới phần tử trong mảng là truy
cập trực tiếp dựa vào chỉ số (ví dụ: a[0],
a[1], a[2],…, a[n])

Kích thước của mảng là hằng số,
không thay đổi khi chạy chương
trình
 Sử dụng mảng không tối ưu được bộ
nhớ. Có thể thừa hoặc thiếu bộ nhớ
khi xóa hoặc chèn phần tử vào mảng

Danh sách liên kết
Vùng nhớ của các phần tử trong danh sách

liên kết được sắp xếp tùy ý (do hệ điều
hành). Các phần tử lưu 1 con trỏ trỏ tới
phần tử tiếp theo.
Cần phải duyệt tuần tự khi muốn truy cập
tới phần tử trong danh sách liên kết.



Kích thước của danh sách liên kết có
thể thay đổi khi chạy chương trình.
Sử dụng danh sách liên kết tối ưu
được bộ nhớ. Vùng nhớ được cấp
phát thêm khi cần chèn thêm phần tử
mới, vùng nhớ được free khi xóa
phần tử.


CHƯƠNG III
3.1 Các khái niệm cơ bản
- Cây tổng quát : cây là một tập hợp T các phần tử (gọi là nút của cây) trong đó có 1 nút
đặc biệt được gọi là gốc, các nút còn lại được chia thành những tập rời nhau T1, T2 , ... ,
Tn theo quan hệ phân cấp trong đó Ti cũng là một cây. Mỗi nút ở cấp i sẽ quản lý một số
nút ở cấp i+1. Quan hệ này người ta còn gọi là quan hệ cha-con.
- Cây nhị phân : là một cây, trong đó số con tại mỗi đỉnh trên cây tối đa là 2 con và
được sắp thành cây con trái và cây con phải
- Cây tìm kiếm nhị phân : là 1 cây nhị phân t/m các đk:
+ All khoá tại các đỉnh của cây con bên trái đều có giá trị đi trước nhỏ hơn các
khoá tại đỉnh gốc.
+ Khoá tại gốc đi trc nhỏ hơn all các khoá ở các đỉnh của cây con bên phải.
+ Cây con bên trái và cây con bên phải cũng là cây TKNP.

- Các dạng cây nhị phân đặc biệt :
+ Cây lệch trái
+ Cây lệch trái
+ Cây zic-zắc
+ Cây nhị phân hoàn chỉnh
+ Cây nhị phân đầy đủ
3.2 Các nguyên tắc duyệt cây đa phân và cây nhị phân
- Nguyên tắc duyệt cây đa phân (cây tổng quát, cây)
+ Duyệt theo thứ tự trước
Nếu cây T rỗng: Không làm gì
Nếu T khác rỗng: Trình tự thăm các cây như sau:
1. Thăm gốc T
2. Thăm các cây con T1, T2,…., T(k) của T theo thứ tự trước
+ Duyệt theo thứ tự giữa
Nếu cây T rỗng: Không làm gì cả
Nếu T khác rỗng: Trình tự thăm:
1. Thăm cây con T1 của T theo thứ tự giữa
2. Thăm gốc T
3. Thăm các cây con còn lại của T theo thứ tự giữa T2,….,T(k)
+ Duyệt theo thứ tự sau
Nếu cây T rỗng: Không làm gì
Nếu T khác rỗng: Trình tự thăm:
1. Thăm các cây con T1, T2,…,T(k) của T theo thứ tự sau
2. Thăm gốc T
- Nguyên tắc duyệt cây nhị phân
+ Duyệt tiền tự – thứ tự trước: duyệt nút gốc, duyệt tiền tự con trái rồi duyệt tiền
tự con phải.
+ Duyệt trung tự – duyệt theo thứ tự giữa: duyệt trung tự con trái rồi đến nút gốc
sau đó là duyệt trung tự con phải.
+ Duyệt hậu tự – duyệt theo thứ tự sau: Duyệt hậu tự con trái rồi duyệt hậu tự con

phải sau đó là nút gốc.


CHƯƠNG IV
4.1 Định nghĩa đồ thị
- Đồ thị là một cấu trúc rời rạc dùng để mô tả một tập hợp các đối tượng rời rạc có mối
quan hệ n-m với nhau (n,m>0). Ký hiệu đồ thị G là G=<V,E>, trong đó:
+ V là tập các đỉnh
+ E là tập các cạnh/cung
4.2 Các khái niệm
- Đồ thị có hướng : nếu E là tập các cặp (u,v) khác (v,u), gọi là các cung
- Đồ thị vô hướng : nếu E gồm các cặp (u,v) = (v, u), gọi là các cạnh
- Đồ thị liên thông : nếu có đường đi giữa mọi cặp đỉnh phân biệt của đồ thị
- Đồ thị đơn : nếu giữa hai đỉnh u, v bất kỳ có nhiều nhất 1 cạnh/cung
- Đồ thị đa : nếu giữa hai đỉnh u, v bất kỳ có thể có nhiều hơn 1 cạnh/cung
- Đỉnh kề : nếu e = (u, v) là một cạnh thuộc E thì ta nói u, v kề nhau, và e là liên thuộc
với u và v
- Đường đi : một đường đi P = (V1, V2, …., Vp) mà cạnh (V(i-1), V(i)) thuộc E,
với i = 2…..p;
- Chu trình : P được gọi là chu trình nếu V1 = Vp
- Bậc của một đỉnh trên đồ thị : bậc của v (ký hiệu: deg(v)) là số cạnh liên thuộc với v
CHƯƠNG V
5.1 Tập hợp
- Định nghĩa tập hợp : Tập hợp là một cấu trúc rời rạc được nói là chứa các phần tử của
nó. Tập hợp thường dùng để gom nhóm các phần tử có các tính chất chung lại với nhau,
nhưng nó cũng có thể chứa các phần tử chẳng có mối quan hệ gì với nhau.
- Các phương pháp mô tả tập hợp : có 3 cách mô tả tập hợp
+ Cách 1: Dùng biểu đồ Ven là một đường cong khép kín, các điểm trong đường
cong đó chỉ các phần tử của tập hợp.


+ Cách 2: Liệt kê tất cả các phần tử của tập hợp A
Ví dụ: A = {1, 2, 3}….
+ Cách 3: Nêu lên các đặc trưng cho biết chính xác một đối tượng bất kỳ có là
một phần tử của tập A hay không.
Ví dụ : A = {x | x là số nguyên chẵn}


5.2 Hàm băm
- Tư tưởng hàm băm :
+ Phân chia tập hợp đã cho thành một số cố định các lớp(giả sử N lớp được đánh
số từ 0 -> N-1)
+ Sử dụng một mảng T có chỉ số chạy từ 0 đến N-1 để chứa các phần tử trong tập
hợp, mỗi thành phần T[i] là một “rổ” đựng các phần tử thuộc lớp thứ i, các phần
tư trong mỗi lớp được tổ chức thành một danh sách liên kết, T[i] là con trỏ trỏ tới
phần tử đầu tiên trong lớp thứ i. T chính là bảng băm mở
- Tác dụng hàm băm : Phân chia các phần tử của tập hợp vào trong các lớp. Nếu x là
giá trị khóa của môt phần tử nào đó của tập hợp thì h(x) là chỉ số nào đó của mảng T,
h(x) được gọi là giá trị băm của x, ta nói x thuộc lớp h(x);
- Tiêu chí lựa chọn :
+ Hàm băm phải cho phép tính được dễ dàng và nhanh chóng giá trị băm của mỗi
khóa
+ Phân bố đều các khóa vào các lớp


PHẦN II. BÀI TẬP
I. Bài tập về danh sách, ngăn xếp, hàng đợi
1. Danh sách
 Dạng cài đặt
Theo mảng
#define N 100

Typedef int item;
typedef struct
{
item Elems[N];
int size;
}List;
Theo con tro
Typedef int item;
typedef struct Node
{
item Data;
Node *next;
};
typedef Node *List;
 Danh sách kế tiếp
#include <stdio.h>
#include <stdlib.h>
#define N 100;
typedef int item;
//Cai dat cau truc mang
typedef struct
{
item Elems[N];
int size;
} List;
//Ham khoi tao danh sach rong
void Init(List *L)
{
(*L).size = 0; //size = 0.
}



//Ham kiem tra danh sach day
int Isfull (List L)
{
return (L.size==N);
}
//Ham kiem tra danh sach rong
int Isempty (List L)
{
return (L.size==0);
}
//Ham khoi tao gia tri x
item init_x()
{
int x;
scanf("%d", &x);
return x;
}
//Ham nhap du lieu
void Input (List *L)
{
int n;
printf("Nhap so phan tu cua danh sach: ");
scanf("%d", &(*L).size);
int i;
for (i=0; i<(*L).size; i++)
{
printf("Nhap phan tu thu %d : ",i+1);
(*L).Elems[i] = init_x();

}
}
//Ham hien thi du lieu
void Output (List L)
{
printf("Danh sach: \n");
int i;
for (i=0; iprintf("%5d", L.Elems[i]);
}
//Ham them phan tu x vao vi tri thu k
int Insert_k (List *L, item x, int k)
{


if (Isfull(*L))
{
printf("Danh sach day !");
return 0;
}
if (k<1 || k>(*L).size+1)
{
printf("Vi tri chen khong hop le !\n");
return 0;
}
printf ("Nhap thong tin: ");
x = init_x();
int i;
for (i = (*L).size; i >= k; i--)
(*L).Elems[i] = (*L).Elems[i-1];

(*L).Elems[k-1]=x;
(*L).size++;
return 1;
}
//Ham xoa phan tu o vi tri thu k
int Del_k (List *L, item *x, int k)
{
if (Isempty(*L))
{
printf("Danh sach rong !");
return 0;
}
if (k<1 || k>(*L).size)
{
printf("Vi tri xoa khong hop le !");
return 0;
}
*x=(*L).Elems[k-1];
int i;
for (i=k-1; i<(*L).size-1; i++)
(*L).Elems[i]=(*L).Elems[i+1];
(*L).size--;
return 1;
}


//Ham tim kiem phan tu co gia tri x
int Search (List L, item x)
{
int i;

for (i=0; iif (L.Elems[i] == x)
return i+1;
return 0;
}
int main()
{
...
return 0;
getch();
}
 Danh sách liên kết đơn
#include<stdio.h>
#include<stdlib.h>
typedef int item;
//Cai dat danh sach
typedef struct Node
{
item Data;
Node *next;
};
typedef Node *List;
//Khoi tao danh sach rong
void Init (List &L)
{
L=NULL;
}
//Kiem tra danh sach rong
int Isempty (List L)
{

return (L==NULL);
}


//Tao mot node chua du lieu x
Node *Make_Node (Node *P, item x)
{
P = (Node *) malloc (sizeof (Node));
P->next = NULL;
P->Data = x;
return P;
}
//Tinh do dai danh sach
int len (List L)
{
Node *P=L;
int i=0;
while (P!=NULL)
{
i++;
P=P->next;
}
return i;
}
//Them phan tu co gia tri x vao vi tri dau
void Insert_first (List &L, item x)
{
Node *P;
P = Make_Node(P,x);
P->next = L;

L = P;
}
//Them phan tu co gia tri x vao vi tri k
void Insert_k (List &L, item x, int k)
{
Node *P, *Q = L;
int i=1;
if (k<1 || k> (len(L)+1)) printf("Vi tri chen khong hop le !");
else
{
P = Make_Node(P,x);
if (k == 1) Insert_first(L,x);


else
{
while (Q != NULL && i != k-1)
{
i++;
Q = Q->next;
}
P->next = Q->next;
Q->next = P;
}
}
}
//Them phan tu o vi tri cuoi
//Xoa phan tu o vi tri dau
void Del_frist (List &L, item &x)
{

x = L->Data;
L = L->next;
}

//Xoa phan tu o vi tri thu k
void Del_k (List &L, item &x, int k)
{
Node *P=L;
int i=1;
if (k<1 || k>len(L)) printf("Vi tri xoa khong hop le !");
else
{
if (k==1) Del_frist(L,x);
else //xoa vi tri k != 1
{


while (P != NULL && i != k-1)
{
P=P->next;
i++;
}
P->next = P->next->next;
}
}
}
//Xoa phan tu o vi tri cuoi
//Nhap du lieu cho danh sach
void Input (List &L)
{

int i=0;
item x;
do
{
i++;
printf ("Nhap phan tu thu %d : ",i);
scanf("%d",&x);
if (x != 0) Insert_k(L,x,len(L)+1);
} while(x != 0);
}
//Hien thi du lieu
void Output (List L)
{
Node *P=L;
while (P != NULL)
{
printf("%5d",P->Data);
P = P->next;
}
printf("\n");
}
2. Ngăn xếp
 Dạng cài đặt
Theo mảng
#define Max 100
Typedef int item;
struct Stack


{

int Top;
item Data[Max];
};
Theo con trỏ
typedef int item;
struct Node
{
item Data;
Node *Next;
};
typedef struct Stack
{
Node *Top;
};
 Các thao tác dùng con tro
//tao cau truc stack
typedef int item;
struct Node
{
item Data;
Node* Next;
};
typedef struct stack
{
Node* Top;
};
//khoi tao ngan xep rong 1
void Init(stack &s)
{
s.Top=NULL;

}
//kiem tra danh sach rong
int empty (stack s)
{
return(s.Top==NULL);
}
//tao mot node
Node* MakeNode(item x)


{
Node*p = (Node*) malloc(sizeof(Node));
p->Next = NULL;
p->Data = x;
return p;
}
//them 1 phan tu vao dinh
void Push(stack &s, item x)
{
Node*p = MakeNode(x);
p->Next = s.Top;
s.Top = p;
}
//Xoa 1 phan tu o dinh
int Pop(stack &s)
{
if(!empty(s))
{
item x=s.Top->Data;
s.Top=s.Top->Next;

return x;
}
}
//Nhap du lieu
void Input(stack &s)
{
int i=0;
item x;
do
{
i++;
printf("\nNhap phan tu thu %d ", i+1);
scanf("%d", &x);
if(x!=0) Push(s,x);
}while(x!=0);
}


//Hien thi du lieu
void Output(stack s)
{
Node *p = s.Top;
while (p!=NULL)
{
printf("%d ", p->Data);
p=p->Next;
}
printf("\n");
}
//Chuyen tu he 10 sang he 2

void Dec_to_Bin()
{
int n,x;
stack s;
Init(s);
printf("\n nhap he so 10: ");
scanf("%d",&n);
while (n>=1)
{
x=n%2;
Push(s,x);
printf("%d",x);
n/=2;
}
printf("\n");
}
3. Hàng đợi
 Dạng cài đặt
Theo mảng
define MAX 100;
typedef int item;
struct Queue
{
int front, rear;
item data[MAX];
int count;


};
Theo con trỏ

typedef int item;
struct Queue
struct Node
{
{
Node * Front, *Rear;
item Data;
int count;
Node * Next;
};
};
 Các thao tác dùng con tro
//Cai dat 1 node
struct Node
{
item Data;
Node * Next;
};
//Cai dat queue
struct Queue
{
Node * Front, *Rear;
int count;
};
//Khoi tao queue rong
void Init(Queue &Q)
{
Q.Front = Q.Rear = NULL;
Q.count = 0;
}

//Kiem tra queue rong
int Isempty (Queue Q)
{
if (Q.count == 0)
return 1;
return 0;
}
//Tao mot node
Node *MakeNode(item x)
{
Node *P = (Node*) malloc(sizeof(Node));
P->Next = NULL; P->Data = x;
return P;
}
//Them phan tu vao cuoi queue


void Push(Queue &Q, item x)
{
Node *P = MakeNode(x);
if (Isempty(Q))
{
Q.Front = Q.Rear = P;
}
else
{
Q.Rear->Next = P;
Q.Rear = P;
}
Q.count ++ ;

}
//Xoa phan tu o dau queue
int Pop(Queue &Q)
{
if (Isempty(Q))
{
printf("Hang doi rong !");
return 0;
}
else
{
item x = Q.Front->Data;
if (Q.count == 1) //neu co 1 phan tu
Init(Q);
else
Q.Front = Q.Front->Next;
Q.count --;
return x;
}
}
//Them phan tu x o vi tri thu k
//Xoa phan tu x o vi tri thu k
//Nhap queue
void Input (Queue &Q)
{
int i=0;
item x;


do

{
i++;
printf ("Nhap phan tu thu %d : ",i);
scanf("%d",&x);
if (x != 0) Push(Q,x);
} while(x != 0);
}
//Hien thi queue
void Output(Queue Q)
{
Node *P = Q.Front;
while (P != NULL)
{
printf("%d ",P->Data);
P = P->Next;
}
printf("\n");
}
II. Bài tập về cây, đồ thị, tập hợp
1. Cây
 Tự vẽ cây gồm 10-12 đỉnh. Duyệt cây vừa vẽ theo các thứ tự: trước, giữa, sau
 Vẽ cây nhị phân biểu diễn biểu thức toán học, đưa biểu thức toán học về
dạng tiền tố, hậu tố
 Dạng cài đặt cây đa phân bằng con trưởng và em liền kề
Theo mảng
#define N 100;
typedef int item;
struct Node
{
item infor;

int EldestChild;
int NextSibling;
};
typedef struct Tree
{
Node Elems[N];
};
Tree T
Theo con trỏ
struct Node


{
item infor;
struct Node *EldestChild;
struct Node *Nextsibling;
};
typedef struct Node *Tree;
Tree root;
 Dạng cài đặt cây nhị phân
Theo mảng
#define N 100;
typedef int item;
struct Node
{
item infor;
int left;
int right;
};
typedef struct BTree

{
Node Elems[N];
};
BTree T;

Theo con trỏ
typedef int item;
typedef struct Node
{
item data;
Node *left, *right;
} Node;
Node *BTree;

 Dạng cài đặt cây TKNP bằng con tro
typedef struct Node
{
int key;
int data;
Node *left, *right;
} Node;
typedef Node *SearchTree;
 Trình bày ý tưởng và viết các hàm cho cây đa phân
Tìm con trưởng, em kề
 Ý tưởng
 Cài đặt
Tìm cha của đỉnh k
 Ý tưởng: Duyệt lần lượt các đỉnh trên cây, xuất phát từ gốc (i=1), kiểm tra
xem con trưởng j của i có = k hay không?
- Nếu bằng thì i chính là cha cần tìm

- Ngược lại, kiểm tra em liền kề của con trưởng j xem có bằng k hay ko?
+ Nếu bằng nhau thì i chính là cha cần tìm


+ Nếu không ktra j là em liền kề của j cũ
Cứ tiếp tục như vậy cho đến khi kiểm tra hết các con của i mà không có con
nào = k thì duyệt đỉnh i tiếp theo trên cây. Ngược lại chỉ cần 1 con j của i = k thì dừng
tìm kiếm và kl i chính là đỉnh cha cần tìm
 Cài đặt:
int Parent (Tree T, int k)
{
int i=0; int j; int found=0;
while(i{
j=T.Elems[i].EldestChild;
if(j==k)
{
return i;
found = 1;
}
else
{
j=T.Elems[j].NextSibling;
while(j!==-1 && (found!=1))
{
if(j==k)
{
return i;
found = 1;
}

else j=T.Elems[j].NextSibling;
} i++ }}
Duyệt cây theo thứ tự trước
 Ý tưởng:
Nếu cây T rỗng: Không làm gì
Nếu T khác rỗng: Trình tự thăm các cây như sau:
1. Thăm gốc T
2. Thăm các cây con T1, T2,…., T(k) của T theo thứ tự trước
 Cài đặt:
void Preorder (Node type T)
{
Node type c;
visit(T);
c = EldestChild(T);
while(c!=$)
{


Preorder (C);
c = NextSibling;
}
}
Duyệt theo thứ tự giữa
 Ý tưởng:
Nếu cây T rỗng: Không làm gì cả
Nếu T khác rỗng: Trình tự thăm:
1. Thăm cây con T1 của T theo thứ tự giữa
2. Thăm gốc T
3. Thăm các cây con còn lại của T theo thứ tự giữa T2,….,T(k)
 Cài đặt:

void Inorder (Node type T)
{
Node type c;
c = EldestChild(T);
if(c!=$)
{
Inorder(c);
c = NextSibling(c);
}
visit(T);
while(c!=$)
{
Inorder(c);
c = NextSibling(c);
}
}

Duyệt theo thứ tự sau
 Ý tưởng:
Nếu cây T rỗng: Không làm gì
Nếu T khác rỗng: Trình tự thăm:
1. Thăm các cây con T1, T2,…,T(k) của T theo thứ tự sau
2. Thăm gốc T
 Cài đặt:
void Postorder (Node type T)
{
Node type c;
c = EldestChild(T);



while(c!=$)
{
Postorder(c);
c = NextSibling(c);
}
visit(T);
}
 Trình bày ý tưởng và viết các hàm cho cây nhị phân
 Ý tưởng
 Cài đặt
 Trình bày ý tưởng và viết các hàm cho cây TKNP
Nhập dữ liệu
void CreateTree (Tree &T)
{
int x;
while (1)
{
printf("Nhap vao Node: ");
scanf("%d", &x);
if (x == 0) break;
int check = insertNode(T, x); //ham them xem o duoi
if (check == -1) printf("Node da ton tai!");
else if (check == 0) printf("Khong du bo nho");
}
}

Tìm đỉnh có khoá x trên cây
Node *searchKey(Tree T, item x)
{
if (T!=NULL)

{
if (T->key == x)
{
Node *P = T;
return P;


}
if (T->key > x) return searchKey(T->Left, x);
if (T->key < x) return searchKey(T->Right, x);
}
return NULL;
}
Thêm đỉnh có khoá x vào cây
int insertNode (Tree &T, item x)
{
if (T != NULL)
{
if (T->key == x) return -1;
if (T->key > x) return insertNode(T->Left, x);
else if (T->key < x)
return insertNode(T->Right, x);
}
T = (Node *) malloc(sizeof(Node));
if (T == NULL) return 0;
T->key = x;
T->Left = T->Right = NULL;
return 1;
}
Xoá đỉnh có khoá x trên cây

 Ý tưởng: Gọi X là nút cần hủy, có ba trường hợp:
TH1: X là nút lá => đơn giản chỉ cần hủy X vì nó không móc nối đến phần
tử nào khác
TH2: X chỉ có 1 con (trái hoặc phải): Trước khi hủy X ta móc nối cha của X
với con duy nhất của nó.
TH3: X có đủ cả 2 con: ta không thể hủy trực tiếp do X có đủ 2 con. Ta sẽ
hủy gián tiếp. Thay vì hủy X, ta sẽ tìm một phần tử thế mạng Q. Phần tử
này có tối đa một con. Thông tin lưu tại Q sẽ được chuyển lên lưu tại X.
Sau đó, nút bị hủy thật sự sẽ là Y giống như 2 trường hợp đầu. Vấn đề là
phải chọn Y sao cho khi lưu Q vào vị trí của X, cây vẫn là CNPTK.
Có 2 phần tử thỏa mãn yêu cầu:
+ Phần tử nhỏ nhất (trái nhất) trên cây con phải.
+ Phần tử lớn nhất (phải nhất) trên cây con trái.
 Cài đặt:
int delKey(Tree &T, item x)
{
if (T==NULL) return 0;
else if (T->key > x)


return delKey(T->Left, x);
else if (T->key < x)
return delKey(T->Right, x);
else
{
Node *P = T;
if (T->Left == NULL) T = T->Right;
else if (T->Right == NULL) T = T->Left;
else
{

Node *S = T, *Q = S->Left;
while (Q->Right != NULL)
{
S = Q;
Q = Q->Right;
}
P->key = Q->key;
S->Right = Q->Left;
delete Q;
}
}
return 1;
}
2. Đồ thị
 Viết dạng cài đặt đồ thị
Theo ma trận kề
#define MAX 100
struct DoThi
{
int n;
int a[MAX][MAX];
};
Theo danh sách kề
struct Cell
{
int vertex;
Cell *next;
};
const int N=100;
typedef Cell *Graph[N];

 Trình bày ý tưởng và viết các hàm
Nhập dữ liệu


×