'Với cuốn bài tập nâng cao nầy, bạn sẽ học được nhiều cách giải các bài loần khác nhau bằng lập trình như tính trị của một định thức NxN, nhân hai ma trận, đổi một biểu thức infix trung
Trang 1(TS; Ban Lan THE)
NHA XUAT BAN THONG KE
Trang 2Bai Lập nang cao
Trang 3La NÓI ĐẦU
Cuốn "Bài đập nẵng cao, cẩu trúc dữ liệu, tửi đặt bing C” được biên soạn với các bài tập nãng cáo về mắng, ngản xếp,
hằng đợi, các danh sách liên kết, chuỗi, đổ thị và nhiều bãi tập
khác được thực hiện trên cở sở ngôn ngữ lập trình C
'Với cuốn bài tập nâng cao nầy, bạn sẽ học được nhiều cách
giải các bài loần khác nhau bằng lập trình như tính trị của một
định thức NxN, nhân hai ma trận, đổi một biểu thức infix (trung
tố) sang dạng prefix (tiển tố), đảo ngược các liên kết, quản lý bộ nhớ nhờ đũng các dzm*es4abs#\a2;høä ng cách giữa hai chuỗi, tạo
mã Huffman, thực th: một tập hợp nhờ dùng cây nhi phan, tim
đường dẫn ngắn nhất, ánh xạ N hàng đợi trong một mảng, thực thị
thuật toán À*
Sách được phân chia bố cục một cách rõ rằng Trong mỗi hài tập đều có giải thích cụ thể về mỗi chương trình, đặc biệt ở cuối
mỗi bài tập, chúng tôi có đưa vào phẩn "Những điểm cẵn ghi
nhđ" tóm tắt những điểm chỉnh nhằm giúp ban nhớ lại những vấn
để đã được nêu ra trong bài tập đẳng thời củng cố kiến thức hạn '
đã học được
Chúng tôi hy vọng cuốn bài tập này sẽ là iài liệu tham khảo
thật sự hữu ích chơ các bạn, Mong nhận được sự đồng góp ÿ kiến xây dưng từ hạn đọc Xin chân thanh cdm on
Tae gtd,
Trang 4hương 1 ; Các hãi tập về mảng, tìm kiếm, phân loại
(hưởng ƒ
Eác bài tận về mảng, tìm kiếm,
phân loại, và tạo băm (hash)
Bài tap: Tính trị của một định thức N x N
* print the matrix
for( i=0: ?<Ñ; ++i ) {
Trang 5Chương 1 : Các bài tập về mảng, tìm kiếm, phân loại
* makes a an upper-triangular matrix
* returns 0 if any of the diagonal entries are 0; 1 otherwise
* int 4 jr
double factor = 1.0:
double temp;
for( i=l: iN: +71) J1 dont worry about row 0
for( je: i<i; +i) (
if( fabs(temp} > EPSILON && fabs(temp-1.0) > EPSILON ) {
printf( “factor=tg dividing row td by %g \n",
factor, j, temp ):
divRow( a, j, temp );
print(a):
factor *= temp:
Trang 6Chương 1 : Các hài tập vé mảng, tìm kiếm, phân loại - 9
double multDia( double a[][N] ) { _
* returns multiplication of diagonal elements
1 Cách thông thường để tìm trị của một định thức N x N là lấy
phần tử đầu tiên trong hang đầu tiền nhân với trị của định thức
được tạo thành bằng cách loại bỏ hàng đó và cột đó Thủ tục này
được thực hiện theo phép đệ quy ở mọi bước cho đến khi chỉ còn lại một phần tử duy nhất mà trị củn nó chính là trị của định thức
11 Dấu của phần tử đưng được nhân cả thể thay đối tay thuộc
vàe hãng và cột củe nó Nái chung, nếu phần tử cá hàng ¡ và cột
Trang 710
vi mang, tim kiết
j thì đấu cua n6 được xác định bởi cảng thức (-31^(i+y)
3 Có mật cách khác đê grái hài tập này Lưu ý rằng nấu ta thực
hiện các phép biến đổi hàng hay cột trên định thức thí trị của nó không th.i đổi, Tận dụng dữ kiện nãy để biếp đổi mạ Lrận tương
ứng với định thực thành mật ma trận tan giác trên hay đưới rồi tìm trị định thức của ná Rô ràng trị định thức eủä một rna trận
tam giác trên hay đưới là tích tủa các phần tứ chéo Da vậy, tìm mot tr] định thức rw hắn chỉ là việc làm ghủ một ma tran trở
thành mna trận Lam giác trên hay dui
8 Bể biến đổi một ma trận thành ma trận tam giác trên
tralkeUpper(3), tạ thực hiện cae phép biển đổi hãng trên ma
trận đố, Một la ý quan trọng lhác là phép nhân của một đình thie D với một ti: + ìà một định thức mới mà trong đỏ bắt kỳ
hàng rúa D được nhân với v Phép nhân một hàng với v có nghữx
là nhãn mới phần tư trong hằng đó với y Do đá tá duy trì một
thứa sẽ biến đổi để theo đài số nhân khi các hàng của định thức
được nhắn hay chia cho ahiểu thừa sổ khác nhau trong tiến
trình tạo tam giác trên (upper-triangulatian), Ở đãy, ta giả sử
mọi phần tử của định thức là các số đấu chấm động
4 Trong tiến trinh upper-triangulation, nếu có bất vị phan tt ado trang eác phần tư cháo trúgSàssssxsssflero(ï), điều đủ cá mghịa
là trị cua định thức bằng 0 (ghi nhớ rằng trị của định thức bằng phép nhân tủa các phần tử chéo {maulEDiat)),
5 Wế từ đây, tả giả sử các phần tử là các số đấu chấm dong (float-
ing-point number}, phép tinh od thé không chính xác Để gia]
thích cho tỉnh gắn đúng này, ta duy trì một thuật new lai BPSI-
LON vữn được xác lập sang một trị đỏ thấp (có thể bằng f), Bất
kỹ trị nao nam trong day +EPSILON_0.-EPSILON sẽ được xem
là 0
6, Thuật toán để biến một ma trân thành một ma trận tam giáp
trên là như sau:
Trang 8hương 1 : Các bai tập về mang tìm kiếm, phân loại
2 1 chia hang 1 cho 0.5 24
Trang 912 Chương 1 : Dác bài lập về mảng, tìm kiếm, phân loại
100125
| 0 00.0617) Vậy, định thức = 24*(1*1*0.0417) = 1
Những đểm cẩn ghi nhớ
1 Cách đầu tiên để giải bài tập này theo phép đệ quy là tự nhiên,
nhưng khó sử dụng vì nó yêu câu loại bỏ một hàng và một cột Vì
vậy, khi thiết kế một thuật toán, bạn nên thử nhiễu phương
pháp khác nhau rồi chọn phương pháp thích hợp nhất
* find min value in row of a
* return the yalue,
Trang 10hương 1 : Cac bai tap vé mang, tìm kiếm, phân I
int findMax( int a[][N] int col ) {
„~
* find max val in col of a
* return the value
1 Một ma tran M x N duge cho là có một điểm saddle (yên ngựa)
nếu một mục nhập a[¡]f] là nhỏ nhất trong hàng ¡ và lớn nhất trong cột j Trong ví dụ ma trận sau đây, 7 là điểm saddle.
Trang 1114 Phương 1 : bác hãi tập vể mảng, tìm kiểm, phân loại,
J123|
a=|456|
|783|
2 Chuong trinh thi don gian va ¢6 thé duoc hoan chinh trong O(M
x NxM) lan bang efich sw dung cdc vang lap for duoe xép lang
“Thuật toán như sau:
}
‡
8 Phép tìm trị nhỏ nhất trong một.hàng là O(N) và lớn nhất trong
một cột là O(M), Do đó phức hợp của thuật toán trở thành O(M*(N+N*M), hoặc O(M*N*M)
Những điểm cần ghi nhớ sated
1 Một điểm saddle là trí nhỏ nhất trong hãng và lữn nhất trong
cột,
2 Uó thê có trên một điểm saddle trong một ra trận (matrix)
3 Có thể không cổ điểm saddle nào trong một ma trần,
4 Phức hợp của thuật toán là O(M xM x NÌ, trong đó M xN là kích
cỡ của ma trận,
Bài lận: Nhân hai ma trận 5parse
Viết một hàm m mult() để nhân hai ma trận sparse trải rác) và chứa
kết quả trong một ma trận sparse khác Mỗi mna trân sparse được biểu thị bãi một mảng các bộ ba Mỗi bộ bai (triplet) gồm có một hàng, một
Trang 12Chương 1 : Cac bai tap vé mang, tim kiểm, phân loại
void ftrans( int a[}{3], int b[]f3] ) {
void printMatrix( int afJ(3] ) {
Trang 1316 Chương 1; Cac bai t@p về mang, tim kiém, phan logi
void insert( int c[][3] int row int col, int val) (
for( 1=1; i<=terms &ä c[1](0]<row; +1 )
for( : i<=terns &k c[1][1]<col; #>i )
†f( i<=terms && c[ï][1] = col ) // already inserted
in *É = (int *)ma]loc( rơøsofb*sizeof(int) 3:
ing temp, temp2;
TnỆ arow, acol, aval brow, browstart browend;
Tor( ï=l; i<=rowsofb; ++i )
temp2 = t[i], t[i] = t[1-1]+temp, temp = temp2:
Trang 14hương 1 ; Các bài tập vế máng, tìm kiếm, phân loại 17
/Í now start mult
for( i=l; {<=aterms; +1 ) ( arơ = a[i][0]: aco] = a[1]I1]; aval = a[1][2];
brow = acol;
hroestart = t[brœ]; brgwend = t[brơw+1]:
for( jebrowstart: j<browend; ++) )
insert( ©, arow b[4]f1], aval*b[J][2] 3:
} }
#mt maln() {
1nt a[](31 = {
{4.2.3}, {01.2}
pr ntMatrix(b); TRƯỜNG ĐẠI HỌC TRÀ VINH
maith Ay Be Sys THU VIEN
tử khác trong ma trận sparse Do vậy, ta duy trì một mảng có
kích cỡ N x 3 cho mỗi ma tran sparse, trong đó Ñ là số các phần
tử khác 0 trong mang Hang dau tiên của mỗi ma trận sparse chứa số hàng, số cột và các phần tử khác Ù trong ma trận Sau
đây là một ví dụ `
Trang 1518 hương 1 - bác tải lập về mảng, lim kiếm, phân loại
a[01I0] = 7 là số hãng của ma trận a a[0]|1]=7 là sà cật của ma
trận a a[0][2|=8 lã sẽ eác phẩn tử khác 0 trong ma trận a Các
phần tứ khác 0 được lưu trang các hãng i=1 đến ¡=B trong đó
a(i][0] là hàng, a[il[1] là eột và af[2] 1a tri trong ma tran a- Luu
ý rằng các phấn tử được phân loại theo hăng nhưng bên trong
một hàng, chúng được phản loại theø các cột
3 Hàm m mulk(a, h, c) lấy tmn8&jzphẩmr4ttuvảm a, với hằng araw và cột
acol, nhân với mỗi phần tử hàng acol của b Tích được cộng vào
phan tử trong e với hàng arow và cột băng cột của phần tử trong
h, Lưu ý rằng vì a và b được phân loại theo (hang, cột) nên các mục nhập mới được tạo cha c cũng có cùng thứ tự phân løại, Da
dé taco thé dé dang chén các mục nhập mới trong ¢ vao cudi cde mục nhập đang được lưu tzữ _,
3 Vấn để duy nhất bây giờ Tà cách dat tei mye nhap dau tiên trong
b với hàng acol Một cách là sử dạng phép tìm nhị phân để đạt
tới hàng này, vi nú được phân loại theø hằng, Nhưng lưu ý rằng
số hãng của lì là không đổi Vì vậy ta duy tri một mắng các chỉ sẽ
trõ đến cầu mục nhập đầu tiên chu mỗi hằng trong b Dø vảy,
niểu ma trận h giống như được minh họa trước đãy thì các chỉ số được duy trì trong một veetor t sẽ giống như được minh họa ở
day.
Trang 16hương 1 : ác bài tập về mảng, tim kiếm, phân lnại 18
t[i]= 0 biểu thị hàng ¡ của b không có chứa bất kỳ phần tử nào
Do bởi điểu này, phép tìm nhị phân ban đầu của thứ tự O(logn)
bay giờ có thể được thực hiện trong O(1) lần Nhưng điểu này
cần thêm O(Nb) lần để tạo t(] trong đó Nb là số các mục nhập
hàng acol của b được rảo qua
phần tử trong a được nhân với mỗi phản tử trong hàng danh sách
(row-list) của b với hàng acol và cột beol, và
các tích được chèn vào e là c[arrow][bcol]
Do đó trong mọi bước, một phần tit trong a sé lam tăng thêm e tiên e[arrow][beol] hiên hữu thì tích được cộng vào trị ban đâu I"hóp ulin của a với b được cho ở đây cho ví dụ trước
Trang 17z0 hương 1 : bác bài tận vé mắng, tìm kiếm, phần loại
Bước AROW ACOL ECOL AlAROWJ|ACOL] 'IAROWJIBCOL]
danh cho cdc pointer, nếu một ma tran sparse được biểu diễn bởi
duy trì (hàng, cột) lớn nhất được chèn vào c và bằng cách thực
hiên một phép tìm nhị phân trong khi tìm kiếm một một (hang, edt) hiện cá, hộc bằng cách duy trì một mảng tương tự với 1]
chơ b Bằng cách chứa thêm những chỉ số như vậy, việc chèn
trong e cĩ thể được thực hiện trong O(1) vốn sé lam cho mmult()
trở thành O(Na*Cb)
Bài tận: Phép nhãn hai ma trận Sparse (các phiên bản khác
nhau) Cho a và b là hai ma trận sparse (rải rác) Viết mật hàm sMatMul(a,
b, e) để thiết lập cấu trúc chu e = a*b.
Trang 18hương 1 : Các bài tập về mảng, tìm kiếm, phân loại
typedef int type;
typedef struct node node:
mat->rows = (node *)malloc( sizeof(node)*rows );
mat->cols = (node *)malloc( sizeof(node)*cols );
for{( i=0; i<rows; ++i) { mat->rows[i].hnext = mat->rows+i;
Trang 1922 Chương † : Các hài tập về mảng, tìm kiếm, phân loại
int sAddi spmat ‘mat, int row int col, type data > { “
* adds a new node to the sparse matrix
for( prev=head, ptr=prev.>hnext; ptrl=head && ptr->col<dataptr:
“
* inserts dataptr in appropriate «| of sparse matrix
* Assume that cRowlnsert() was ca‘ ed before
Trang 20thương † : Cac bai tập về mảng, tim kiém, phan loại 23
free(dataptr) ; return SUCCESS:
Trang 2124 Chuong 1 : Cac bai tập vé mang, tìm kiếm, phân loại
int i:
Trang 22Chương 1 : bác bài tập về mảng, tìm kiếm, nhân loại 25
for( i=0; ict; +7)
for( ptri=a->rows[{i].hnext; ptril=a->rows+i; ptri=ptri->hnext )
‘int row = ptri->col;
fort ptrjeb->rows[row].hnext: ptrj!=b->rows+row;
ptrj*ptrj->hnext ) {
} }
sAdd( &b, 1,1, 6);
sHPrint(&a,M) ; SHPrint(&b, P) :
SMatMul( ša, &b, &c ), SHPrint(&c ,M)
i va cing nut này trong danh sách đọc của cột j Mật nút (mode)
tiêu biểu cho một mục nhập Do đó, nó chứa hàng, cột, và các trị
cùng với các pointer ngang và dọc trong các danh sách
Trang 2326 Chương † : Các bài tập về mắng, tìm kiếm, phân loại
3 Cho kích cỡ của các ma trận sparse a, b là MxP, PxN Do do, kich
cỡ của e là MxN, Ta mẽ tả một thuật toán bằng cách sử dụng
mét vi du Cho
lo 2) a= |3 0|, b=|005|
3 Thuật todn rao gua méi hàng của a và kiểm tra danh sách ngang
của nö tương ứng với mỗi hàng cho bất kỳ phần tử trang nó Đối
với mỗi phần til trong a với hàng arow và cột aeol, hàng acol của
b được rảo qua và phần tử trong a được nhân với mỗi phần tử
trong hàng-danh sách (rowslist);eja:h.xới hàng acal và cột bcol Các tích được chèn vào ¢ theo dạng e[arow][beol] Do đó trong
Tmọi bước, một phần tử trong a làm tăng thêm c Nếu e[araw][beol] hiện hữu thĩ tích được cộng vàn tri bar đầu Phép nhân của a và
b được cho ở đây cho ví dụ trước
Bước AROW ACOL BCOL AlAROWIIACOLI'B €[AROWI(BCOL]
Bước 4 biểu thị a[4] được lấy dé 14 jaa nhung khang dive ro
qua khi nụ rồng lưu ý rằng tích bảng 24 ở bước 4, trong khi t[Ä|[2| có một tế; là 29, Điều này xuy ra bởi vì cL8](9) đã có chứa
một trị 5 ở bước 5
Trang 24hương 1 : Các bài tập về mảng, tim kiếm, phân luại 27
4 Gha na, nb là sä các mục nhập lkhác 0 trang a và b Bước e¿ hán
trong thuật tnấn này là cộng các tích của các nhắn lử lrũng a vá
b với c Vì vậy, ngay cả khi vòng lập ngoài rảo qua từ (} đến M-1
thì hàm eAddU được viện dẫn chø mỗi mục nhấp afï|(J] ự viện dẫn này được thực hiên cho mỗi nhẳn tử khác 0 trong hãng j của
b Da đó, tối da số phẻn nhãn cho a[ïllj] sẽ bằng N, số cột tua b,
Vay phức hợp của thuật toán nhần ma trân là O(na*M) Tụy nhiên, nếu ta thăm phức hợp Lới vòng lầp ngoài tùng thì phù
Những điểm cần ghỉ nhữ
1, Mật sự sữa đổi nhỏ cho ham ađđ(matrix,xow,col.value) thăng
thường đã đãn đến sư thực thị đề đãng của phép nhãn ma trận
Ni chung, nếu ali]UJ] được chèn vào và nó đã cũ thị ta ghỉ đề trị
hose cho ra một lâi, Rầằng cách cộng Lrị mái vào trị ban đầu, ta cá
thể cảng các Lích của các phản Lử trong a và h vào c theo cách gia
diễn này như b dO, phde hợp tầng lên cho
G(M*P*?NTP| khi aGetVal là O(P)
4 Các phần chèn được đơn giản bằng sự biểu điễn các hàng và các
cột rỗng qua các nút tiêu dé thay vi các đanh sách NƯU|,
Bài tập: Thực hiện phép phân luại - tron theo K cach dé phan
luại một File có chứa cac Recard (bản nhi)
#define K 2 #/ Keway ergs
oer ine DATAFILE “main trt* sq
#def|ne TEHPFILE ~temp trt~
typedef struct node node:
typedet enum (FALSE TRUE) boo} ;
struct node
fot vat | char «IN}
}:
Trang 2528 Chuang 1 : Cac bài tập về mảng, tìm kiếm, phân Iại
ede buf[K];
int rec[K];
f/ buffer used for merging,
// record numbers of nodes in buffer
‘int ements char *filename ) {
}
void readFromFile( char *filename, node *n, int off ) {
/#
* reads a record at offset off from file filename into n
* off is number of records before the record in the file (NOT bytes}
* off starts from 0
mf
FILE *fp;
/fprintf( “reading rec no ¥d \n", off );
if( off >= getNRecords(filename) ) {
fprintf( stderr “ERROR: reading beyond the file.\n™ ):
Trang 26Đương 1 : Các hài tập vé mang, tim kiếm, phan loại
void writeFun( char *filename ) {
‘int i, nrec = getNRecords( filename);
for( 1-0; i<orec; ++i) { readFromFile( filename &n, 1);
printf( “S2de{%2d,%-5s}.\n", i, n.val, ns ):
} }
void copyrec{ int rec, int *rec2 ) {
* fills buf and rec with appropriate values
* 7 is length of each run
* start is rec no of first rec in first run
* data is in srefile in nrec records
29
Trang 27au hương 1 : Các bai tap về mảng, lìm kiếm, phân luại
“
qt i;
prrntf( “start=td l=%d.\n", start, 1);
for( i=0; ick; +41) {
int startoff = start+I*i;
if( startaff >= nrec )
break:
rec[i] = startoff;
printf( “buf(ad]=sd.\n" 1, startoff ):
TreadFromf1Ìe( srcfile buf+1 startoff );
void updatebuf( node *buf int *rec, int *rec2, int prevrec int }
char *srefile int nrec ) {
*
* updates buf+rec2 as rec2[prevrec] was output
* read appropriate record from srcffÏe if necessary
* rec st†]] contains the original rec nos which can be used for
* checking ends of runs -
* 7 15 runtength,
*/
1f( rec2[prevrec] < nred' KỸ Fecal prevrec) < recCprevrec}+1-1 ) (
2/ rẹc2[prevrec] was M0T the Vast rec of that run rec2[prevrec]++;
readFromFile( srcftle, buf*prevrec, rec2[prevrec] ):
else {
JJ recZ[prevrec] was the ]ast rec of that run
rec2[prevrec] = -1; // job of this run is aver
}
}
1nt getMin( node *buf, int *rec2 ) {
“
* returns index in buf of that record which has min sorting value
* rec2 is needed for checking whether a buf entry is valid
Trang 28hương 1 : Các bải tập vể mảng, lÌm kiếm, phân loại #1
* the same at this point
* buf contains their actual data
* 1 is run]ength
* srefile is needed for reading next data,
* the data is appended to dstfile
* total no of records being written is min(1*k, nrec-rec[0])
1T( nextrec =— -1 ) {
fprintf( stderr, "ERROR: merge()¡ all recZ are -1l\n" );
return:
}
2/prinkf( "mìme%d.Vn" newtrec );
// this is the index jn rec2 of next record to be output
writeToFile( dstfile, buf*nextrec );
7} remove this written record read new record from srcfile if
needed
updatebuf( huf, rec, rec2 nextrec, 1, srefile nrec 3:
f7printf( “after updatebuf : rec2=xd td šd.\n" rec2{[0]
rec2[1], rec2[2] ):
1 }
void mergedriver( char *srefite char *dstfile } {
/*
* sort+merge srcfile and store in dstfile
*/
Trang 29a2 hương 1 : Các bài lận về măng, fìm kiếm, phãn luại
int nrec = getNRecords(srcfT1e);
int i, 1:
‘int rec2(k];
char tempname[M]:
for( =1: 1<nfec; 1* ) {
/? T 3s 1ength nf each run
// no 0f runs = ceiT( nrec/] );
// we teed to consider only K runs at a time
for( i=0; i<nrec; †+el*K ) {
Z! TiT1 Buf with appropriate values, Fillbuf( i, 1 nrec, srcfile );
C€0pyrec( rec rec2 };
merge( srcfile, dstfile buf, recở, I nrec };
un}ink( srcfile );
strepy( tempname, srcfile );
strcpy( srcfile dstfile }:
strepy( dstfile, tempname };
7/ sorted file is srcfile
readFun( srcfile ): - 2#4#msefEiectesm
int main() {
char srcfile[N] = DATAFILE;
char dstfive(N] = TEMPFILE:
untink( srcfile }:
unlink( dstfile );
writeFun( srcfile 3;
readFun( srefile );
printf( "nrec=*d.\n", getNRecords(srcfile) );
mergedriver( srefile, dstfile ):
return 0;
}
Giải thích
1 Ham main() tạo một file kiểm tra bằng cách sử dung writeFuntl
va goi mergedriver() mergedriver() goi ham merge() sau khi dow
các khối K (fillbuf{)) ctia file vao bộ nhớ
3 Hàm merge() so sánh các khối và phản loại chúng trân khóa đã
xác định trước Khối cổ khóa nhỏ nhất (getMinU) được viết vàø
file và Ichi của nẻ được điển đẩy (updntebuff]) với rueard kế tiếm
Trang 30Chương † : ác bải tặp vế mảng, tìm kiếm, phân lơại 33
từ ñle, Do đô phép phan loai (sorting) và trén (merging) tién
hành đồng thửi để phân loại RÌa liền tục
8 Số lượng khối được so sánh được gọi là run Mỗi chiều dài run tăng với mỗi lần lặp lại Nếu ban đâu nó là 1 thì nó trả thành , roi K*K và cứ như vây tiếp tục Khi nỏ trở nên lớn hon hoặc
bang sé record trong file (getNRecords()), file duge phan loi boi
vì tất cã các record trong mỗi run được phân loại sau mỗi lắn
4 Ví dụ: Giá sử các khối được lưu trong mật file như minh họa dưới
đây và cho K=3 Thuät toán biển đổi file như sau:
1, Phúc hợp của phép trộn -phân loai (merge-sort) la O(mlogn) trong
đó n là số record trong file Tuy nhiên, nái chung các câu lệnh
được thêm vào phức hợp là các phép su sánh hay một phép gan
xếp lẻng, Nhưng trong trường hợp của các file, ta cắn xem xét
việc đọc và ghi của các record trong ñie, vì thời gian cần thiết để thue thi mét thao tác như vậy lớn hơn nhiễu so với một phép sử
sánh trang bộ nhớ hay một phép gân đơn giản
3 Phân loại trang các file được gụi là phân Ìoai ngoài (external
sorting) trong khi phan loai trong bộ nhớ chính được gợi là phân
loại trong có kỳ hạn (termed laternal sort)
3 Bằng rách trao đổi tên của các ñlè nguân và file đích trong mergedriver( ), ta da tránh được việc sao chép các file trong rnỗi
lần lặp
Trang 3134 Chương 1 : Lác hài.tập vể mâng, tìm kiếm, nhân loại
Bai tap: Tim mot plateau (đoạn bằng) trong một ma trận
Tìm một miễn chữ nhật trong một ma trận với tổng lớn nhất của
* filter the matrix of size k*] starting frơm a[i][i]
* size of the matrix 1s rows*cols
Trang 32nương 1 : Các bãi tập về máng, tìm kiếm, phân loại 35
for(jjj=0: j3j<l && (itjj4)<c01s: #+Jjj!
printf(3d " a[i*i111f3*4431):
prinEf( An");
Yo oath
}
void prstezagint a[]J[C0LS] int rows int cols) {
‘sf a rectangular region having max sum of elements in it
int maxsum = a[0]{0]:
int maxrowl=0, maxrow2=0, maxcoll=0 maxcol2=0;
Trang 3338 Thương 1 : tác bẵi tập v6 mang, tim kiểm, phãn luại
if sum > maxsum
waxsum = sum,
3 }
Các trị của ¡, j, width (chiểu rộng) và height (chiéu cao) tai một
điểm bất kỳ tiêu biểu cho ma trận Các trị đó có thế được lưu để
_ in ma tran ở cuối thuật toán
Phức hợp của thủ tục nãy là O(m*m*m#n#n#n), trang đỏ kích cữ
của ma trận ban đâu là m x a Phức hựp của phép tìm tổng các phần tử của M là Oứn*n),
3, Phủ tục này có thể được thực hiện hiệu quả hơn bằng cách lưu ý rang khang phải mọi ma trận trong M đều cẩn được tạo Êli với
mật phần từ matrisli]U] chiểu rộng lớn nhất của ma trận bắt đầu từ phần tử co thể là columns-j và chiều cao lớn nhất cả thể
ia rows-i Do do, s6 lan lap eda cde ving lp qua chiều rộng và
chiéu cao cỏ thế bị giảm Nguài ra, đối với một phần tử e, nếu
tổng các phần tử của một miễn chữ nhat cũ height x width (can
x rangi bat đầu từ e là am thay vĩ không có miễn chữ nhật cỡ lớn
hơn height x width bắt đấu từ e có thể có một tổng lớn hơn kết
Trang 34hương 1 : Các tải lấp vế mảng, tìm kiếm, ghân luạl 3T
quả sau cùng Ta chứng mình điều này trong ví dụ ma trận -
Cho i=1 và j=8 matrix[iKj] = 10 Cho height = 2 và width = 1,
Suy ra ma trận có chứa hai phần bử trong nó, |10, -11| và tổng
bằng ‹] Vì tổng âm nên không có điểm nàa để tăng kích cỡ của
na trận và xét các phẫn tử khác hổi vì cha dù tổng của chúng là
bạo ahiều (giả sử sì, bằng cách cộng rna trận này vào nó, thì
tổng (sum) nhất định sẽ nhả hơn s Ma trận ở chứa tổng s cỏ
thể là môt đơn cữ cho kết quả Vì vậy, ma trân ở đây không thể
cố một tổng lớn hơn lết qué sau rùng Da dé, nếu ta tang thềm
chiều cao của.maa trận san cho các phan tif lz (10, -11, 3) thi ting tré thanh 2, nhé hon mot ma tran 1 x 1 bắt đầu từ 3, Thay vào
đó, nếu ta tăng chiều rộng sae che cde phan ti la (20, -11, -6, -71
thi tầng là -14, nhủ hứa nữa,
Ham ñlter(ï thực hiện phương án này,
1 Bằng cách xét chỉ hai ma trần bắt đầu từ một phần tử e, nghĩa là
các mu trận tàng chiều rùng đ phia nhai của e và tăng chiều cau xuống phía dưới e, ta chọn tất cả các miền chữ nhật có thé of ma
không bị bất kỳ sự lặp lại nào,
2, Ta không cẮn tầrg@#€k‡:g0#4J@søi2( ma trận con ngay khi tổng
eac phan tử của nó trở nên äm
3 Nếu muụi trị trang ma trận nhập liệu (input matrix) ãm thì kết quả là mật ma trận 1 x 1 với phần tử duy nhất có một liển độ
4, Gó thể cớ nhiều cách giải cha bai tap nay
5 Phức hợp của phép tìm các phẩn tử của một ma trận cøn
(submatrix) cd thé gia tăng bằng cách chủ ÿ Lổng giá tăng
Bài lập: Thực hiện một phép tim bam (hash)
*Viết mặt chương trình lấy các chuỗi ở dạng nhập liêu (ìnput] và chứa chủng trong một bảng bắm (hash table? hương trinh nay sau do sé yêu cầu người đùng tìm các chuỗi trong hash Lable Dùng sự địch chuyén- 3p 1am ham hashing va sv tao chuỗi để xử lý tràn
Chương trình
#ïnc]ude =st4ie.hz
#include <string b>
#include <maloc.h>
Trang 3538 Chương † : Các hài tập về mảng, tim kiếm, phân i:
#deFine MAXLEN B0
#define HASHSI7E 23 (/ some prime val
#define SHIFTBY 3 // each group size in hashing,
typedef struct node node:
typedef char *type;
typedef node xhashtahle[HASHSI7E]:
* returns index into hashtable applying hash function
* uses shift-folding followed by mod function for hashing
TRE ï n, finalm9:
char *keyptr: 7
for(keyptr=key; *keyptr: finalnt=n)
for(i=0 nO: 1-šŠHIFfUP°fEĐyZWfn++i, +xkeyptr)
# cae shift-falcing feitowed by moc: function for hashing,
% dows NOT check for duglicate insertion
otr->ke =< strdup(key!
ptr-ova + vi
ptr->next = h[†ndex1- h[fndex] = ptr
printf( "he Sd] = 23 \n", index key)
Trang 36Chương 1 : Các bi tận về mảng, Tìm kiếm, phân l0ại 39
Tt hGetVal(hashtable h, char *key) {
M2 , ĐEP->key, ptf->val);
printf(*\n"); á
} }
Trang 3741 hương † : bâc băi tập về mảng, lìm kiếm, nhên I:
line hủ:
return O:
}
Giải thích
1 Bảng hđm (bash table) duge duy i nh 14 mot wang the cde
danh sâch Mỗi danh sâch (lišt) 2aôc rỗng hoặc chứa câc aũL (node) bao gĩm cfc chudi ânh xa sang chỉ số trong hash ‡ahÌe,
sau khi ân dụng hầm hashing Chudi trong nút được gọi lă khóa
fkay), Mỗi nút cũng: chứa một số nguyín vấn lă gố mă tại đó
chuỗi được chỉn văo hash tahle, Do đồ, mỗi sút chứa một rắp
(chda, tră)” Trang một tình huống Lhực, một Erị (value) cả thể lă
bất kỳ trị năo eó mặt khóa liín quan với nó
® Chương Lrinh câ chữa hai vòng lặp (fo¿p) Trang vòng lặp đầu
tiín, nó yíu cầu người dùng nhập văo một laat cẩ chuối (strrig)
vă gại AInsert() dĩ chĩn ede chudi ceong hash tahle Vòng lêp thứ
hai yíu cầu người tùng nhập một chudi vă trả về so ma tai db nd
đê được chỉn văo Mật số chỉn lă -1 biểu thị chuỗi không có
trong hash table Điều nảy được thực hiện bằng câch sử dụng
hăm hetVal(J Câ hai braid bâm hashing hGettndex() znă với một chuỗi chụ brute, nd tra về chi sĩ tao hash (hashing)
cla nĩ Nd gdp chudi lại thănh một mẫu gồm m ký tự (sở lẽ
ngoạt trữ kỷ tý sau cũng), vă tao thănh một số nguyín từ mỗi ký tum Sau Íồ nú cộng tất cô câc số nguyễn năy lại với nhìu để cho ra mat số khâc Số năy sau đâ sẻ được chia cho lich cỡ của
mĩ hash table dĩ lay phan du lam chi si yao hash table, hÏnsert()
thím chuỗi mâi năy vă trinh tu chĩn eda ni yao mgt mit va out
nay dược thím văo đầu danh sâch tại chỉ số đó hGetVwl() tim
danh sâch tại chí số đó cho chuối nhập liệu, Nếu nĩ tìm thấy một chuỗi như vậy 4hi trình tự chỉn của nề được trả về, nếu
không nó trả vĩ -1
3 Vì phức hợp của phĩp chđn một nút trong danh sâch lă O(1l nền
phức hợp của hlneerM() lă phức hợp cũa hăm hashing, Phifc hop cua ham hashing la Olp| trong dĩ p la chiĩu dai trung hình của
chuỗi, Suy ra phite hop vie hinsert() 14 Ofp), Phie hep eda
hGetValt) lă O(p+q) brong đó q lă số trung bình của câc out trong
tmỗi danh sâch, Sự tạo chuỗi (ehaning! liín quan đến mặt phĩp
tìm tuyển tính
1 Phức hợp của phĩp chỉn trong hash table được quyết định bởi
Trang 38hương † : Các bài tập về mảng, tìm kiếm, nhân luại 4†
ham hashing nếu sự tạa chuỗi đơn giản được sử dụng để xử lý tran
2 Phức hựp của phép tìm kiếm được quyết đình bởi ca ham hashing
và leỹ thuật xử lý tran (overflow handling)
3, Một hãm hash lý tưởng ánh xạ mọi chuỗi nhập liệu (input string) sang một chỉ số khác và do đó không có sự xung đột nàn Giả sử phúc hợp của rnột: hàm hash là O(1) thi các phép chèn vã tìm
kiếm vào một hash table lÿ tưởng là O(1)
4, Các hash tabla được sử dụng trong các trình biên dịch để quản [ÿ hắng ký hiệu Các hash table còn có nhiễu ứng dụng khác
5 Các lẹỹ thuật xử ]ý tràn kháe nhau chẳng hạn như dò tuyến tính
(linear prohing), dà bậc 4 (quadratic prøbing), đồ ngẫu nhiên
(random ‘probing), tao lai bam (rehashing), được sử dụng tùy thuộc vào yêu cầu ửng dụng
Bai tap: Sy thye thi cia ky thual rehashing
Viết các hàm để chèn và tìm kiếm trang mật hash table bang cach sử
dung ky thudt rehashing (tao lai bam), Ding linear probing (đỏ tuyến
tinh) néu ky thuat rehashing khéng thanh céng
Chương trình
#inclute <stdio,h> h
#include <šstring.h> ¬ PI
#incìuđe <malloc.h> na
#define HASHSIZE 23 71 some prime val
typedef struct node node:
typedef char “type;
typedef node *hashtable[HASIS17E]:
* returns index into hashtable applying hash function
* Uses sum of elements followed by mod Function for hashing,
Trang 39* returns index into hashtable applying hash function,
* sums the products of elements with their indices and then mod
int hLinearProbe(hashtable h, type key int index) {
* search for node having key in h starting from index+]
*”
int †:
for(i=index+l: i<HASHSI7E; ++i) // index to end of hashtable
if(hL4] && !strcme(h[1]->key, key))
return i:
e]se Íf(!h[1])
return -1;
for(i=0; i<index; +1) // starting from 0 to index-1
1f(h[i] &® !strcmp(h[1]->key, key))
return i:
else if(!h{i})
return -1;
Trang 40ÿñương 1 : bac tải lập vẽ mảng, tim kiếm, phân loại
int index = hGetIndexi (key);
if(h{index] && strcmp(h[index]->key, key)} {
‘index = hGet Index2(key):
if(hlindex} && stremp(h[index]->key, key)) {
index = hLinearProbech, key, index);