Tải bản đầy đủ (.pdf) (121 trang)

giáo trình cấu trúc dữ liệu 2

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 (3.52 MB, 121 trang )


5
6
S
ắp thứ tự ngoại l
à s
ắp thứ tự tr
ên t
ập tin. Khác với sắp xếp d
ãy trên
b
ộ nhớ có số l
ư
ợng phần tử nhỏ v
à truy xu
ất nhanh, tập tin có thể
có s
ố l
ư
ợng phần tử rất lớn v
à th
ời gian truy xuất chậm. Do vậy việc
s
ắp xếp tr
ên các c
ấu trúc dữ liệu loại tập
tin đ
òi h
ỏi phải áp dụng các
phương pháp đ
ặc biệt.


Chương này s
ẽ giới thiệu một số ph
ương pháp như sau:

Phương pháp tr
ộn Run

Phương pháp tr
ộn tự nhi
ên

Phương pháp tr
ộn đa lối cân bằng (balanced multiway merging)

Phương pháp tr
ộn đa pha (Polyphase Merge)
1.
P
HƯƠNG PHÁP TR
ỘN RUN
Khái ni
ệm c
ơ b
ản
Run là m
ột d
ãy liên ti
ếp các phần tử đ
ư
ợc sắp thứ tự.

Ví d
ụ 1 2 3 4 5 l
à m
ột run gồm có năm phần tử
Chi
ều d
ài run chính là s
ố phần tử trong run. Chẳng hạn, run
trong ví d
ụ tr
ên có chi
ều d
ài là 5.
Như v
ậy, mỗi phần tử c
ủa d
ãy có th
ể xem nh
ư là m
ột run có
chi
ều d
ài là 1. Hay nói khác đi, m
ỗi phần tử của d
ãy chính là
m
ột run có chiều d
ài b
ằng 1.
Vi

ệc tạo ra một run mới từ hai run ban đầu gọi l
à tr
ộn run
(merge). Hi
ển nhi
ên, run đư
ợc tạo từ hai run ban đầu l
à m
ột d
ãy
các ph
ần tử đ
ã
đư
ợc sắp thứ tự.
Gi
ải thuật
Gi
ải thuật sắp xếp tập tin bằng ph
ương pháp tr
ộn run có thể tóm

ợc nh
ư sau:
Input
:
f0 là t
ập tin cần sắp thứ tự.
Output
:

f0 là t
ập tin đ
ã
đư
ợc sắp thứ tự.
G
ọi f1, f2 l
à hai t
ập tin trộn.
Các t
ập tin f0, f1, f2 có t
h
ể l
à các t
ập tin tuần tự (text file) hay có
th
ể l
à các t
ập tin truy xuất ngẫu nhi
ên (File of <ki
ểu>)

ớc 1
-
Gi
ả sử các phần tử tr
ên f0 là:
24 12 67 33 58 42 11 34 29 31
-
f1 ban đ

ầu rỗng, v
à f2 ban đ
ầu cũng rỗng.
-
Th
ực hiện phân bố m = 1 phần tử lần l
ư
ợt từ f0 v
ào f1 và f2:
f1: 24 67 58 11 29
f0:
24
12
67 33 58 42 11 34 29 31
f2: 12 33 42 34 31
-
Tr
ộn f1, f2 th
ành f0:
f0: 12 24 33 67 42 58 11 34 29 31

ớc 2
-
Phân b
ố m = 2 phần tử lần l
ư
ợt từ f0 v
ào f1 và f2:
f1: 12 24 42 58 29 31
f0:

12 24
33 6
7
42 58 11 34 29 31
f2: 33 67 11 34
CH
ƯƠ
NG 1
-
S
ẮP THỨ TỰ NGOẠI
1
7
8
-
Tr
ộn f1, f2 th
ành f0:
f
1:
12 24
42 58
29 31
f0:
12 24
33 67
11 34
42 58
29 31
f2:

33 67
11 34

ớc 3
-
Tương t
ự b
ư
ớc 2, phân bố m=4 phần tử lần l
ư
ợt từ f0 v
ào f1 và
f2, k
ết quả thu đ
ư
ợc nh
ư sau:
f1:
12 24 33 67
29 3
1
f2:
11 34 42 58
-
Tr
ộn f1, f2 th
ành f0:
f0:
11 12 24 33 34 42 58 67
29 31


ớc 4
-
Phân b
ố m = 8 phần tử lần l
ư
ợt từ f0 v
ào f1 và f2:
f1: 11 12 24 33 34 42 58 67
f2: 29 31
-
Tr
ộn f1, f2 th
ành f0:
f0: 11 12 24 29 31 33 34 42 58 67 29

ớc 5
L
ặp lại t
ương
t
ự các b
ư
ớc tr
ên, cho đ
ến khi chiều d
ài m c
ủa run cần
phân b
ổ lớn h

ơn chi
ều d
ài n c
ủa f0 th
ì d
ừng. Lúc n
ày f0 đ
ã
đư
ợc sắp
th
ứ tự xong.
Cài đ
ặt
/*



Sap xep file bang phuong phap tron truc tiep
Cai dat bang Borland C 3.1 for DOS.


*/
#include <conio.h>
#
include <stdio.h>
void tao_file(void);
void xuat_file(void);
void chia(FILE *a,FILE *b,FILE *c,int p);
void tron(FILE *b,FILE *c,FILE *a,int p);

int p,n;
/*



*/
void main (void)
{
FILE *a,*b,*c;
clrscr();
tao_file();
xuat_file();
p = 1;
while (
p < n)
{
chia(a,b,c,p);
tron(b,c,a,p);
p=2*p;
}
printf("
\
n");
xuat_file();
getch();
}
void tao_file(void)
9
10
/*




Tao file co n phan tu



*/
{
int i,x;
FILE *fp;
fp=fopen("d:
\
\
ctdl
\
\
sorfile
\
bang.int","wb");
printf("Cho b
iet so phan tu : ");
scanf("%d",&n);
for (i=0;i<n;i++)
{
scanf("%d",&x);
fprintf(fp,"%3d",x);
}
fclose(fp);
}

void xuat_file(void)
/*



Hien thi noi dung cua file len man hinh



*/
{
int x;
FILE *fp;
fp=fopen("d:
\
\
ctdl
\
\
sort
file
\
bang.int","rb");
i=0;
while (i<n)
{
fscanf(fp,"%d",&x);
printf("%3d",x);
i++;
}

fclose(fp);
}
void chia(FILE *a,FILE *b,FILE *c,int p)
/*



Chia xoay vong file a cho file b va file c moi lan p phan tu cho den khi het
fil
e a.



*/
{
int dem,x;
a=fopen("d:
\
ctdl
\
sortfile
\
bang.int","rb");
b=fopen("d:
\
ctdl
\
sortfile
\
bang1.int","wb");

c=fopen("d:
\
ctdl
\
sortfile
\
bang2","wb");
while (!feof(a))
{
/*
Chia p phan tu cho b
*/
dem=0;
while ((dem<p) && (!feof
(a)))
{
fscanf(a,"%3d",&x);
fprintf(b,"%3d",x);
dem++;
}
/*
Chia p phan tu cho c
*/
11
12
dem=0;
while ((dem<p) && (!feof(a)))
{
fscanf(a,"%3d",&x);
fprintf(c,"%3d",x);

dem++;
}
}
fclose(a); fclose(b); fclose(c);
}
v
oid tron(FILE *b,FILE *c,FILE *a,int p)
/*



Tron p phan tu tren b voi p phan tu tren c thanh 2*p phan tu tren a
cho den khi file b hoac c het.



*/
{
int stop,x,y,l,r;
a=fopen("d:
\
ctdl
\
sortfile
\
bang.int","wb");
b=fopen("d:
\
ctdl
\

sortfile
\
bang1.int","rb
");
c=fopen("d:
\
ctdl
\
sortfile
\
bang2.int","rb");
while ((!feof(b)) && (!feof(c)))
{
l=0;/*
so phan tu cua b da ghi len
a*/
r=0;/*
so phan tu cua c da ghi len a
*/
fscanf(b,"%3d",&x);
fscanf(c,"%3d",&y);
stop=0;
while
((l!=p) && (r!=p) && (!stop))
{
if (x<y)
{
fprintf(a,"%3d",x);
l++;
if ((l<p) && (!feof(b)))

/*
chua du p phan tu va chua het file b
*/
fscanf(b,"%3d",&x);
else
{
fprintf(a,"%3d",y);
r++;
if (feof(
b))
stop=1;
}
}
else
{
fprintf(a,"%3d",y);
r++;
if ((r<p) && (!feof(c)))
/*
chua du p phan tu va chua het file c
*/
fscanf(c,"%3d",&y);
else
{
fprintf(a,"%3d",x);
13
14
l++;
if (feof(c))
stop=1;

}
}
}
/*



Chep phan con lai cua p phan tu tren b len a



*/
while ((!feof(b)) && (l<p))
{
fscanf(b,"%3d",&x);
fprintf(a,"%3d",x);
l++;
}
/*



Chep phan con lai cua p phan tu tren c len a



*/
while ((!feof(c)) && (r<p))
{
fscanf(c,"%3d",&y);

fprintf(a,"%3d",y);
r++;
}
}
if (!feof(b))
{
/*
chep phan con lai cua b len a
*/
while (!feof(b))
{
fscanf(b,"%3d",&x);
fprintf(a,"%3d",x);
}
}
if (!feof(c))
{
/*
chep phan con la
i cua c len
a*/
while (!feof(c))
{
fscanf(c,"%3d",&x);
fprintf(a,"%3d",x);
}
}
fclose(a); fclose(b); fclose(c);
}
2.

PHƯƠNG PHÁP TR
ỘN TỰ NHI
ÊN.
Gi
ải thuật
Trong phương pháp tr
ộn đ
ã trình bày
ở tr
ên, gi
ải thuật không tận
d
ụng đ
ư
ợc ch
i
ều d
ài c
ực đại của các run tr
ư
ớc khi phân bổ; do vậy,
vi
ệc tối
ưu thu
ật toán ch
ưa đư
ợc tận dụng.
Đ
ặc điểm c
ơ b

ản của ph
ương pháp tr
ộn tự nhi
ên là t
ận dụng độ d
ài
“t
ự nhi
ên” c
ủa các run ban đầu; nghĩa l
à, th
ực hiện việc trộn các run
có đ
ộ d
ài c
ực đại v
ơi n
hau cho đ
ến khi d
ãy ch
ỉ bao gồm một run:
dãy
đ
ã
đư
ợc sắp thứ tự.
15
16
Input
:

f0 là t
ập tin cần sắp thứ tự.
Output
:
f0 là t
ập tin đ
ã
đư
ợc sắp thứ tự.
L
ặp
Cho đ
ến khi d
ãy c
ần sắp chỉ gồm duy nhất một run.
Phân b

-
Chép m
ột dây con có thứ tự v
ào t
ập tin phụ fi
(I >= 1).
Khi ch
ấm dứt dây con n
ày, bi
ến eor (end of run) có giá trị True.
-
Chép dãy con có th
ứ tự kế tiếp v

ào t
ập tin phụ kế tiếp fi+1 (xoay
vòng).
-
Vi
ệc phân bố kết thúc khi kết thúc tập tin cần sắp f0.
Tr
ộn
-
Tr
ộn 1 run trong f1 v
à1 run t
rong f2 vào f0.
-
Vi
ệc trộn kết thúc khi duyệt hết f1 v
à h
ết f2 (hay nói cách khác,
vi
ệc trộn kết thúc khi đ
ã có
đ
ủ n phần tử cần chép v
ào f0).
Cài đ
ặt
/*




Sap xep file bang phuong phap tron tu nhien


*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <iostream.h>
void CreatFile(FILE *Ft,int);
void ListFile(FILE *);
void Distribute();
void Copy(FILE *,FILE *);
void CopyRun(FILE *,FILE *);
void MergeRun();
void Merge();
//
typedef int DataType;
FILE *F0,*F1,*F2;
int M,N,Eor;
/*

Bien eor dung de kiem tra ket thuc Run hoac File


*/
DataType X1,X2,X,Y;
//
Ham main
void main(void)
{

clrscr();
randomize();
cout<<" Nhap so phan tu: ";
cin>>N;
CreatFile(F0,N);
ListFile(F0);
do
{
F0=fopen("d:
\
\
ctdl
\
\
sortfile
\
\
bang.int","rb");
F
1=fopen("d:
\
\
ctdl
\
\
sortfile
\
\
bang1.int","wb");
17

18
F2=fopen("d:
\
\
ctdl
\
\
sortfile
\
\
bang2.int","wb");
Distribute();
F0=fopen("d:
\
\
ctdl
\
\
sortfile
\
\
bang.int","wb");
F1=fopen("d:
\
\
ctdl
\
\
sortfile
\

\
bang1.int","rb");
F2=fopen("d:
\
\
ctdl
\
\
sortfile
\
\
bang2.int","rb");
M=0;
Merge();
}while (M != 1);
ListFile(F0);
getch();
}
void CreatFile(FILE *Ft,int Num)
/*
Tao file co ngau nhien n phan tu* */
{
randomize();
Ft=fopen("d:
\
\
ctdl
\
\
sortfile

\
\
bang.int","wb");
for( int i = 0 ; i < Num ; i++)
{
X = random(
30);
fprintf(Ft,"%3d",X);
}
fclose(Ft);
}
void ListFile(FILE *Ft)
/*
Hien thi noi dung cua file len man hinh
*/
{
DataType X,I=0;
Ft = fopen("d:
\
\
ctdl
\
\
sortfile
\
\
bang.int","rb");
while ( I < N )
{
fscanf(Ft,"%3d",&X);

cout<<"
"<<X;
I++;
}
printf("
\
n
\
n");
fclose(Ft);
}
/*
*/
void Copy(FILE *Fi,FILE *Fj)
{
//Doc phan tu X tu Tap tin Fi, ghi X vao Fj
//Eor==1, Neu het Run(tren Fi) hoac het File Fi
fscanf(Fi,"%3d",&X);
fprintf(Fj,"%3d",X);
if( !feof(Fi) )
{
fscanf(Fi,"%3d",&Y);
long curpos = ftell(Fi)
-
2;
fseek(Fi, curpos, SEEK_SET);
}
if ( feof(Fi) ) Eor = 1;
else Eor = (X > Y) ? 1 : 0 ;
}

19
20
void Distribute()
/*
Phan bo luan phien cac Run tu nhien tu F0 vao F1 va F2
*/
{
do
{
CopyRun(F0,F1);
if(
!feof(F0) ) CopyRun(F0,F2);
}while( !feof(F0) );
fclose(F0);
fclose(F1);
fclose(F2);
}
void CopyRun(FILE *Fi,FILE *Fj)
/*
Chep 1 Run tu Fi vao Fj
*/
{
do
Copy(Fi,Fj);
while ( !Eor);
}
void MergeRun()
/*
Tron 1 Run cua F1 va F2 vao F0
*/

{
do
{
fscanf(F1,"%3d",&X1);
long curpos = ftell(F1)
-
2;
fseek(F1, curpos, SEEK_SET);
fscanf(F2,"%3d",&X2);
curpos = ftell(F2)
-
2;
fseek(F2, curpos, SEEK_SET);
if( X1 <= X2 )
{
Copy(F1,F0);
if (Eor) CopyRun(F2,F0);
}
else
{
Copy(F2
,F0);
if ( Eor ) CopyRun(F1,F0);
}
} while ( !Eor );
}
void Merge()
/*
Tron cac run tu F1 va F2 vao F0
*/

{
while( (!feof(F1)) && (!feof(F2)) )
{
MergeRun();
M++;
}
while( !feof(F1) )
{
21
22
CopyRun(F1,F0);
M++;
}
while( !feof(F2) )
{
CopyRun(F2,F0);
M++;
}
fclose(F0);
fclose(F1);
fclose(F2);
}
3.
PHƯƠNG PHÁP TR
ỘN ĐA LỐI CÂN BẰNG
(Balanced MultiWay Merging)
Gi
ải thuật
Các phương pháp đ
ã trình bày

ở tr
ên ch
ủ yếu dựa tr
ên hai thao tác:
phân ph
ối

tr
ộn
các run. Th
ời gian thực thi các ph
ương pháp này
ch
ủ yếu bị chi phối bởi thời gian phân phối các run
t
ừ tập tin f0 v
ào
các t
ập tin phụ f1 v
à f2.
Phương pháp tr
ộn đa lối cân bằng sẽ khắc phục đ
ư
ợc nh
ư
ợc điểm
này.
G
ọi
F

= { f1, f2, … , fn } là t
ập các file nguồn
G
= { g1, g2, …, gn } là t

p các file đích
Phân ph

i các run trên file c

n s

p x
ế
p
cho các file thu

c t

p
các file ngu

n ;
do
{
Hoán đ

i vai trò c

a t


p các file ngu

n và t

p các file đích ;
Tr

n t

ng b

run trên các file ngu

n và đ
ư
a vào các file đích ;
} while ( t

ng s

run trên các file đích > 1 ) ;
M

t s

qui
ư

c

N
: t

p các f
ile ngu

n
S
: t

p các file ngu

n tham gia vào quá trình tr

n đ

t

o thành m

t run cho file đích.
Q
: t

p các file ngu

n còn run
đang x

lý.

D
: t

p các file đích
D
: t

p các file đích đ
ã
đ
ư

c phân ph

i m

t đ
ư

ng
ch

y trong “tua” hi

n hành .
Khi t

t c

các file đích đ

ã
đ
ư

c phân ph

i m

t run thì h
ế
t m

t tua.
B
ư

c 1
N
= { f1, f2, … , fn }
D
= { g1, g2, …., gn }
//
Phân ph

i xoay vòng các run c

a file
F
( file c


n s

p x
ế
p)
cho các file thu

c
N
i = 1 ;
while ( ! feof (
F
))
{

L

y 1
run c

a
F
và phân ph

i cho fi

i = ( i mod n ) + 1 ;
}
23
24

S
=
N
; // t

t c

các file ngu

n đ

u tham gia vào quá trình
tr

n.
D
= {} ; // ch
ư
a có file đích nào đ
ư

c phân ph

i run.
l
= 0 ; // đ
ế
m s

run trên các t


p đích.
B
ư

c 2
a.
L

y m

t file đích trong (
D
-
D
) là t
ập các file đích
ch
ư
a đ
ư
ợc
phân ph

i trong “tua” hi

n hành ,
và g
ọi nó l
à file

đích hi
ện h
ành Dh ( t
ức sẽ đ
ư
ợc
phân ph

i run ).
Q
=
S
;
b.
xa
=
Min
{
xa
/
a

Q
} // ph

n t

x trên file
a
0

0
c
.
Copy
xa
lên
Dh
0
d.
if ( file ngu

n
a
0
h
ế
t )
{
Q
=
Q

{
a
0
}
S
=
S


{
a
0
}
if (
S
= {} )
// xong quá trình tr

n t

ngu

n đ
ế
n đích
{
l
++ ;
D
=
D
+ {Dh
Goto b
ư

c 3
// hoán đ

i vai trò các file : F



G
}
else
{
if
Q

{}
Goto b
ư

c 2.b
else //
Q
=
{}, b

run hi

n t

i đ
ã
tr

n xong
{
l

++ ;
D
=
D
+ {Dh
}
if (
D
=
D
)
D
= {} // xong m
ột tua
Goto
b
ư

c 2.a
}
}
}
else // file ngu

n
a
0
ch
ư
a

h
ế
t
{
if ( h
ế
t run hi

n t

i trên
a
0
)
{
Q
=
Q

{
a
0
}
if
Q

{}
Goto b
ư


c 2.b
else //
Q
=
{}, b

run
hi

n t

i đ
ã tr

n xong
{
l
++ ;
D
=
D
+ {Dh
}
if (
D
=
D
)
25
26

D
= {} // xong m
ột tua
Goto
b
ư

c 2.a
}
}
else // run hi

n t

i trên
a
0
ch
ư
a h
ế
t, ti
ế
p t

c
tìm
Min
Goto b
ư


c 2.b
}
B
ư

c 3
if (
l
= 1 )
STOP ;
else
{
if (
l <
n )
S
=
D
;
// không đ

run đ

phân ph

i
cho n file
else
S

=
D
;
D
= {}
l
= 0
N


D
Goto b
ư

c 2
}
Cài đ
ặt
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*CT Sap xep t
ren file theo phuong phap tron n duong
can bang.
Du lieu co the la 1 file gom n so tao ngau nhien,
hoac la file "Input.Cpp" trong cung thu muc voi CT
Co in file (so phan tu it) trong moi buoc sap xep.
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*
/
#include <stdlib.h>
#include <conio.h>
#include <stdio.h>

#include <io.h>
#include <string.h>
#include <time.h>
#define FALSE 0
#define TRUE !FALSE
#define FILE_INPUT "Input.Cpp"
typedef struct
{
int Giatri;
int ThuocFile;
} Kieu_Xa;
//Các
hàm s
ử dụng
void TaoFileDuLieu (void);
void DocFile_Input__TaoFileDuLieu (void);
void Display_Run_1File (char *filenamePtr);
void InCacFile (char *TenCacFile [10]);
void Buoc_1 (void);
27
28
void Buoc_2 (void);
void Buoc_2a (void);
void Buoc_2bcd (FILE
*file_Dhh);
void Buoc_3 (void);
int HetFile (FILE *f);
int XemCur (FILE *f);
void Copy_run (FILE *f, FILE *fx);
int Copy_element (FILE *f, FILE *fx);

int KiemTraRong (int *DC_Mang);
void SetRong_Dhoa (void);
void HoanDoi2TapHopTenFile (char *T
enCacFile_A[10],
char *TenCacFile_B[10]);
void CapNhatDbongTruDhoa (void);
/*

Cac Bien Toan Cuc

*/
int n;
FILE *TapCacFile_F[10], *TapCacFile_G[10];
int Tap_N[10], Tap_Dbong[10], Tap_S[10], Tap_Q[10],
Tap_Dhoa[10], Tap_Dbo
ngTruDhoa[10] ;
/* Neu Tap_N[i] = 1 la file fi thuoc tap N, neu = 0 la
khong thuoc */
char *TenCacFile_F[10] = { "File_F0", "File_F1",
"File_F2", "File_F3", "File_F4", "File_F5", "File_F6",
"File_F7",
"File_F8", "File_F9" },
*TenCacFile_G[10] = { "F
ile_G0", "File_G1", "File_G2",
"File_G3","File_G4","File_G5","File_G6","File_G7","File
_G8", "File_G9" };
int l; /* so run tren cac tap dich*/
int Dhh = 0; /* De biet file dich hien hanh,vd Dhh
= 1 thi file g1 la file dich hien hanh. */
in

t SoLanHoanDoi_F_G = 0;
/*

*/
void main ()
{
int MuonChon;
char *filenamePtr;
char filename[13];
clrscr();
printf ("
\
r
\
n 1. TAO FILE DU LIEU NGAU NHIEN");
printf ("
\
r
\
n 2. DOC DU LIEU TU
FILE");
printf ("
\
r
\
n
\
n Muon chon : ");
fflush (stdin); scanf("%d", &MuonChon);
switch (MuonChon)

{
case 1 : TaoFileDuLieu (); break;
case 2 : DocFile_Input__TaoFileDuLieu ();
break;
}
strcpy (filename, "FileDL");
filenamePtr = filename;
pr
intf("
\
nn la so luong file nguon luc bat dau
:
\
n");
printf ("Xin nhap n < 8
\
n");
printf ("n : ");
29
30
scanf ("%d", &n);
printf ("
\
nf : "); Display_Run_1File(filenamePtr);
printf ("
\
n
\
n
\

n"); getch();
printf ("
\
n XIN CHO : DANG SAP XEP
\
n");
B
uoc_1 ();
do
{
Buoc_2 ();
} while (l > 1);
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham tao file du lieu gom n so nguyen duoc phat sinh
ngau nhien. */
/*

*/
void TaoFileDuLie
u (void)
{
FILE *f;
int n, dem, temp;
char filename[13];
strcpy (filename, "FileDL");
if ((f = fopen(filename, "w+b")) == NULL)
{
printf ("Khong tao duoc file %s
\

n", filename);
getch();
}
else
{printf("Xin nhap so phan tu cua file du li
eu : ");
scanf ("%d", &n);
randomize();
dem = 0;
while (dem < n)
{
temp = random (n); //Tao so ngau nhien, 0 <
gia tri so < n
fwrite (&temp, sizeof(int), 1, f);
dem++;
}
}
fclose (f);
printf ("
\
nDa tao xong file du lieu co %d phan
tu.
\
n", n);
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham doc file input de tao file du lieu. */
/*

*/

void DocFile_Input__TaoFileDuLieu ()
{
FILE *fptr, *f;
char filename[13];
int n, temp;
if ((fptr = fopen(FILE_INPUT, "rt")) == NULL)
{
printf ("Khong co file %s
\
n", FILE_INPUT);
getch();
31
32
}
else
{
strcpy (filename, "FileDL");
if ((f = fopen(filename, "w+b")) == NULL)
{
printf ("Khong tao duoc file %s
\
n",
f
ilename);
getch();
}
else
{ n = 0;
while (!feof(fptr))
{

fscanf (fptr, "%d ", &temp);
fwrite (&temp, sizeof(int), 1, f);
n++;
}
fclose (fptr);
fclose (f);
printf ("
\
nDa tao xong file du lieu co %d
phan tu.
\
n", n);
}
}
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham hien thi mot file len man hinh, co phan cach
giua cac run. */
/*

*/
void Display_Run_1File (char *filenamePtr)
{
int t
emp, cur, EndOfRun ;
FILE *f;
char filename[13];
int stt; // De kiem tra lai co bi mat ptu nao
trong luc sap xep ?
strcpy (filename, filenamePtr);

if ((f = fopen(filename, "rb")) == NULL)
{
printf ("Khong co file %s
\
n", filename);
getch()
; exit(1);
}
else
{ stt = 0;
while (!HetFile (f))
{ fread (&temp, sizeof(int), 1, f);
printf ("%d ", temp);
stt++;
if (!HetFile (f))
{
cur = XemCur (f);
EndOfRun = (temp > cur);
if (EndOfRun)
printf ("
-
");
}
else
break;
}
33
34
fclose (f);
}

}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham nhan vao mot tap hop cac ten file va hien thi
cac file nay len man hinh, co phan cach giua cac run.*/
/*


*/
void InCacFile (char *TenCacFile [10])
{
char *filenamePtr;
char filename[13];
int i;
for (i= 1; i<= n; i++)
{
strcpy (filename, TenCacFile[i]);
filenamePtr = filename;
printf ("
\
n%s : ", TenCacFile[i]);
Display_Run_1File (filenamePtr);
}
}
/*

*/
void Buoc_1 ()
{
FILE *FileDL;
int i;

for (i= 1; i<= n; i++)
Tap_N[i] = 1;
for (i= 1; i<= n; i++)
Tap_Dbong[i] = 1;
if ((FileDL = fopen("FileDL"
, "rb")) == NULL)
{
printf ("Khong co file %s
\
n","FileDL");
getch(); exit(1);
}
for (i= 1; i<= n; i++)
if ((TapCacFile_F[i] = fopen(TenCacFile_F[i],
"w+b"))
== NULL)
{
printf ("Khong co file %s
\
n",TenCacFile_F[i]);
getch(); exit(1);
}
while (!HetFile (FileDL))
{ for (i= 1; i<= n; i++)
if (Tap_N[i] == 1)
Copy_run (FileDL, TapCacFile_F[i]);
}
for (i= 1; i<= n; i++)
Tap_S[i] = Tap_N[i]
;

fclose (FileDL);
for (i= 1; i<= n; i++)
35
36
fclose (TapCacFile_F[i]);
InCacFile (TenCacFile_F);
printf ("
\
n");
getch();
}
/*

*/
void Buoc_2 ()
{
int i;
printf ("
\
nTRON LAN %d :", SoLanHoanDoi
_F_G +1);
// de in cac file luc dang sap, DL it
for (i= 1; i<= n; i++)
if ((TapCacFile_F[i] = fopen(TenCacFile_F[i],
"r+b")) == NULL)
{
printf ("Khong co file
\
n",TenCacFile_F[i]);
getch(); exit(1);

}
for (i= 1; i<= n; i++)
if ((TapC
acFile_G[i] = fopen(TenCacFile_G[i],
"w+b")) == NULL)
{
printf ("Khong co file %s
\
n",TenCacFile_G[i]);
getch(); exit(1);
}
SetRong_Dhoa ();
l = 0;
Dhh = 0;
Buoc_2a ();
}
/*

*/
void Buoc_2a
()
{
int i;
FILE *file_Dhh;
Dhh++;
CapNhatDbongTruDhoa();
while (Dhh <= n)
if (Tap_DbongTruDhoa[Dhh] == 1)
break;
else

Dhh++;
// Lay file dich hien hanh
switch (Dhh)
{
case 1 : file_Dhh = TapCacFile_G[1]; break;
case 2 : file_D
hh = TapCacFile_G[2]; break;
case 3 : file_Dhh = TapCacFile_G[3]; break;
case 4 : file_Dhh = TapCacFile_G[4]; break;
case 5 : file_Dhh = TapCacFile_G[5]; break;
case 6 : file_Dhh = TapCacFile_G[6]; break;
37
38
case 7 : file_Dhh = TapCacFile_G[7]; brea
k;
case 8 : file_Dhh = TapCacFile_G[8]; break;
case 9 : file_Dhh = TapCacFile_G[9]; break;
default: file_Dhh = NULL;
}
for (i= 1; i<= n; i++)
Tap_Q[i] = Tap_S[i];
while (!KiemTraRong (Tap_Q))
Buoc_2bcd (file_Dhh);
}
/*++++++++++++++++++++++
+++++++++++++++++++++++++++++*/
/* Tim phan tu Xa0 la Min cua cac phan tu Xa tren cac
file a thuoc tap Q, Chep Xa0 sang file dich hien hanh.
Cap nhat lai cac thong tin lien quan.*/
/*



*/
void Buoc_2bcd (FILE *file_Dhh)
{
int i, num;
Kieu_Xa CacPT_Xa[10], Xa0; // phan tu Xa0
int EOR = 0; // End of run de theo doi run
hien tai tren file a0.
FILE * file_a0;
/*

Buoc_2b


*/
num = 1; // bat dau voi CacPT_Xa[1]
for (i= 1; i<= n; i++)
if (Tap_Q[i] == 1)
{
CacPT_Xa[num].Giatri = XemCur
(TapCacFile_F[i]);
CacPT_Xa[num].ThuocFile = i;
num++;
}
Xa0.Giatri = CacPT_Xa[1].Giatri;
Xa0.ThuocFile = CacPT_Xa[
1].ThuocFile;
for (i= 2; i< num; i++)
if (CacPT_Xa[i].Giatri < Xa0.Giatri)

{
Xa0.Giatri = CacPT_Xa[i].Giatri;
Xa0.ThuocFile = CacPT_Xa[i].ThuocFile;
}
/*

Buoc_2c

*/
/*
Copy Xa0 len file dich hien hanh (f
ile_Dhh).*/
switch (Xa0.ThuocFile)
{
case 1 : file_a0 = TapCacFile_F[1]; break;
case 2 : file_a0 = TapCacFile_F[2]; break;
case 3 : file_a0 = TapCacFile_F[3]; break;
case 4 : file_a0 = TapCacFile_F[4]; break;
case 5 : file_a0 = TapCacFile_F[5];
break;
case 6 : file_a0 = TapCacFile_F[6]; break;
case 7 : file_a0 = TapCacFile_F[7]; break;
case 8 : file_a0 = TapCacFile_F[8]; break;
39
40
case 9 : file_a0 = TapCacFile_F[9]; break;
}
EOR = Copy_element (file_a0, file_Dhh);
/*


Buoc_2d

*/
if (HetFile(file_a0)) // File nguon a0
het
{
Tap_Q[Xa0.ThuocFile] = 0;
Tap_S[Xa0.ThuocFile] = 0;
if (KiemTraRong (Tap_S)) // Xong qua trinh tron
tu Nguon den Dich
{
l++;
Tap_Dhoa[Dhh] = 1;
Buoc_3
();// Neu chua sap xong se F <

> G
}
else
if (KiemTraRong (Tap_Q)) // Q = {} , Bo run
hien tai da tron xong
{
l++;
Tap_Dhoa[Dhh] = 1;
CapNhatDbongTruDhoa();
if (KiemTraRong (Tap_DbongTruDhoa))
// Dhoa = Dbong
{
SetRong_D
hoa();// Xong 1 tua

Dhh = 0;
}
Buoc_2a ();
}
}
else // file nguon a0 chua het
{
if (EOR) // Het run hien tai tren file_a0
{
Tap_Q[Xa0.ThuocFile] = 0;
if (KiemTraRong (Tap_Q)) // Q = {} , Bo run
hien tai da tron xong
{ l++;
Tap_Dhoa[Dhh] = 1;
CapNhatDbongTruDhoa();
if (KiemTraRong (Tap_DbongTruDhoa))
{
SetRong_Dhoa();
Dhh = 0;
}
Buoc_2a ();
}
}
}
}
/*

*/
void Buoc_3 ()
{

int
i;
for (i= 1; i<= n; i++)
fclose (TapCacFile_F[i]);
41
42
for (i= 1; i<= n; i++)
fclose (TapCacFile_G[i]);
InCacFile (TenCacFile_G);
printf ("
\
n");
if (l == 1)
{
printf ("
\
n Con %d run ", l);
printf ("
\
n DA SAP XEP XONG
\
n");
g
etch();
}
else
{
if (l < n) // Khong du run de phan phoi cho n
file.
for (i= 1; i<= n; i++)

Tap_S[i] = Tap_Dhoa[i];
else
for (i= 1; i<= n; i++)
Tap_S[i] = Tap_Dbong[i];
// Bat dau lan tron moi
printf("
\
n Con %d run ", l);
HoanDoi2TapHopTenFile (TenCacFile_F,
TenCacFile_G);
SoLanHoanDoi_F_G++;
printf ("
\
n Hoan doi F <

> G lan %d
\
n",
SoLanHoanDoi_F_G);
printf ("Xin an phim bat ky de sap xep tiep.
\
n");
getch();
}
}
/*++++++++++++++++++++++++++++++++++++++++++
+++++++++*/
/* Ham tra ve 1 khi con tro file dat tai EOF (se doc
chu chua doc, nen khac ham feof co san ), nguoc lai tra
ve 0; dung cho file so int, kieu binary.*/

/*

*/
int HetFile (FILE *f)
{
int te
mp, Het;
fread (&temp, sizeof(int), 1, f);
if (feof(f))
Het = 1;
else
{
Het = 0;
fseek (f,
-
2, SEEK_CUR);
}
return (Het);
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham tra ve gia tri so xem duoc, nhung con tro file
khong di c
huyen toi nhu ham fread, neu gap EOF se tra
ve EOF.Dung cho file so int, kieu binary.
/*

*/
int XemCur(FILE *f)
43
44

{
int temp, Het;
fread (&temp, sizeof(int), 1, f);
if (feof(f))
temp = EOF;
fseek (f,
-
2, SEEK_CUR);
return (temp);
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham copy 1 run hien tai cua file f sang file fx.*/
/*

*/
void Copy_run (FILE *f, FILE *f
x)
{
int EndOfRun, temp;
EndOfRun = FALSE;
while (!EndOfRun)
EndOfRun = Copy_element (f, fx);
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham copy phan tu hien hanh cua file f sang file fx
va kiem tra cuoi run :
chep xong ptu cuoi
cua run ham se tra ve EndOfRun la 1,
nguoc lai se tra
ve 0 . */

/*

*/
int Copy_element (FILE *f, FILE *fx)
{
int EndOfRun, temp, next;
if (!HetFile (f))
{ fread (&temp, sizeof(int), 1, f);
fwrite (&temp, sizeof(int), 1, fx);
if (!HetFile (f))
{
next = XemCur (f);
EndOfRun = (temp > next);
}
else
EndOfRun = TRUE;
}
else
EndOfRun = TRUE;
return (EndOfRun);
}
/*+++++
++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham tra ve TRUE neu tat ca cac phan tu cua mang la
0, nguoc lai tra ve FALSE. */
/*

*/
i
nt KiemTraRong (int *DC_Mang)

{
int i, Rong;
i = 1;
45
46
Rong = TRUE;
while (i <= n)
if (DC_Mang[i] == 1)
{
Rong = FALSE;
break;
}
else
i++;
return (Rong);
}
/*

*/
void SetRong_Dhoa ()
{
int i;
for (i= 1; i<= n; i++)
Tap_Dhoa[i] = 0;
}
/*

*/
void CapNhatDbongTruDhoa ()
{

int i;
for (i= 1; i<= n; i++)
if ((Tap_Dbong[i]==1) && (Tap_Dhoa[i]==0))
Tap_DbongTruDhoa[i] = 1;
el
se
Tap_DbongTruDhoa[i] = 0;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Ham hoan doi cac phan tu (la cac ten file) cua hai
tap hop cac ten file. */
/*

*/
void HoanDoi2TapHopTenFile (ch
ar *TenCacFile_A[10],
char *TenCacFile_B[10])
{
char MangLuuTen[10][10];
char *Temp[10];
int i;
for (i= 1; i<= n; i++)
Temp[i] = (char *)(MangLuuTen + i);
for (i= 1; i<= n; i++)
strcpy (Temp[i], TenCacFile_A[i]);
for (i= 1; i<= n; i++)
strcpy
(TenCacFile_A[i], TenCacFile_B[i]);
for (i= 1; i<= n; i++)
strcpy (TenCacFile_B[i], Temp[i]);

}
4.
PHƯƠNG PHÁP TR
ỘN ĐA PHA (POLYPHASE MERGE)
Phương pháp tr
ộn đa lối cân bằng đ
ã lo
ại bỏ các phép sao chép
thu
ần túy thông qua việc gộp quá tr
ình phân ph
ối v
à
quá trình tr
ộn
trong cùng m
ột giai đoạn. Tuy nhi
ên các t
ập tin ch
ưa đư
ợc sử dụng
m
ột cách có hiệu quả bởi v
ì trong cùng m
ột lần duyệt th
ì phân n
ửa
s
ố tập tin luôn luôn giữ vai tr
ò tr

ộn (nguồn) v
à phân n
ửa số tập tin
47
48
luôn luôn gi
ữ vai tr
ò phân ph
ối
(đích).
Ta có th
ể cải tiến ph
ương
pháp trên b
ằng cách giải quyết thay đổi vai tr
ò c
ủa các tập tin trong
cùng m
ột lần duyệt ph
ương pháp này g
ọi l
à phương pháp tr
ộn đa
pha.
Ta xét ví d
ụ sau với ba tập tin f
1
, f
2
, f

3

ớc 1:
Phân ph
ối luân phi
ên các run ban đ
ầu của
f
0
vào f
1
và f
2

ớc 2:
Tr
ộn các run của f
1
, f
2
vào f
3
. Gi
ải thuật kết thúc nếu f
3
ch

có m
ột run


ớc 3:
Chép n
ửa run của f
3
vào f
1

ớc 4
: Tr
ộn các run của f
1
và f
3
vào f
2
. Gi
ải thuật kết thúc nếu f
2
ch
ỉ có một run.

ớc 5:
Chép n
ửa số run của f
2
vào f
1
. L
ặp lại


ớc 2.
Phương pháp này c
òn có nh
ư
ợc điểm l
à m
ất thời gian sao chép nửa
s
ố run của tập tin n
ày vào t
ập tin kia. Việc sao chép n
ày có th
ể loại
b
ỏ nếu ta bắt đầu với Fn run của tập tin f
1
và Fn
-
1
run c
ủa tập tin f
2
,
v
ới Fn v
à Fn
-
1
là các s
ố li

ên t
i
ếp trong d
ãy Fibonacci.
Chúng ta xem xét các ví d
ụ sau:
Ví d
ụ 1: Tr
ư
ờng hợp n=7, tổng số run ban đầu l
à 13+8=21 run
Phase
F 1
F2
F3
0
1, 1, 1, 1, 1, 1, 1, 1
1, 1, 1, 1, 1
Sort
1
1, 1, 1,
2, 2, 2, 2, 2
Merge 1
2
3, 3, 3
2, 2
Merge 2
3
5, 5
3

Merge
3
4
5
8
Merge 4
5
13
Merge 5
6
21
Merge 6
Phase 0:
Phân ph
ối các run ban đầu
Phase 1:
Tr
ộn 8 run của f1 v
à f2 vào
f3
Phase 2:
Tr
ộn 5 run của f1 v
à f3 vào
f2
Phase 3:
Tr
ộn 3 run của f2 v
à f3 vào
f1

Phase 4:
Tr
ộn 2 run của f1 v
à f2 vào
f3
Phase 5:
Tr
ộn 1 run của f1 v
à f3 vào
f2
Phase 6:
Tr
ộn 1 run của f2 v
à f3 vào
f1
Ví d
ụ 2:
Phase
T6
T5
T4
T3
T2
T1
T
ổng số runs
đư
ợc xữ lý
Phase 0
1

31
1
30
1
28
1
24
1
16
-
129
Phase 1
1
15
1
14
1
12
1
8
-
5
16
80
Phase 2
1
7
1
6
1

4
-
9
8
5
8
72
Phase 3
1
3
1
2
-
17
4
9
4
5
4
68
Phase 4
1
1
-
33
2
17
2
9
2

5
2
66
Phase 5
-
65
1
33
1
17
1
9
1
5
1
65
Phase 6
129
1
-
-
-
-
-
129
Phase 0:
Phân ph
ối các run ban đầu
Phase 1:
Tr

ộn 16 run từ T2 đến T6 v
ào
T1
49
50
Phase 2:
Tr
ộn 8 run của T1, T3, T4, T5, T6 v
ào
T2
Phase 3:
Tr
ộn 4 run của T1, T2, T4,
T5, T6 vào
T3
Phase 4:
Tr
ộn 2 run của T6, T5, T3, T1, T6 v
ào
T4
Phase 5:
Tr
ộn 1 run của T1, T2, T3, T4, T6 v
ào
T5
Phase 6:
Tr
ộn 1 run từ T1 đến T5 v
ào
T6.

Xem xét b
ảng tr
ên ( t
ừ d
ư
ới l
ên) chúng ta th
ấy có bảy b
ư
ớc phân bố
theo dãy Fibonacci b
ậc 4 l
à: {1,0,
0,0,0}, {1,1,1,1,1}, {2,2,2,2,1},
{4,4,4,3,2}, {8,8,7,6,4}, {16,15,14,12,8}, và {31,30,28,24,16}.
V
ới số tập tin T=6 bảng sau cho thấy số run ban đầu đ
ư
ợc phân bố
thích h
ợp:
Phân b
ố Fibonacci ho
àn h
ảo với T=6
Level
T6
T5
T4
T3

T2
Total Runs
0
1
0
0
0
0
1
1
1
1
1
1
1
5
2
2
2
2
2
1
9
3
4
4
4
3
2
17

4
8
8
7
6
4
33
5
16
15
14
12
8
65
6
31
30
28
24
16
129
7
61
59
55
47
31
253
8
120

116
108
92
61
497
-
-
-
-
-
-
-
n
an
bn
cn
dn
en
tn
n+1
an+bn
an+cn
an+dn
an+en
an
tn+4an
Trong ví d
ụ 1, số r
un phan ph
ối ban đầu cho các tập tin l

à 2 s

Fibonacci k
ế tiếp nhau của d
ãy Fibonacci b
ậc 1: 0, 1, 1, 2, 3, 5, 8 . . .
Trong ví d
ụ 2, số run ban đầu phân bố cho các tập tin theo d
ãy
Fibonacci b
ậc 4: 0, 0, 0, 0, 1, 1, 2, 4, 8, 16 . . .
Dãy
Fibonacci b
ậc
P t
ổng quát đ
ư
ợc định nghĩa nh
ư sau:
F
(p)
n
= F
(p)
n
-
1
+ + F
(p)
n

-
2
+ + F
(p)
n
-
p
, v
ới n>=p
Và F
(p)
n
= 0,
v
ới 0 <= n <= p
-
2;
F
(p)
p
-
1
= 1
Dãy Fibonacci thông th
ư
ờng l
à dãy Fibonacci b
ậc 1.
Thông thư
ờng nếu chúng ta lấy p= T

-
1, phân b
ố trộn đa pha đối
v
ới
P t
ập tin sẽ t
ương
ứng với số Fibonacci bậc P.
51
52
Phép băm đư
ợc đề xuất v
à hi
ện thực tr
ên máy tính t
ừ những năm 50
c
ủa thế kỷ 20. Nó dựa tr
ên ý t
ư
ởng: chuyển đổi khóa th
ành m
ột số
(x
ử lý băm) v
à s
ử dụng số n
ày đ
ể đánh chỉ số

cho b
ảng dữ liệu.
Các phép toán trên các c
ấu trúc dữ liệu nh
ư danh sách, cây nh

phân,… ph
ần lớn đ
ư
ợc thực hiện bằng cách so sánh các phần tử của
c
ấu trúc, do vậy thời gian truy xuất không nhanh v
à ph
ụ thuộc v
ào
kích thư
ớc của cấu trúc. Ch
ương này s
ẽ khảo
sát m
ột cấu trúc dữ
li
ệu mới đ
ư
ợc gọi l
à b
ảng băm (hash table). Các phép toán tr
ên b
ảng
băm s

ẽ giúp hạn chế số lần so sánh, v
à vì v
ậy sẽ cố gắng giảm thiểu
đư
ợc thời gian truy xuất. Độ phức tạp của các phép toán tr
ên b
ảng
băm thư
ờng có bậc l
à 0(1) và khôn
g ph
ụ thuộc v
ào kích thư
ớc của
b
ảng băm.
Chương này s
ẽ giới thiệu các nộ
i d
ung sau:

Phép băm hay hàm băm (hash function)

B
ảng băm

Đ
ụng độ v
à gi
ải quyết đụng độ

Thông thư
ờng bảng băm đ
ư
ợc sử dụng khi cần giải quyết những b
ài
toán có các c
ấu trúc dữ liệu lớn
và đư
ợc l
ưu tr
ữ ở bộ nhớ ngo
ài.
1.
HÀM BĂM (HASH FUNCTION)
1.1.
Đ
ịnh nghĩa
Trong h
ầu hết các ứng dụng, khoá đ
ư
ợc d
ùng như m
ột ph
ương th
ức
đ
ể truy xuất dữ liệu một cách gián tiếp. H
àm đư
ợc d
ùng đ

ể ánh xạ
m
ột khoá v
ào m
ột d
ãy các s
ố nguy
ên và dùng các giá tr
ị ngu
yên này
đ
ể truy xuất dữ liệu đ
ư
ợc gọi l
à hàm băm (h
ình 2.1)
K
h(K)
hình 2.1
Như v
ậy, h
àm băm là hàm bi
ến đổi khóa của phần tử th
ành đ
ịa chỉ
trên b
ảng băm.
Khóa có th
ể l
à d

ạng số hay số dạng chuỗi. Để giải quyết vấn đề băm
v
ới các khoá khô
ng ph
ải l
à s
ố nguy
ên chúng ta tìm cách bi
ến đổi
khoá thành s
ố nguy
ên, ch

ng h

n:

lo
ại bỏ dấu ‘
-
’ trong mã s
ố 9635
-
8904 đưa v
ề số nguy
ên
96358904

Đ
ối với chuỗi, sử dụng giá trị các ký tự trong bảng m

ã
ASCCI

Sau đó s
ử dụng các h
àm băm chu
ẩn tr
ên s
ố nguy
ên.
Yêu c
ầu đối với h
àm băm t
ốt
Hàm băm t
ốt thỏa m
ãn các
đi
ều kiện sau:

Tính toán nhanh

Các khoá đư
ợc phân bố đều trong bảng

Ít x
ảy ra đụng độ.
1.2.
Ví d
ụ về các h

àm băm
(i) Hàm băm d
ạng bảng tra
Hàm băm có th
ể tổ chức ở dạng bảng tra (c
òn g
ọi l
à b
ảng truy xuất),
thông d
ụng nhất l
à
ở dạng công thức.
CH
ƯƠ
NG
2
-
B
ẢNG BĂM (HASH TABLE)
2
h

×