Thuật toán lưu dữ liệu
Một cách lưu dữ liệu mớiĐặng Thanh TùngCác bạn thân mến!Sau khi đọc số báo tháng 7 năm 2004 tôi đã rút ra một phương pháp mới về việc lưu dữ liệu. Như các bạn đã biết, với những bài toán có dữ liệu lớn chúng ta được phép dùng bộ nhớ ảo (Virtual memory) để giải nhưng địa chỉ lưu được tối đa là khoảng 200K byte (Để máy tính nào cũng chạy được) nhưng như thế chưa tận dụng được khoảng trống trong máy của chúng ta. Vì vậy trong bài viết này tôi xin được trình bày một phương pháp khác có thể tận dụng tối đa bộ nhớ của máy tính.Đặt vấn đề: Trong thực tế việc tìm đường đôi khi rất khó khăn bởi việc mã hoá thành các đỉnh của đồ thị và giả sử có mã hoá được thì số đỉnh tồn tại cũng rất lớn. Vấn đề nảy sinh về việc lưu trữ hết các đỉnh. Các bạn có để ý rằng trong pascal có thể đọc file và lấy dữ liệu từ đó ra rất dễ dàng!. Chính vì thế mà tôi đã tận dụng "lỗ hổng" này của pascal để xử lý dữ liệu.Bắt đầu từ bài toán quen thuộc: Cho đồ thị: gồm N đỉnh, đỉnh xuất phát và đỉnh đích hãy tìm đường đi ngắn nhất từ đỉnh xuất phát tới đỉnh đích (n<=500000 đỉnh!).Dữ liệu vào từ file "loang.inp" trong đó- Dòng đầu tiên bao gồm: số N đầu tiên thể hiện số đỉnh của đồ thị, hai số tiếp theo lần lượt là đỉnh xuất phát và đỉnh đích.- Những dòng còn lại là một cặp (u,v) thể hiện từ u đến được v.Kết quả ghi ra file "loang.Out":- Dòng đầu tiên là số m thể hiện số bước đi ngắn nhất.- M dòng sau thể hiện cho mỗi đỉnh trong đường đi.Cũng với thuật toán duyệt đồ thị theo chiều rộng mà ta có thể giải bài này hết sức dễ dàng với việc lưu dữ liệu tôi trình bày dưới đây. Như các bạn đã biết với N<=500 000 đỉnh thì việc dùng mảng là không thể mà file là kho chứa dữ liệu vô tận mà ta còn chưa biết hết. Việc giải bài này phụ thuộc vào điều đó.Thuật giải: Các bạn hãy để ý rằng mỗi đỉnh nếu chuyển thành một xâu thì sẽ là một xâu có độ dài không quá 8 ký tự và ta sẽ lợi dụng điều đó để giải quyết bài toán này: Chuyển tất cả các đỉnh cũng như đầu và cuối (trong loang) thành một xâu từ đó chuyển thành một file text để lưu những gì có liên quan tới nó.VD: Đỉnh 3 có thể đến được đỉnh 1 và đỉnh 2. Khi đóFile "3.ke" sẽ lưu trữ 2 số 1 và 2: 3.ke12Mục đích của mỗi file *.ke là để lưu giữ các đỉnh có thể đến được từ đỉnh *.queueTương tự với các file khác*.đ: chứa một số 1 hoặc 0 thể hiện đỉnh * đã bị đánh dấu hay chưa.*.tr: chứa một số nguyên thể hiện là đỉnh trước nó. Quan trọng nhất của bài toán này là xử lý mảng Queue.Bình thường đoạn chương trình loang như sau:RepeatU:=queue[dau];Inc(dau);For v:= 1 to n doIf (tu u den v) and (v chua bi danh dau) thenBeginDan dau (v);Inc(cuoi):=v;Tr[v]:=u;End;Until dau>cuoi;Ta sẽ thay phần tử queue[dau] (cũng như queue[cuoi]) bằng cách chuyển dau(hay cuoi) thành một file là "dau.que" để lưu v như sau:Inc(cuoi);Str(cuoi,temp);Assign(f,temp+ ’.que’);Rewrite(f);Writeln(f,v);Close(f);Với cách đó bạn có thể lưu được rất nhiều đỉnh mà không cần quan tâm đến độ lớn của v (hay dau hoặc cuoi).Toàn bộ chương trình của bài toán này như sau:{$A+, B-, D+, E+, F-, G-, I+, L+, N-, O-,P-,Q+,R+,S+,T-,V+,X+}{$M 16384,0,655360}USES crt;Const fi= ’loang.in’;Fo= ’loang.out’;Ke= ’.ke’;Que= ’.que’;đ = ’.đ’;tr = ’.tr’;kq = ’.kq’;Var n,xp,di:longint;Time:longint;Procedure readf;Var f,f1: text;U,v: string;BeginAssign(f,fi);Reset(f);Readln(f,n,xp,di);For u:=1 to n do BeginStr(u,temp);Assign(f1,temp+ke);Rewrite(f1);Close(f1);End;While not seekeof(f) doBeginReadln(f,u,v);Str(u,temp);Assign(f1, temp+ke);Appent(f1);Writeln(f1,v);Close(f1);Assign(f1, temp+đ);rewrite(f1);Writeln(f1,0);Close(f1);Str(v,temp);Assign(f1,temp+đ);Rewrite(f1,0);Close(f1);End;Close(f);End;Procedure Loang;Var d,c:longint;U,v:longint;Te1,te2: string;Te3: sting;F,f1,f2,f3: text;Ok: byte;BeginD:=1; c:=1;Str(xp,te1);Assign(f, te1+đ);Rewrite(f);Writeln(f,1);Close(f);Assign(f,te1+tr);Rewrite(f,0); Close(f);Assign(f, ’1’ +que);Rewrite(f);Writeln(f,xp);Close(f);RepeatStr(d,te1);Assign(f,tel+que);Reset(f);Readln(f,u); {lay phan tu dau tien trong "queue"}Close(f);Inc(d);Str(u,te1);Assign(f,te1+ke); {Doc cac phan tu ke voi u}Reset(f);While not seekeof(f) doBeginReadln(f,v);Str(v,te2);Assign(f1,te2+đ);Reset(f1);Readln(f1,ok); {kiem tr xem v da bi danh dau hay chua}If ok=0 thenBeginAssign(f2, te2+đ);Rewrite(f2); {Danh dau v}Write(f2,1);Close(f2);Inc(c);Str(c, te3);Assign(f2, te3+que);Rewrite(f2); {Nhap v vao "queue"}Writeln(f2,v);Close(f2);Assign(f2,te2+tr);Rewrite(f2,u); {luu lai truoc cua v}Close(f2);End;Close(f1);End;Close(f); Until d>c;End;Procedure lankq;Var sb, ok, t,i:longint;Temp: string;F,f1:text;BeginAssign(f,fo);Rewrite(f);Str(di,temp);Assign(f1,temp+đ);Reset(f1);Readln(f1,ok);Close(f1);If ok=0 thenWriteln(f, ’Khong ton tai duong di’)ElseBeginSb:=0;RepeatInc(sb);Str(sb, temp);Assign(f1,temp+kq); {ghi dich vao file ket qua tam thoi}Readln(f1,t);Close(f1);Di:=t;Until di=0;Writeln(f,sb);For i:=sb downto 1 doBeginStr(i,temp);Assign(f1,temp+kq); {Doc lai cac file ket qua de chuyen sang file can ghi}Reset(f1);Readln(f1,t);Close(f1);Writeln(f,t);End;End;Close(f);End;BeginTime:=MemL[0:$46C];Docf; Loang;Lankq;Writeln((MemL[0:$46C] - time)/18.2:10:10);End.Trên đây chỉ là một thủ thuật nhỏ để lưu dữ liệu mà từ đó các bạn có thể tận dụng cho mình. Tôi xin lưu ý đây chỉ là một thủ thuật cho nên các bạn hãy dùng cho đúng lúc, đúng chỗ. Chương trình trên mới chỉ làm được với đồ thị có hướng. Các bạn có thể dễ dàng cải tiến lại chút ít để có thể làm được hai chiều (phần đọc file!). Nếu có ý kiến đóng góp mời các bạn gửi đến hòm thư hocpascal@yahoo.com Chúc các bạn thành công! . Một cách lưu dữ liệu mớiĐặng Thanh TùngCác bạn thân mến!Sau khi đọc số báo tháng 7 năm 2004 tôi đã rút ra một phương pháp mới về việc lưu dữ liệu. Như. time)/18.2:10:10);End.Trên đây chỉ là một thủ thuật nhỏ để lưu dữ liệu mà từ đó các bạn có thể tận dụng cho mình. Tôi xin lưu ý đây chỉ là một thủ thuật cho nên các bạn hãy