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

Đề cương môn Cấu trúc dữ liệu và giải thuật HV CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG

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 (308.51 KB, 55 trang )

Cấu trúc dữ liệu và giải thuật
I.

Sắp sếp và tìm kiếm

1: Sắp xếp
• sắp xếp chọn(selection sort)
A: Thuật toán selection sort
void selection_sort(){
int i, j, k, temp;
for (i = 0; i< N; i++){
k = i;
for (j = i+1; j < N; j++){
if (a[j] < a[k]) k = j;
}
temp = a[i]; a[i] =a [k]; a[k] = temp;
}
}

B. Độ phức tạp
Cmin=Cmax=Ctb=n(n-1)/2
Tốt nhất: nlogn

C: Ví dụ, các bước thực hiện sắp xếp chọn dãy số bên dưới như sau:
Cho dãy số K={5, 6, 9, 1, 3, 4, 2, 7, 8}
bước 1: 1

6

9


5

3

4

2

7

8

bước 2: 1

2

9

5

3

4

6

7

8


bước 3: 1

2

3

5

9

4

6

7

8

bước 4: 1

2

3

4

9

5


6

7

8

bước 5: 1

2

3

4

5

9

6

7

8

bước 6: 1

2

3


4

5

6

9

7

8

bước 7: 1

2

3

4

5

6

7

9

8


bước 8: 1

2

3

4

5

6

7

8

9

1


b1
b2
b3
b4
b5
b6
b7
b8
b9


18
10

12
12
11

15
15
15
12

10
18
18
18
12

19
19
19
19
19
13

11
11
12
15

15
15
15

17
17
17
17
17
17
17
16

13
13
13
13
13
19
19
19
17

12
12
12
12
18
18
18

18
18
18

16
16
16
16
16
16
16
17
19
19

• Sắp xếp chèn (Insert sort)
A: Thuật toán
void insertion_sort(){
int i, j, k, temp;
for (i = 1; i< N; i++){
temp = a[i];
j=i-1;
while ((a[j] > temp)&&(j>=0)) {
a[j+1]=a[j];
j--;
}
a[j+1]=temp;
}
}


B: Độ phức tạp
độ phức tạp bé nhất: Cmin=(n-1)
độ phức tạp lớn nhất: n(n-1)/2=O(n2)
độ phức tạp trung bình: (n2+n-2)/4=O(n2)
Nlogn

C: Ví dụ
Cho một dãy

K={4

7

6

5

1

3

8

9

2}

bước 1:

4


7

6

5

1

3

8

9

2

bước 2:

4

6

7

5

1

3


8

9

2

2


bước 3:

4

5

6

7

1

3

8

9

2


bước 4:

1

4

5

6

7

3

8

9

2

bước 5:

1

3

4

5


6

7

8

9

2

bước 6:

1

3

4

5

6

7

8

9

2


bước 7:

1

3

4

5

6

7

8

9

2

bước 8:

1

2

3

4


5

6

7

8

9

18

12

15

10

19

11

17

13

b1

12


18

b2

12

15

18

b3

10

12

15

18

b4

10

12

15

18


19

b5

10

11

12

15

18

19

b6

10

11

12

15

17

18


19

b7

10

11

12

13

15

17

18

19

b8
b9

10
10

11
11

12

12

12
12

13
13

15
15

17
16

18
17

• Sắp xếp nhanh( Quich sort)
A: Thuật toán
void quick(int left, int right) {
int i,j;
int x,y;
i=left; j=right;
x= a[left];
do {
while(a[i]while(a[j]>x && j>left) j--;
if(i<=j){
y=a[i];a[i]=a[j];a[j]=y;
i++;j--;

}
}while (i<=j);
if (leftif (i
3

12

16

19
18

19


}

B: Độ phức tạp

tốt nhất: Cmax=Ctb=O(nlog2n); Nlogn

C: Ví dụ
bước
bước
bước
bước

B1

B2
B3
B4


1:
2:
3:
4:

18
12
10
10
10

4
1
1
1
1

7
2
2
2
2

12
12

11
11
11

6
3
3
3
3

15
15
12
12
12

5
4
4
4
4

10
10
15
12
12

1
5

5
5
5

19
16
16
13
13

3
6
6
6
6

8
8
8
8
7

9
9
9
9
8

2
7

7
7
9

11
11
12
15
15

17
17
17
17
16

13
13
13
16
17

12
18
18
18
18

Sắp xếp nổi bọt ( Bubble sort)


A: Thuật toán
Void Bubble_sort
For (i=1; i<=n-1; i++){
For (j=n-1; j>=i; j--){
If (kj>kj+1){
<doi cho k; cho kj+1>;
}
}
}
}
void bubble_sort(){
int i, j, temp, no_exchange;
i = 1;
do{
no_exchange = 1;
for (j=n-1; j >= i; j--){
if (a[j-1] > a[j]){
temp=a[j-1];
a[j-1]=a[j];
a[j]=temp;
no_exchange = 0;
}
}

4

16
19
19
19

19


i++;
} until (no_exchange || (i == n-1));
}

B: Độ phức tạp

O(n2) với n=|k|
C: Ví dụ: kiểm nghiệm thuật toán trên bộ khoá
k={9
7
18
8
6
bước 1:
bước 2:
bước 3:
bước 4:
bước 5:

6
6
6
6
6

9
7

7
7
7

7
9
8
8
8

18
8
9
9
9

11}
8
18
11
11
11

11
11
18
18
18

-----------------------------------------------------------------


ví dụ 2: K={9
bước 1:
bước 2:
bước 3:
bước 4:
bước 5:

b1
b2
b3
b4
b5
b6
b7
b8
b9

18 12
10 18
11

1

7

8

3


5

4}

1
1
1
1
1

7
7
3
3
3

8
3
5
4
4

3
5
4
5
5

5
4

7
7
7

4
8
8
8
8

15
12
18
12

10
15
12
18
12

19
11
15
12
18
13

11
19

12
15
13
18
15

17
12
19
13
15
15
18
16

• sắp xếp vun đống (Heap sort)
A: Thụât toán
void upheap(int m){
int x;
x=a[m];
while ((a[(m-1)/2]<=x) && (m>0)){
a[m]=a[(m-1)/2];
5

9
9
9
9
9


13
17
13
19
16
16
16
18
17

12
13
17
16
19
17
17
17
18
18

16
16
16
17
17
19
19
19
19

19


m=(m-1)/2;
}
a[m]=x;
}
void insert_heap(int x){
a[m]=x;
upheap(m);
m++;
}

--------------------------------------------------void downheap(int k){
int j, x;
x=a[k];
while (k<=(m-2)/2){
j=2*k+1;
if (jif (x>=a[j]) break;

a[k]=a[j]; k=j;
}
a[k]=x;
}
-----------------------------------------------------------------

int remove_node(){
int temp;
temp=a[0];

a[0]=a[m];
m--;
downheap(0);
return temp;
}
void heap_sort(){
int i;
m=0;
6


for (i=0; i<=n-1; i++) insert_heap(a[i]);
m=n-1;
for (i=n-1; i>=0; i--) a[i]=remove_node();
}

B: Độ phức tạp
O(N2).

C: Ví dụ
• sắp xếp trộn (Merge sort)
A: Thuật toán
void merge_sort(int *a, int left, int right){
int middle;
if (right<=left) return;
middle=(right+left)/2;
merge_sort(a, left, middle);
merge_sort(a, middle+1, right);
merge(a, left, middle ,right);
}


B: Độ phức tạp
O(nlogn)

C: Ví dụ
Cho dãy K={ 5

4

6

1

Bước 1: So sánh 2 phần tử đầu tiên
4
5
1
6

8

3

3

9

8

Bước 2: Thực hiện tương tự như bước 1:

4
5
1
6 3

8

7

2}

7
7

9

2

9

2

1

4

5

6


3

7

8

9

2

1

3

4

5

6

7

8

9

2

1


2

3

4

5

6

7

8

18
12
10
10

12
18
12
11

15
10
15
12

B1

B2
B3

10
15
18
13

19
11
11
15
7

11
19
13
17

17
13
17
18

13
17
19
19

9


12
12
12
12

16
16
16
16


B4

10

11

12

13

13

15

16

17


18

19

2: Tìm kiếm
• Tìm kiếm tuần tự: Lần lượt duyệt từng phần tử của danh sách từ phần tử đầu
tiên tới cuối cùng cho tới khi có kết quả tìm kiếm

A: Thuật toán
int sequential_search(int *a, int x, int n){
int i;
for (i=0; iif (a[i] == X)
return(i);
}
return(-1);
}

B: Độ phức tạp
C(n)=O(n); C(n)=O(1)

• Tìm kiếm nhị phân
A: Thuật toán
int binary_search(int *a, int x){
int k, left =0, right=n-1;
do{
k=(left+right)/2;
if (xelse l=k+1;
}while ((x!=a[k]) && (left<=right))

if (x=a[k]) return k;
else return -1;
}
-----------------------------------------------------------------

Cài đặt:
int bsearch (float a[], int n, float x)
{ int i,j,k;
If (!storted(a,n))
Return -2;
i=0, j=n-1
int storted (float a[], int n)
8


{for (int i=0; iIf(a[i]> a[i+1])
Return 0;
Return 1;}
i=0; j=n-1;
while(i<=j)
{ k=(i+j)/2;
If(a[k]==x) return k;
If(a[k]>x) j=k-1;
Else j=k+1;}
Return -1;}

B: Độ phức tạp
O(log2n)


II.

Ngắn Xếp – Hàng Đợi – Danh sách liên kết

1) Ngăn Xếp (stack)
a) Định nghĩa: Ngăn xếp (stack) hay bộ xếp chồng là một kiểu danh sách
tuyến tính mà phép bổ sung phần tử và loại bỏ phần tử luôn luôn được thực
hiện ở một đầu gọi là đỉnh (top)

b) Biểu diễn
• Khai báo
#define MAX 100
typedef struct {
int top;
int nut[MAX];
} stack;

• Thao tác:
o Khởi tạo ngăn xếp
void StackInitialize(stack *s){
s-> top = -1;
return;
}

o Kiểm tra ngăn xếp rỗng
int

StackEmpty(stack s){
return (s.top = = -1);


9


}

o Kiểm tra ngăn xếp đầy
int

StackFull(stack s){
return (s.top = = MAX-1);

}

o Bổ sung một phần tử vào ngăn xếp
void

Push(stack *s, int x){
if (StackFull(*s)){
printf(“Ngan xep day !”);
return;
}else{
s-> top ++;
s-> nut[s-> top] = x;
return;
}

o Lấy ra một phần tử khỏi ngăn xếp
int

Pop(stack *s){

if (StackEmpty(*s)){
printf(“Ngan xep rong !”);
}else{
return s-> nut[s-> top--];
}

}

c) Áp dụng:
Ứng dụng ngăn xếp: Áp dụng tack giải bài toán đổi 1 số ở hệ số 10 thành
số ở hệ số b bất kỳ: Để chuyển đổi một số ở hệ cơ số 10 thành số ở hệ số bất
kỳ, ta lấy số đó chia cơ số cần chuyển đổi, lưu trữ lại phần dư của phép chia,
sau đó đảo ngược dãy các số dư ta nhận được số cần chuyển đổi việc làm
này giống như cơ số chế lifo của stack:
#inlude<stdio.h>
#include<conio.h>
#include<string.h>
#define MAX 100;
10


int ok=1;
typedef struct{
int top;
int node[MAX];
}stack;
int empty(stack *ps){
if(ps->top==-1){
printf("\n stack rỗng");
return(1);

}return(0);
}
void push(stack *ps,int p){
if (ps->top=MAX-1)
{ printf("\n stack đầy");
return;
}
else{ ps->top=(ps->top)+1;
ps->node[ps->top]=p;
}
}
int pop(stack *ps){
if(empty(ps))
{printf("\n stack rỗng");
return(0);
};
return(ps->node[ps->top--];
}
void main(void){
int coso,sodu;
float n;
stack s;
s.top=-1;
printf("\n nhập số n=");
scanf("%f",&n);
printf("\n cơ số cần chuyển:");
scanf("%d",&coso);
while(n!=0)
{
sodu=n%coso;

push(&s,sodu);
n=n/coso;

11


}
while(!empty(&s))
printf("%x",pop(&s);
getch();
}
- Tính giá trị của biểu thức ở dạng hậu tố
Duyệt biểu thức từ trái qua phải.
- Nếu gặp toán hạng, đưa vào ngăn xếp.
- Nếu gặp toán tử, lấy ra 2 toán hạng trong ngăn xếp từ ngăn xếp ra tính, kết
quả được bao nhiêu thì đưa vào ngăn xếp. Khi duyệt đến hết phần tử cuối
cùng trong ngăn xếp sẽ chưa kết quả

- Chuyển đổi từ dạng trung tố sang dạng hậu tố
Thuật toán chuyển đổi biểu thức từ dạng trung tố sang dạng hậu tố như sau:
Duyệt biểu thức từ trái qua phải.
- Nếu gặp dấu mở ngoặc: Bỏ qua
- Nếu gặp toán hạng: Đưa vào biểu thức mới.
- Nếu gặp toán tử: Đưa vào ngăn xếp.
- Nếu gặp dấu đóng ngoặc: Lấy toán tử trong ngăn xếp, đưa vào biểu thức mới.

2) Hàng đợi (queue)
a) Định nghĩa: Hàng đợi là một cấu trúc dữ liệu gần giống với ngắn
xếp, nhưng khác với ngăn xếp ở nguyên tắc chọn phần tử cần lấy ra khỏi tập phần
tử. Trái ngược với ngăn xếp, phần tử được lấy ra khỏi hàng đợi không phải là phần

tử mới nhất được đưa vào mà là phần tử đã được lưu trong hàng đợi lâu nhất.

b)

Biểu diễn

• Khai báo
#define MAX 100
typedef struct {
int head, tail, count;
int node[MAX];

} queue;

• Thao tác khởi tạo hàng đợi
void QueueInitialize(queue *q){
q-> head = 0;
q-> tail = MAX-1;
q-> count = 0;

12


return;
}

• Thao tác kiểm tra hàng đợi rỗng
int QueueEmpty(queue q){
return (q.count <= 0);
}


• Thao tác thêm một phần tử vào hàng đợi
void Put(queue *q, int x){
if (q-> count == MAX)
printf(“Hang doi day !”);
else{
if (q->tail == MAX-1 )
q->tail=0;
else
(q->tail)++;
q->node[q->tail]=x;
q-> count++;
}
return;
}

• Lấy phần tử ra khỏi hàng đợi
int Get(queue *q){
int x;
if (QueueEmpty(*q))
printf("Hang doi rong !");
else{
x = q-> node[q-> head];
if (q->head == MAX-1 )
q->head=0;
else
(q->head)++;
q-> count--;
}
return x;

}
3) Danh sách liên kết :

13


a) Định nghĩa danh sách liên kết đơn : Là danh sách có cấu trúc dữ liệu có kiểu
truy cập tuần tự. Mỗi phần tử trong danh sách liên kết có chứa thông tin về phần tử tiếp
theo, qua đó ta có thế truy cập tới phần tử này.

b) Biểu diễn
• Khai báo
struct node {
int item;
struct node *next;
};
typedef struct node *listnode;

• Tạo, cấp phát và giải phóng bộ nhớ cho một nút
listnode p; // Khai báo biến p
p = (listnode)malloc(sizeof(struct node));//cấp phát bộ
nhớ cho p
free(p); //giải phóng bộ nhớ đã cấp phát cho nút p;

• khởi tạo danh sách
void init(DanhSach &d)
{d.pfirst=NULL;d.plast=NULL;
}

• Kiểm tra rỗng


int empty(DanhSach &d)
{return(d.pfirst==NULL);
}

• Thêm phần tử vào đầu danh sách
void Insert_Begin(listnode *p, int x){
listnode q;
q = (listnode)malloc(sizeof(struct node));
q-> item = x;
q-> next = *p;
*p = q;
}

• Thêm phần tử vào cuối danh sách
void Insert_End(listnode *p, int x){
listnode q, r;
q = (listnode)malloc(sizeof(struct node));
14


q-> item = x;
q->next = NULL;
if (*p==NULL) *p = q;
else{
r = *p;
while (r->next != NULL) r = r->next;
r->next = q;
}
}


• Thêm phần tử vào giữa danh sách
void Insert_Middle(listnode *p, int position, int x){
int count=1, found=0;
listnode q, r;
r = *p;
while ((r != NULL)&&(found==0)){
if (count == position){
q = (listnode)malloc(sizeof(struct node));
q-> item = x;
q-> next = r-> next;
r-> next = q;
found = 1;
}
count ++;
r = r-> next;
}
if (found==0)
printf(“Khong tim thay vi tri can chen !”);
}

• Xoá phần tử ở đầu danh sách
void Remove_Begin(listnode *p){
listnode q;
if (*p == NULL) return;
q = *p;
*p = (*p)-> next;
q-> next = NULL;
free(q);
}


• Xoá phần tử ở cuối danh sách
15


void Remove_End(listnode *p){
listnode q, r;
if (*p == NULL) return;
if ((*p)-> next == NULL){
Remove_Begin(*p);
return;
}
r = *p;
while (r-> next != NULL){
q = r;
r = r-> next;
}
q-> next = NULL;
free(r);
}

• Xoá phần tử ở giữa danh sách
void Remove_Middle(listnode *p, int position){
int count=1, found=0;
listnode q, r;
r = *p;
while ((r != NULL)&&(found==0)){
if (count == position){
q = r-> next;
r-> next = q-> next;

q-> next = NULL;
free (q);
found = 1;
}
count ++;
r = r-> next;
}
if (found==0)
printf(“Khong tim thay vi tri can xoa !”);

}

c) Ứng dụng
#include <stdio.h>
#include <conio.h>
16


#include <iostream.h>
#include <stdlib.h>
struct node
{
int info;
node *link;
};
typedef node *list;
void create (list &first)
{
first = NULL;
}

void addt(list &first,int x)
{
node *p = new node;
p->info = x;
p->link = NULL;
if (first == NULL)
first = p;
else
{
p->link = first; // first se~ na(`m phía sau p
first = p; // thay first ba(`ng p
}
}
int check(list &first)
{
if (first == NULL)
return 1;
else
return 0;
}
void addb(list &first,int x)
17


{
node *p = new node, *qp = NULL;
p->info = x;
p->link = NULL;
if (first == NULL)
first = p;

else
{
qp = first;
node *q = qp->link;
while (q != NULL) // chay den cuoi danh sach
{
qp = q;
q = q->link;
}
qp->link = p; // chen p vào link cua nút cuoi
}
}
void add(list &q,int x) //
{
}
void remove(list &first, list &q)
{
node *p = first, *pp = NULL;
while (p != NULL && p != q)
{
pp = p;
p = p->link;
}
if (p == q)
{
pp->link = p->link;
delete q;
18



q = NULL;
}
}
void addc(list &last, int x) //
{
}
void main()
{
list first;
create(first);
addb(first,1);
addb(first,2);
addb(first,3);
addt(first,4);
addt(first,5);
addb(first,6);
list p = first;
while (p != NULL)
{
cout<<(p->info)<<" ";
p = p->link;
}
cout<getch();
}

III. Cây nhị phân
1. Định nghĩa : Là một cây nhị phân hoặc là rỗng hoặc là có 1 nút gốc và
tối đa 2 nút con bên trái và bên phải cũng là cây nhị phân


2. Cài đặt cây nhị phân bằng danh sách liên kết
• Khai báo
struct node {
int

item;

struct node *left;
struct node *right;

19


}
typedef struct node *treenode;

treenode root;

• Khởi tạo cây rỗng

void init(node *&proot)
{
proot=NULL;

};

• Tạo 1 nút mới

node* makenode(int x)
{node* p = new node;

p->info=x;
p->left=NULL;
p->right=NULL;
return p;
};

• Tạo nút gốc

Void init2(node*proot, float x)
{ proot = makenode(x);}

• Xoá cây nhị phân

Void delete (node*&proot)
{ if (proot!=NULL)
{
Deltree(prootleft);
Deltree(prootright);
Delete proot;
Proot = NULL;
}
}

• Thêm nút là vào bên trái của nút p

Void insertletf (node*p, float x)
{ if (pleft !==NULL)
{ printf(\n ben trai node p co node con”);
Return;}
Node*q = makenode(x);

pleft = q;}

• Thêm nút là vào bên phải của p

Void insertright (node*p, float x)
{
if (pright!=NULL)
{ printf(“\ ben phai p co node con”);
Return;}
Node*q = make’(x);
pright = q;}

• Duyệt thứ tự trước: (NLR – Node – Left - Right) Đầu tiên là thăm nút gốc.
Sau đó duyệt cây con bên trái, cuối cùng duyệt cây con bên phải

void

PreOrder (treenode root ) {
if (root !=NULL) {

20


printf(“%d”, root.item);
PreOrder(root.left);
PreOrder(root.right);
}
}

• Duyệt thứ tự giữa: (LNR): Duyệt cây con bên trái sau đó thăm nút gốc. Cuối

cùng duyệt cây con bên phải

void

InOrder (treenode root ) {
if (root !=NULL) {
InOrder (root.left);
printf(“%d”, root.item);
InOrder (root.right);
}

}

• Duyệt thứ tự sau: (LRN): Duyệt cây con bên trái sau đó duyệt tiếp cây con
bên phải cuối cùng là thăm nút gốc

void

PostOrder (treenode root ) {
if (root !=NULL) {
PostOrder (root.left);
PostOrder (root.right);
printf(“%d”, root.item);
}

}

IV. Cây tìm kiếm nhị phân
1. Định nghĩa: Tìm kiếm bằng cây nhị phân là một phương pháp tìm kiếm rất hiệu
quả và được xem như là một trong những thuật toán cơ sở của khoa học máy

tính. Đây cũng là một phương pháp đơn giản và được lựa chọn để áp dụng
trong rất nhiều tình huống thực tế.
Ý tưởng cơ bản của phương pháp này là xây dựng một cây nhị phân tìm kiếm. Đó
là một cây nhị phân có tính chất sau: Với mỗi nút của cây, khoá của các nút của cây con bên
trái bao giờ cũng nhỏ hơn và khoá của các nút của cây con bên phải bao giờ cũng lớn hơn
hoặc bằng khoá của nút đó.

2. Cài đặt cây tìm kiếm nhi phân
struct node {
int

item;

struct node *left;
struct node *right;

21


}
typedef struct node *treenode;
treenode tree_search(int x, treenode root){
int found=0;
treenode temp=root;
while (temp!=NULL){
if (x < temp.item) temp=temp.left;
elseif (x > temp.item)temp=temp.right;
else break;
}
return temp;

}

o Chèn phần tử vào cây nhị phân tìm kiếm
void tree_insert(int x, treenode *root){
treenode p;
p = (treenode) malloc (sizeof(struct node));
p.item=x;
p.left=p.right=NULL;
if (root==NULL)
root=p;
else if (x < root->item)
tree_insert(x, root->left)
else
tree_insert(x, root->right)
}
}

Câu 6 Định nghĩa cây nhị phân tìm kiếm, trình bày thuật toán thêm một node
vào cây nhị phân tìm kiếm, trình bày giải thuật loại bỏ một node ở cây nhị
phân tìm kiếm, trình bày giải thuật tìm node x trên cây nhị phân tìm kiếm.
TL: a.Cây nhị phân tìm kiếm là 1 cây nhị phân mà mỗi nút của nó đều được
gán 1 giá trị khóa nào đó trong các giá trị khóa đã cho và đối với mọi nút
trên cây tính chất sau đây luôn được thỏa mãn
+ Mọi khóa thuộc cây con trái nút đó đều nhỏ nhỏ hơn khóa ứng với nút đó.
+ Mọi khóa thuộc cây con phải nút đó đều lớn hơn khóa ứng với nút đó
b. Thêm một nut vào cây nhị phân tìm kiếm:
- Nếu trùng với gốc thì không thể thêm node.

22



- Nếu xbên phải.
- Nếu x>gốc và chưa có lá con bên phải thì thực hiện thêm node vào nhánh
bên phải.
if(x=proot->infor){
printf("\n nội dung bị trung");
delay(2000);return;
}
else if(x->proot-> infor&&proot->left==NULL){
select(proot,x);return;
}
else if(x->proot-> infor&&proot->right==NULL){
select(proot,x);return;
}
else if(xproot->infor)
insert(proot->left,x);
else insert(proot->right,x);
}
c. Thao tác xóa một node trên cây nhị phân tìm kiếm
/*Khi xoa mot nut P trong cay nhi phan tim kiem ta tim mot nut de thay the
nut do. Neu P la nut la thi nut thay the la nut NULL. Neu P chi co mot
cay con thi nut thay the la nut con cua no. Neu P co 2 cay con thi nut
thay the la nut trai nhat cua cay con ben phai hoac nut phai nhat cua
cay con ben trai.Ta quy uoc chon nut phai nhat cua cay con ben trai*/
void remove(node *&proot, int x)
{node *fp,*p,*f,*rp,*q; /*rp la nut thay the cho nut p co noi dung x,
f la nut cha cua nut thay the rp*/
p=search2(proot,fp,x); //fp la nut cha cua nut p
if(p==NULL) {cout<<"Khong tim thay nut x";return;}

//Nut la
if(p->right==NULL && p->left==NULL)
{if(p==proot) {delete proot;proot=NULL;return;}
if(fp->left==p) {fp->left=NULL;delete p;return;}
if(fp->right==p) {fp->right=NULL;delete p;return;}
};
//Nut chi co mot cay con trai
if(p->left!=NULL && p->right==NULL)
{if(fp->left==p) {fp->left=p->left;delete p;return;}
if(fp->right==p) {fp->right=p->left;delete p;return;}
23


}
//Nut chi co mot cay con phai
if(p->left==NULL && p->right!=NULL)
{if(fp->left==p) {fp->left=p->right;delete p;return;}
if(fp->right==p) {fp->right=p->right;delete p;return;}
};
//Nut p co 2 nut con
//Tim nut thay the, la nut phai nhat cua cay con trai
f=p;
rp=p->left;
while(rp->right!=NULL) {f=rp;rp=rp->right;}
f->right=rp->left;/*rp la phai nhat, do do khong co con phai
vi khong con rp nen nut cha phai chi den nut sau do*/
p->info=rp->info;
//doi noi dung cua p va rp, roi xoa rp
delete rp;
}


V.Đồ thị
+ Đồ thị G = <V,E> là đồ thị đơn  với mọi u,v thuộc V sao cho tồn tại
nhiều nhất một cạnh
+ Đồ thị G = <V,E> là đa đồ thị  tồn tại u, v thuộc V sao cho có nhiều
hơn một cạnh

Ví dụ:

Hình 1

1. Biểu diễn đồ thị:

a) Ma trận kề:: Biểu diến đồ thị bằng ma trận vuông cấp n có các phần tử
G = <V,E> như hình vẽ :

24


+ Đồ thị vô hướng

-

MTK của đồ thị vô hướng là đối xứng (Aij = Aji)

-

Tổng các phần tử của ma trận bằng 2 lần số cạnh của đồ thị

-


Tổng các phần tử của hàng (i) hoặc cột thứ (i) chính bằng số các cạnh nối với đỉnh i
Ma trận kề: A = (Aij)

1
2
3
4
5
6
7
8
9
10
-----------------------------------------------------------------------------------------------------------1
0
1
1
1
0
0
0
0
0
0
2
1
0
1
0

0
0
1
0
0
0
3
1
1
0
1
1
1
1
0
0
0
4
1
0
1
0
1
0
0
0
0
0
A=
5

0
0
1
1
0
1
0
0
1
0
6
0
0
1
0
1
0
1
1
1
1
7
0
1
1
0
0
1
0
1

0
0
8
0
0
0
0
0
1
1
0
0
1
9
0
0
0
0
1
1
0
0
0
1
10
0
0
0
0
0

1
0
1
1
0
+ Đồ thị có hướng

1
2
3
4
5
6
-----------------------------------------------------------------------------------------------------------1
2
3
4
5
6

0
1
1
0
0
0

1
0
1

0
0
0

0
0
0
0
1
0

0
0
1
0
0
1

25

0
1
0
1
0
0

0
0
0

0
1
0


×