Với một cơ sỡ dữ liệu khổng lồ, việc đưa ra một phương phápnhằm giải quyết vấn đề có cách hiệu quả và nhanh chống luôn được sự quan tâm của các nhà phát triển phần mềm.. Thông qua chương
Trang 2PHẦN MỞ ĐẦU
1 Lý do chon đề tài.
Với sự phát triển của khoa học kỹ thuật, công nghệ thông tin nói chung và
bộ môn cấu trúc dữ liệu và giải thuật nói riêng ngày càng được ứng dụng rộng rãi trong nhiều lĩnh vực Với một cơ sỡ dữ liệu khổng lồ, việc đưa ra một phương phápnhằm giải quyết vấn đề có cách hiệu quả và nhanh chống luôn được sự quan tâm của các nhà phát triển phần mềm Thông thường dữ liệu được biểu diễn dưới dạng danh sách liên kết Với việc truy xuất dữ liệu chưa đạt hiệu quả cao Sử dụng cấu trúc dữ liệu cây là một phương pháp tăng hiệu quả cao trong các thao tác xử lý Vấn đề đặt ra với việc sử dụng cấu trúc dạng cây, chúng ta cần dùng giải thuật nào với từng dạng dữ liệu để đạt hiệu quả cao nhất Chúng ta cùng tìm hiểu phương pháp của cây phân đoạn
2 Mục tiêu đề tài.
Thông qua chương trình đồ án “ Tìm hiểu về cây phân đoạn” giúp cho bản thân trong quá trình học tập chung và tiếp cận một phương pháp mới để giải quyết một số bài toán tin
Dù đã dành nhiều thời gian tìm hiểu và hoàn thiện bài tập nhưng chắc chắn se không tránh khỏi sai sót Em mong se nhận được những lời nhận xét và đóng góp ý kiến
từ thầy cô để được hoàn thiện hơn
PHẦN I CƠ SỞ LÝ THUYẾT CÂY PHÂN ĐOẠN
Trang 31.1 Yêu cầu giải bài toán trong tin học
Để hình dung được một bài toán tin học bạn cần thực hiện một số bước sau:
nhằm để hiểu đề
bài toán và mối quan hệ giữa các đại lượng
bằng các ví dụ đã đưa ra ở bước đầu
Xây dựng thành các hàm hay đoạn con nhằm dễ quản lý và thực hiện cải tiến
Trước khi bước vào tìm hiểu tài liệu bạn phải có những kiến thức cơ bản sau:
1 Biết thực hiện một bài toán tin như thế nào
2 Biết đọc mã giả, sơ đồ khối là kiến thức tối thiểu ( Biết ngôn ngữ lập trình Choặc cao hơn là một lợi thế) Bởi vì khi trình bày vấn đề tôi sử dụng mã giã
và khi thực hiện chương trình tôi viết bằng ngôn ngữ C
3 Tối thiểu phải đọc qua lý thuyết dưới đây và liên hệ với từng giải thích ở ví
dụ đầu tiên Sau đó các bài sau không trình bày lại kiến thức căn bản và cáckhái niệm
1.2-Cây phân đoạn.
Cây phân đoạn là cấu trúc dữ liệu cho phép thực hiện các thao tác truy vấn
và cập nhật trên một đoạn các phần tử của mảng với chi phí thực hiện mỗi thao tác
có mức độ phức tạp là hàm logarit Cây phân đoạn là một cây nhị phân đầy đủ, để
quản lý các phần trong đoạn [i j] của mảng, cây phân đoạn được tổ chức như sau:
•
Trang 4ví dụ: Sau đây là cây phân đoạn quản lý đoạn [1 8]:
Mỗi nút của cây lưu trữ thông tin của một đoạn cố định Thông tin này thường là
tổng các phần tử, giá trị lớn nhất , giá trị nhỏ nhất…của các phần tử trong đoạn
Các nút lá của cây lưu trữ giá trị tương ứng với các phần tử của mảng
Trang 5PHẦN II PHÂN TÍCH VÀ THIẾT KẾ MỘT SỐ BÀI TOÁN
2.1 Ví dụ cây nhị phân hoàn chỉnh
Tóm tắt đề:
Cây phân đoạn được sử dụng khi chúng ta có một mảng A, thực hiện các chỉnh sửa
và truy vấn trên các đoạn liên tiếp Ví dụ: ta có một mảng A với 105 phần tử và cầnthực hiện Q thao tác, mỗi thao tác thuộc 1 trong 2 loại:
Trang 6Cài đặt:
int n; // kích thước mảng
int t[2 * N];
void build() { // khởi tạo cây
for (int i = n - 1; i > 0; i)
t[i] = t[i<<1] + t[i<<1|1];
Trang 72.2 Bài toán Sereja and Brackets.
Tóm tắt đề:
Cho một dãy ngoặc độ dài N (N≤106), cho M truy vấn có dạngli,ri(1≤li≤ri≤N) Yêu cầu của bài toán là với mỗi truy vấn tìm một chuỗi con(không cần liên tiếp) của chuỗi từ li đến ri dài nhất mà tạo thành dãy ngoặc đúng
Lời giải:
Với mỗi nút(ví dụ như nút id, quản lý đoạn [l,r]) chúng ta lưu ba biến nguyên:
độ dài optimal trong đoạn
độ dài optimal trong đoạn
Cài đăt:
Ta tạo 1 kiểu dữ liệu cho 1 nút của cây ST như sau:
Trang 8Node st[MAXN * 4]; Khai báo cây ST:
Để tính thông tin ở nút id quản lý đoạn [l,r], dựa trên 2 nút con 2∗id và 2∗id+1, tađịnh nghĩa 1 thao tác kết hợp 2 nút của cây ST:
Node operator + (const Node& left, const Node& right) {
Node res;
// min(số dấu "(" thừa ra ở cây con trái, và số dấu ")" thừa ra ở cây con phải)
int tmp = min(left.open, right.close);
// Để xây dựng kết quả tối ưu ở nút id, ta nối dãy ngoặc tối ưu ở 2 con, rồi thêm // min(số "(" thừa ra ở con trái, số ")" thừa ra ở con phải)
res.optimal = left.optimal + right.optimal + tmp;
res.open = left.open + right.open - tmp;
res.close = left.close + right.close - tmp;
return res;
}
Trang 9void build(int id, int l, int r) {
Trang 102.3 Bài toán KQUERY.
Tóm tắt đê:
Sắp xếp các truy vấn theo thứ tự tăng dần của k
Lúc đầu mảng b gồm toàn bộ các số 1
Với mỗi truy vấn, ta xem trong mảng a có những phần tử nào lớn hơn giá trị k củatruy vấn trước, và nhỏ hơn giá trị k của truy vấn hiện tại, rồi đánh dấu các vị trí đó
Trang 11trên mảng b thành 0 Để làm được việc này một cách hiệu quả, ta cũng cần sắp xếplại mảng a theo thứ tự tăng dần.
// so sánh 2 truy vấn để dùng vào việc sort
bool operator < (const Query& a, const Query &b) {
return a.k < b.k;
}
Trang 12vector< Query > queries; // các truy vấn
// Đọc vào các truy vấn
readInput();
// Sắp xếp các truy vấn
sort(queries.begin(), queries.end());
// Khởi tạo mảng id sao cho:
// a[id[1]], a[id[2]], a[id[3]] là mảng a đã sắp xếp tăng dần
// Khởi tạo Segment Tree
Vậy ta có thể viết hàm xây dựng cây như sau:
void build(int id, int l, int r) {
Trang 13Một hàm cập nhật khi ta muốn gán lại một vị trí bằng 0:
void update(int id, int l, int r, int u) {
update(id*2, l, mid, u);
update(id*2 + 1, mid+1, r, u);
st[id] = st[id*2] + st[id*2+1];
}
Và cuối cùng là thực hiện truy vấn lấy tổng một đoạn:
int get(int id, int l, int r, int u, int v) {
Trang 14Bài này tương đối giống với bài KQUERY đã phân tích ở trên, tuy nhiên vì
có thao tác cập nhật, nên ta buộc phải xử lý online.
Phương pháp
Có logN nút mà ta cần xét khi trả lời truy vấn của đoạn [u,v].
Nếu trên mỗi nút chúng ta có thể lưu lại danh sách các phần tử đó theo thứ tự tăngdần, ta có thể tìm ra kết quả ở mỗi nút bằng tìm kiếm nhị phân
Vì thế với mỗi nút ta lưu lại một vector chứa các phần tử từ l đến r theo thứ tự tăng
dần Điều này có thể được thực hiện với bộ phức tạp bộ nhớ là O(NlogN) do mỗi phần tử có thể ở tối đa O(logN) nút (độ sâu của cây không quá O(logN)) Ở mỗi
nút cha có ta có thể gộp hai nút con vào nút cha bằng phương pháp giống nhưMerge Sort (lưu lại hai biến chạy và so sánh lần lượt từng phần tử ở hai mảng) để
có thể xây dựng cây trong O(NlogN).
Trang 15Cài đặt:
Hàm xây cây có thể được như sau:
void build(int id, int l, int r) {
Trang 16Cho dãy số A với N phần tử (N≤50,000) Bạn cần thực hiện 2 loại truy vấn:
1 Cộng tất cả các số trong đoạn [l,r] lên giá trị val
2 In ra giá trị lớn nhất của các số trong đoạn [l,r]
Trang 17Truy vấn đoạn [u,v] Giả sử ta gọi F(id) là giá trị lớn nhất trong đoạn mà nút
id quản lý Trong lúc cập nhật, muốn hàm này thực hiện với độ phức tạp không quáO(logN), thì khi đến 1 nút id quản lý đoạn [l,r] với đoạn [l,r] nằm hoàn toàn trongđoạn [u,v], thì ta không được đi vào các nút con của nó nữa (nếu không độ phứctạp se là O(N) do ta đi vào tất cả các nút nằm trong đoạn [u,v]) Để giải quyết, tadùng kĩ thuật Lazy Propagation như sau:
đều được cộng thêm T(id)
ta đã "đẩy" giá trị của mảng T ở tất cả các nút tổ tiên của id′ xuống id′ Đểlàm được điều này, ở các hàm get và update, trước khi gọi đệ quy xuống cáccon 2∗id và 2∗id+1, ta phải gán:
int lazy; // giá trị T trong phân tích trên
int val; // giá trị lớn nhất
} nodes[MAXN * 4];
Trang 18update(id*2, l, mid, u, v, val);
update(id*2+1, mid+1, r, u, v, val);
nodes[id].val = max(nodes[id*2].val, nodes[id*2+1].val);
}
Hàm lấy giá trị lớn nhất:
Trang 19int get(int id, int l, int r, int u, int v) {
return max(get(id*2, l, mid, u, v),
get(id*2+1, mid+1, r, u, v));
}
PHẦN III MỐT SÔ BÀI TOÀN KHÁC
3.1 Bài toán Frequent values
Ngoài ra, được cung cấp một số truy vấn bao gồm các chỉ số i và j ( 1 i ≤ j ≤ n ).Đối với mỗi truy vấn, hãy xác định giá trị thường xuyên nhất trong số các số
3.2 NKLINEUP - Xếp hàng
Hàng ngày khi lấy sữa, N con bò của bác John (1 ≤ N ≤ 50000) luôn xếphàng theo thứ tự không đổi Một hôm bác John quyết định tổ chức một trò chơi chomột số con bò Để đơn giản, bác John se chọn ra một đoạn liên tiếp các con bò để
Trang 20Bác John đã chuẩn bị một danh sách gồm Q (1 ≤ Q ≤ 200000) đoạn các con bò vàchiều cao của chúng (trong phạm vi [1, 1000000]) Với mỗi đoạn, bác John muốnxác định chênh lệch chiều cao giữa con bò thấp nhất và cao nhất Bạn hãy giúp bácJohn thực hiện công việc này!
con bò thứ i
N), cho biết đoạn các con bò từ A đến B
Trang 21Đàn bò đọc và thực thi một danh sách gồm M (1 <= M <= 100,000) thao tác mô tảbởi một trong hai số nguyên (0 <= thao tác <= 1).
Thao tác thứ nhất (mô tả bởi số 0) theo sau bởi hai số nguyên S_i và E_i (1 <= S_i
<= E_i <= N) cho biết công tắc đầu và công tắc cuối Đàn bò se bấm mỗi công tắc
từ S_i đến E_i đúng một lần
Thao tác thứ hai (mô tả bởi số 1) yêu cầu đàn bò đến xem có bao nhiêu ngọn đèngiữa S_i và E_i (1 <= S_i <= E_i <= N) đang bật Hãy giúp bác John đảm bảo rằngđàn bò trả lời đúng bằng cách xử lý danh sách và trả về các kết quả đúng
Dữ liệu
khoảng trắng: thao tác, S_i, và E_i
KẾT LUẬN
1.Kết quả đạt được
Khi giải các bài tập bằng cây phân đoạn giúp em đánh giá, phân tích bài toán
và hình thành tư duy theo công thức
Đặc biệt quá trình thực hiện đồ án cơ sở giúp em làm quen với việc trình bày hoànchỉnh một thuật toán cũng như đồ án tin học
Trang 22tiếp cận QHĐ ở mức độ đơn giản Các bài tập được giải quyết để tìm ra lời giải vàkhông đặt ra vấn đề tối ưu bài toán với cấu trúc dữ liệu tốt hơn
Bên cạch các bài đã giải được còn khá nhiều bài toán chưa giải quyết
Tài liệu tham khảo
1 Tài liệu chia sẽ của thầy Phạm Anh Phương
2 Chuyên đề cấu trúc dữ liệu đặc biệt – Nguyễn Minh Hiếu
3 Website http://nvoi.info
4 Website http://vi.wikipedia.org
Trang 23NHẬN XÉT CỦA GIẢNG VIÊN HƯỚNG DẪN