1. Trang chủ
  2. » Công Nghệ Thông Tin

Cấu trúc dữ liệu và giải thuật ĐH saigon

128 782 9
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Cấu trúc dữ liệu và giải thuật ĐH Sài Gòn
Tác giả Các Tác Giả
Trường học Trường Đại học Sài Gòn
Chuyên ngành Cấu trúc dữ liệu và giải thuật
Thể loại Giáo trình
Năm xuất bản 2010
Thành phố TP. Hồ Chí Minh
Định dạng
Số trang 128
Dung lượng 611,57 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Chương 1 TỔNG QUAN VỀ CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT A.Tóm tắt lý thuyết 1.Cấu trúc dữ liệu và giải thuật Xuyên suốt trong giáo trình này, chúng tôi muốn đề cập đến hai mặt quan trọng

Trang 1

TRƯỜNG ĐẠI HỌC SÀI GÒN KHOA CÔNG NGHỆ THÔNG TIN

BỘ MÔN KHOA HỌC MÁY TÍNH

-o0o -

BÀI TẬP CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT

(lưu hành nội bộ)

Năm 2010

Trang 2

Lời giới thiệu

Cấu trúc dữ liệu và giải thuật là học phần bắt buộc thuộc khối kiến thức cơ

sở ngành của sinh viên các chuyên ngành công nghệ thông tin và cũng là nội dung quan trọng ở các kỳ thi tốt nghiệp, thi hoàn chỉnh đại học các chuyên ngành công nghệ thông tin

Giáo trình này trình bày các chủ đề bài tập về:Tổng quan về cấu trúc dữ liệu

và giải thuật, tìm kiếm, sắp xếp, cấu trúc danh sách liên kết và cấu trúc cây theo ngôn ngữ C/C++ Mỗi chủ đề được thiết kế gồm các phần: Tóm tắt lý thuyết, một số dạng bài tập điển hình và một số đề bài tập chọn lọc Phần cuối của giáo trình có hướng dẫn giải cho một số bài tập tiêu biểu, đồng thời bổ sung một số đề thi mẫu để sinh viên tự rèn luyện kỹ năng phân tích vấn đề bài toán Giáo trình chỉ trình bày vấn

đề bài tập, còn các vấn đề lý thuyết liên quan thì bạn đọc có thể tham khảo chi tiết ở các quyển sách đã được chỉ ra ở phần tài liệu tham khảo

Quyển giáo trình này được biên soạn để làm tài liệu tham khảo khi giảng các học phần cấu trúc dữ liệu và giải thuật ở hệ đại học và cao đẳng Chúng tôi xin trân trọng giới thiệu với bạn đọc quyển giáo trình này và hy vọng rằng nó sẽ giúp cho việc giảng dạy và học tập học phần cấu trúc dữ liệu và giải thuật được thuận lợi hơn

Thành phố Hồ Chí Minh, ngày 06 tháng 09 năm 2010

CÁC TÁC GIẢ

Trang 3

Chương 1

TỔNG QUAN VỀ CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT

A.Tóm tắt lý thuyết

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

Xuyên suốt trong giáo trình này, chúng tôi muốn đề cập đến hai mặt quan

trọng của một vấn đề bài toán là cách thức tổ chức dữ liệu của bài toán và các phép

xử lý trên các dữ liệu đó

1.1.Cấu trúc dữ liệu

Cấu trúc dữ liệu của bài toán là cách thức tổ chức dữ liệu sao cho phản ánh

chính xác dữ liệu của bài toán và có thể dùng máy tính để xử lý các dữ liệu đó một cách hiệu quả

Một cấu trúc dữ liệu được đánh giá là tốt nếu nó thỏa mãn được các yêu cầu

như: Phản ánh đúng thực tế bài toán, phù hợp với các thao tác xử lý trên đó, tiết kiệm được tài nguyên hệ thống,…

1.2.Giải thuật (trong giáo trình này chúng tôi đồng nhất khái niệm thuật toán

và giải thuật)

Giải thuật là một bảng liệt kê các chỉ dẫn (hay các qui tắc) cần thực hiện theo từng bước xác định nhằm giải quyết một vấn đề bài toán

Các đặc trưng của giải thuật

Tính xác định: Ở mỗi bước các chỉ dẫn phải rõ ràng

Tính kết thúc: Giải thuật phải dừng sau một số hữu hạn bước

Tính đúng đắn: Giải thuật phải cho ra kết quả đúng theo yêu cầu của

bài toán

Tính tổng quát: Giải thuật phải áp dụng được cho các bài toán cùng

loại

1.3.Sự liên hệ giữa giải thuật và cấu trúc dữ liệu

Giải thuật và cấu trúc dữ liệu có mối liên hệ chặt chẽ với nhau Giải thuật phản ánh các phép xử lý, còn đối tượng xử lý của giải thuật là các dữ liệu; dữ liệu chứa đựng các thông tin cần thiết để thực hiện giải thuật Để xác định được giải thuật

Trang 4

phù hợp cần phải biết nó tác động đến những loại dữ liệu nào và khi chọn lựa một cấu trúc dữ liệu cũng cần phải hiểu rõ những thao tác nào sẽ được tác động lên nó

2.Độ phức tạp của một giải thuật

2.1.Phân tích thời gian thực hiện giải thuật

Với một bài toán chỉ có một giải thuật Việc chọn lựa giải thuật đưa đến kết quả nhanh là một đòi hỏi quan trọng Vấn đề là căn cứ vào những yêu tố nào để biết giải thuật này nhanh hơn giải thuật kia?

Rõ ràng thời gian thực hiện một giải thuật (hay chương trình để thực hiện giải

thuật đó) phụ thuộc vào nhiều yếu tố Một yếu tố cần chú ý đầu tiên tiên chính là kích thước của dữ liệu đưa vào Chẳng hạn thời gian để sắp xếp một dãy số chịu ảnh

hưởng bởi số lượng số của dãy số đó Nếu gọi n là số lượng này, thì thời gian thực hiện T của một giải thuật được biểu diễn như một hàm của n: T(n)

Các kiểu lệnh và tốc độ xử lý của máy tính, ngôn ngữ viết chương trình và chương trình dịch ngôn ngữ ấy đều ảnh hưởng đến thời gian thực hiện chương trình; nhưng những yếu tố này không đồng đều với mỗi loại máy tính Vì vậy không thể dựa vào chúng khi xác lập T(n) Điều đó cũng có nghĩa là T(n) không thể được biểu diễn thành đơn vị thời gian bằng giây, bằng phút được Tuy nhiên không phải vì thế

mà không thể so sánh được các giải thuật về mặt tốc độ Nếu như thời gian thực hiện của một giải thuật là T1(n)=Cn2 và thời gian thực hiện giải thuật khác là T2(n)= kn (C, n, k là các hằng số nào đó), thì khi n khá lớn, thời gian thực hiện giải thuật t2 ít hơn so với giải thuật T1 , như vậy nếu nói thời gian thực hiện giải thuật T(n) tỉ lệ với với n2 hay tỉ lệ với n cũng cho ta ý niệm về tốc độ thực hiện giải thuật đó khi n khá lớn (với n nhỏ thì việc xét T(n) không có ý nghĩa) Cách đánh giá thời gian thực hiện giải thuật độc lập với máy tính và các yếu tố liên quan tới máy như vậy sẽ dẫn tới khái niệm về “cấp độ lớn của thời gian thực hiện giải thuật” hay còn gọi là “độ phức tạp tính toán của giải thuật”

2.2.Thời gian chạy của các lệnh

Lệnh gán

Lệnh gán có dạng

X = <biểu thức>

Trang 5

Thời gian chạy của lệnh gán là thời gian thực hiện biểu thức Trường hợp hay gặp nhất là biểu thức chỉ chứa các phép toán sơ cấp, và thời gian thực hiện nó là O(1) Nếu biểu thức chứa các lời gọi hàm thì ta phải tính đến thời gian thực hiện hàm, và do đó trong trường hợp này thời gian thực hiện biểu thức có thể không còn phải O(1)

Giả sử thời gian đánh giá điều kiện là T0(n), thời gian thực hiện <lệnh 1> là

T1(n), thời gian thực hiện <lệnh 2> là T2(n) Thời gian thực hiện lệnh lựa chọn if-else

sẽ là thời gian lớn nhất trong các thời gian T0(n) + T1(n) và T0(n) + T1(n)

Trường hợp hay gặp là kiểm tra điều kiện chỉ cần O(1) Khi đó nếu T1(n) = O(f(n)), T2(n) = O(g(n)) và f(n) tăng nhanh hơn g(n) thì thời gian chạy của lệnh if-else là O(f(n)); còn nếu g(n) tăng nhanh hơn f(n) thì lệnh if-else cần thời gian O(g(n))

Thời gian chạy của lệnh lựa chọn switch được đánh giá tương tự như lệnh else, chỉ cần lưu ý rằng, lệnh if-else có hai khả năng lựa chọn, còn lệnh switch có thể

if-có nhiều hơn hai khả năng lựa chọn

Các lệnh lặp

for, while, do-while

Để đánh giá thời gian thực hiện một lệnh lặp, trước hết ta cần đánh giá số tối

đa các lần lặp, giả sử đó là L(n) Sau đó đánh giá thời gian chạy của mỗi lần lặp, chú

ý rằng thời gian thực hiện thân của một lệnh lặp ở các lần lặp khác nhau có thể khác nhau, giả sử thời gian thực hiện thân lệnh lặp ở lần thứ i (i=1,2, , L(n)) là Ti(n) Mỗi lần lặp, chúng ta cần kiểm tra điều kiện lặp, giả sử thời gian kiểm tra là T0(n) Như vậy thời gian chạy của lệnh lặp là:

Trang 6

Công đoạn khó nhất trong đánh giá thời gian chạy của một lệnh lặp là đánh giá số lần lặp Trong nhiều lệnh lặp, đặc biệt là trong các lệnh lặp for, ta có thể thấy ngay số lần lặp tối đa là bao nhiêu Nhưng cũng không ít các lệnh lặp, từ điều kiện lặp để suy ra số tối đa các lần lặp, cần phải tiến hành các suy diễn không đơn giản

Trường hợp hay gặp là: kiểm tra điều kiện lặp (thông thường là đánh giá một biểu thức) chỉ cần thời gian O(1), thời gian thực hiện các lần lặp là như nhau và giả

sử ta đánh giá được là O(f(n)); khi đó, nếu đánh giá được số lần lặp là O(g(n)), thì thời gian chạy của lệnh lặp là O(g(n)f(n))

2.3.Độ phức tạp tính toán của giải thuật

Nếu thời gian thực hiện một giải thuật là T(n)=Cn2 (với C là hằng số) thì ta nói: độ phức tạp tính toán của giải thuật này có cấp là n2 (hay cấp độ lớn của thời gian thực hiện giải thuật là n2) và ta ký hiệu T(n) = O(n2) - ký hiệu chữ O lớn Một cách tổng quát ta có thể định nghĩa như sau:

Một hàm f(n) được xác định là O(g(n))

f(n)=O(g(n)) và được gọi là có cấp g(n) nếu tồn tại một hằng số C và no sao cho f(n) ≤ C.g(n) khi n ≥ no

Nghĩa là f(n) bị chặn trên bởi một hằng số nhân với g(n), với mọi giá trị của n

từ một điểm nào đó Chú ý rằng O(C(f(n))=O(f(n))

Để xác định độ phức tạp tính toán của một giải thuật bất kỳ có thể dẫn tới những bài toán phức tạp Tuy nhiên trong thực tế, đối với một số giải thuật ta cũng

có thể phân tích được bằng một số quy tắc đơn giản

Quy tắc cộng

Giả sử T1(n) và T2(n) là thời gian thực hiện của hai đoạn chương trình P1 và

P2 mà T1(n) = O(f(n)) và T2(n)=O(g(n)), thì thời gian thực hiện P1 rồi P2 tiếp theo sẽ

Trang 7

Nếu tương ứng với P1 và P2 là T1(n) và T2(n), T1(n) = O(f(n)) và

T2(n)=O(g(n)), thì thời gian thực hiện P1 và P2 lồng nhau là T1(n) * T2(n) = O(f(n).g(n))

Chẳng hạn đoạn lệnh

for (int i=1;i<=n;i++)

for (int j=1;j<=n;j++ )

x=x+1;

có thời gian thực hiện là O(n.n)=O(n2)

Chú ý rằng có những trường hợp giải thuật không phải chỉ thuộc vào kích thước của dữ liệu vào mà còn phụ thuộc vào chính tính trạng của dữ liệu đó nữa Chẳng hạn việc sắp xếp một dãy số theo thứ tự tăng dần nếu gặp dãy số đưa vào đã

có đúng thứ tự thì sẽ khác với trường hợp dãy số đưa vào chưa có thứ tự hoặc có thứ

tự ngược lại, lúc đó khi phân tích thời gian thực hiện giải thuật ta sẽ phải xét tới: đối với mọi dữ liệu vào có kích thước n thì T(n) trong trường hợp thuật lợi nhất là thế nào? rồi T(n) trong trường hợp xấu nhất và T(n) trung bình ? Việc xác định T(n) trung bình thường khó vì sẽ phải dùng tới những công cụ toán phức tạp Trong các trường hợp mà T(n) trung bình khó xác định người ta thường đánh giá giải thuật qua giá trị xấu nhất của T(n)

2.4.Sự phân lớp các giải thuật

Thông thường các hàm thể hiện độ phức tạp tính toán của giải thuật có dạng hằng số, log2n, n, nlogn, n2, n3, 2n, n!, nn,…

Hằng số:Hầu hết các chỉ thị của các chương trình đều được thực hiện một lần hay một số số lần nhất định không phụ thuộc vào n

Các hàm như 2n, n!, nn được gọi là hàm mũ Một giải thuật mà thời gian thực hiện của nó có cấp là các hàm loại mũ thì tốc độ rất chậm Các hàm log2n, n, nlogn,

n2, n3 được gọi là các hàm loại đa thức Giải thuật với thời gian thực hiện có cấp hàm

đa thức thì thường là chấp nhận được

Các cấp độ thời gian chạy của giải thuật và tên gọi của chúng được liệt kê trong bảng sau:

O(1) hằng

Trang 8

Giải thuật này có thể trình bày ngắn gọn như sau:

Bước 1:Nhập hai số nguyên lớn a,b Để có thể thực hiện được phép a+b một cách tự nhiên thì khi nhập a,b thì a và b phải được giống hàng bên phải

Ví dụ: Giả sử a có m=5 chữ số, b có n=4 chữ số như sau:

a = 97895

b = 6478

Thì việc lưu trữ hai số này là như sau:

a[1] = 9, a[2]=7, a[3]=8, a[4]=9, a[5]=5

b[2] = 6, b[3]=4, b[4]=7, b[5]=8 Việc giống hàng bên phải cho a và b có thể tiến hành bằng cách đặt max là số lớn nhất trong hai số m và n

for i=max-m+1 to max

cin>>a[i];

for i=max-n+1 to max

Trang 9

cin>>b[i];

Bước 2:

Thực hiện phép hai số a,b theo cách thông thường: Nghĩa là cộng từng cặp chữ số a[i], b[i] bắt đầu từ phía bên phải và lưu kết quả cuối cùng lưu vào mảng c Lưu ý các mảng a,b bắt đầu từ chỉ số 1, còn mảng c bắt đầu từ chỉ số 0 và c[0] có thể bằng 0 (khi phép cộng hai chữ số cuối cùng không có nhớ) và cũng có thể khác 0 (khi phép cộng hai chữ số cuối cùng có nhớ)

sonho=0;

for (i=max;i >0;i )

{ c[i]=(a[i]+b[i]+ sonho)%10;

sonho =(a[i]+b[i]+ sonho)/10;

a.Tìm ma trận phân số tối giản

Trang 10

void nhapmangps(phanso ps[maxm][maxn], int &m, int &n);

void xuatmangps(phanso ps[maxm][maxn], int m, int n);

int sosanhps(phanso ps1, phanso ps2);

void bangphansotoigian(phanso ps[maxm][maxn], int m, int n);

void timpslonnhat(phanso ps[maxm][maxn], int m, int n);

Trang 13

Ví dụ 1.2.Bài toán quản lý

Cho một danh sách lưu thông tin của các nhân viên trong một công ty, thông tin gồm :

- Mã nhân viên (chuỗi, tối đa là 8 ký tự)

- Họ và tên (chuỗi, tối đa là 20 ký tự)

- Phòng ban (chuỗi, tối đa 10 ký tự)

- Lương cơ bản (số nguyên)

- Thưởng (số nguyên)

- Thực lãnh (số nguyên, trong đó thực lãnh = lương cơ bản + thưởng )

Hãy thực hiện các công việc sau:

a.Tính tổng thực lãnh tháng của tất cả nhân viên trong công ty

b.In danh sách những nhân viên có mức lương cơ bản thấp nhất

c.Đếm số lượng nhân viên có mức thưởng >= 1200000

d.In danh sách các nhân viên tăng dần theo phòng ban, nếu phòng ban trùng nhau thì giảm dần theo mã nhân viên

Trang 14

struct nhanvien nv[100],temp;

void nhap(nhanvien nv[], int &n);

void xuat(nhanvien nv[], int n);

void tongthuclanh(nhanvien nv[], int n);

void luongcbthapnhat(nhanvien nv[], int n);

void mucthuong(nhanvien nv[], int n);

void sapxep(nhanvien nv[], int n);

Trang 16

Ví dụ 1-4.Dãy con chung dài nhất

Cho hai dãy số a, b Hãy tìm dãy con chung dài nhất của hai dãy này Dãy con ở đây không nhất thiết phải là các phần tử liền nhau

Chẳng hạn cho hai dãy số sau:

Trang 17

0 0 1 0 0 0 0

0 0 0 0 0 0 0

0 0 0 1 0 0 0

0 0 0 0 0 0 1

Khi đó dãy cần tìm là dãy ứng với đường đi xuống dài nhất trong ma trận kề:

Là phần tử ở các vị trí 2, 4, 5 của dãy a hoặc là các vị trí 3, 4, 7 của dãy b

Dạng 5: Tối ưu hóa cấu trúc

Ví dụ 1.5.Dãy con có tổng lớn nhất

Cho dãy n số nguyên {a} Dãy con liên tiếp là dãy mà thành phần của nó là các thành phần liên tiếp nhau trong {a}, ta gọi tổng của dãy con là tổng tất cả các thành phần của nó Tìm tổng lớn nhất trong tất cả các tổng của các dãy con của {a}

Chẳng hạn n = 7 số sau:

Thì kết quả tổng dãy con cần tìm là 7

Giải thuật 1:

Giải thuật đơn giản nhất có thể viết ngay là: xét tất cả các cặp số nguyên L

và U thỏa mãn 1 ≤ L ≤ U ≤ n; đối với mỗi cặp như vậy ta tính tổng của dãy con a[L U] và so sánh tổng này với giá trị lớn nhất hiện có:

for (L=1;L<=n;L++) for (U=L;U<=n;U++) {

Trang 18

Ta có thể cải tiến giải thuật trên để có giải thuật với độ phức tạp là O(n2) bằng cách sử dụng hệ thức :

Tổng a[L U]= Tổng a[L U-1]+a[U]

maxsofar=0;

for (L=1;L<=n;L++) {

sum=0;

for (U=L;U<=n;U++) {

sum=sum+a[U];

maxsofar=max(maxsofar,sum);

} }

Giải thuật 3:

Tổng lớn nhất trong dãy con a[1 i] là tổng lớn nhất trong dãy con 1](gọi là maxsofar) hoặc tổng lớn nhất trong tất cả các tổng của các dãy con kết thúc

a[1 i-tại i (gọi là maxendinghere) Chúng ta có nhận xét rằng: Dãy con lớn nhất kết thúc a[1 i-tại

i là dãy con lớn nhất kết thúc tại vị trí i-1 được bổ sung thêm phần tử a[i] ở cuối hoặc

là dãy con rỗng trong trường hợp tổng của dãy con nhận được là số âm Ta có giải thuật như sau:

Trang 19

maxsofar 4 4 6 6 6 7 7 Giải thuật 3 này có độ phức tạp là O(n)

#include <iostream.h>

#include <conio.h>

void algorithm1(int a[], int n);

void algorithm2(int a[], int n);

void algorithm3(int a[], int n);

int max(int a,int b);

void input(int a[],int &n);

Trang 20

for (int U=L;U<=n;U++)

Trang 22

C.Bài tập

Viết chương trình hoàn chỉnh cho các bài toán sau đây

BT1-1.Cho dãy n số nguyên a0,a1, ,an-1

a.Tìm chiều dài của dãy con dài nhất chứa toàn số chẵn

b.Tìm dãy con liên tiếp tăng dài nhất

c.Tìm giá trị lớn thứ k của dãy

d.Tìm dãy con tăng chứa nhiều số nguyên tố nhất

e.Tìm tần số xuất hiện của các số

Cho biết độ phức tạp tính toán của các thuật toán trên

BT1-2.Cho dãy n số nguyên a0,a1, ,an-1 Hãy chuyển k phần tử đầu tiên của dãy về cuối dãy

BT1-3.Cho hai số nguyên lớn a và b; trong đó a có m chữ số và số b có n chữ số

Viết chương trình thực hiện các phép cộng, trừ, nhân hai số nguyên lớn

BT1-4.Xây dựng cấu trúc dữ liệu để lưu trữ đa thức có bậc tự nhiên n (0 ≤ n ≤ 100) trên trường số nguyên (ai , x ∈ Z)

a.Tính giá trị của đa thức tại giá trị x0 nào đó

b.Tính tổng, hiệu, tích, thương hai đa thức p và q

BT1-5.Cho mảng một chiều gồm n tọa độ điểm (giả sử hoành độ và tung độ của các

điểm là các số nguyên)

a.Tìm một điểm trong mảng xa gốc tọa độ nhất

b.Tìm tọa độ hai điểm gần nhau nhất

c.Xác định tọa độ của hình chữ nhật nhỏ nhất (tọa độ góc trên bên trái và tọa

độ góc dưới bên phải của hình chữ nhật) bao hết cả n điểm trên

Ví dụ n = 5 và tọa độ 5 điểm là: (0,0); (0,3); (3,3); (4,1); (4,4)

Thì kết quả câu a là điểm (4,4), kết quả câu b là (3,3) và (4,4), kết quả câu c

là (0,4); 4(,0)

Trang 23

BT1-6.Cho ma trận hai chiều m dòng n cột; trong đó mỗi phần tử là một phân số (giả

sử các tử số và mẫu số của các phân số là các số nguyên)

a.Tính tổng giá trị của các phân số trong mảng (kết quả là phân số ở dạng tối giản)

b.Tính tích giá trị của các phân số trong mảng (kết quả là phân số ở dạng tối giản)

c.Sắp xếp các phân số theo chiều tăng dần từ trái qua phải (theo dòng) và từ trên xuống dưới (theo cột)

BT1-7.Cho ma trận hai chiều m dòng n cột (m,n>=3); các phần tử là các số nguyên

dương

a.Hãy chuyển các số của ma trận về số chính phương nhỏ nhất lớn hơn hoặc bằng nó

b.Hãy chuyển các số của ma trận về số nguyên tố gần nó nhất

c.Tìm một mặt nạ 3 dòng 3 cột chứa nhiều số nguyên tố nhất (mặt nạ di có các cạnh song song với các cạnh của ma trận)

BT1-8.Cho một tập tin văn bản có tên là “BANGSO.INP” có cấu trúc như sau:

-Dòng đầu tiên ghi hai số m và n

-Trong m dòng tiếp theo mỗi dòng ghi n số nguyên; các số cách nhau ít nhất một khoảng cách

a.Xoay vòng các cột qua phải một vị trí (cột 0 sẽ qua cột 1, cột 1 qua cột 2, cột cuối cùng n-1 sẽ về vị trí của cột 0)

b.Xoay vòng các dòng xuống dưới một vị trí (dòng 0 sẽ qua dòng 1, dòng 1 qua dòng 2, dòng cuối cùng n-1 sẽ về vị trí của dòng 0)

c.Xoay vòng các dòng xuống dưới k vị trí (ví dụ khi k =2 thì nghĩa là dòng 0 chuyển đến dòng 2, dòng 1 chuyển đến dòng 3,… dòng n-1 chuyển đến dòng 1)

Kết quả của các câu a,b,c này được ghi vào tập tin BANGSO.OUT

BT1-9.Khai báo kiểu cấu trúc dữ liệu mảng mà mỗi phần tử chứa thông tin về một

quyển sách bao gồm các trường: Mã số sách, tên sách, tác giả, năm xuất bản

a.Đếm số sách xuất bản năm X

b.Sắp xếp danh sách theo mã số sách tăng

BT1-10.Trong mặt phẳng OXY cho đa giác lồi A1,A2,…,An

Trang 24

a.Tính chu vi của đa giác

b.Tính diện tích của đa giác

BT1-11.Xét tập tất cả phân số tối giản (số hữu tỉ) giữa 0 và 1 với mẫu số nhỏ hơn

BT1-12.Tìm độ phức tạp của các thuật toán sau:

a.Tìm giá trị lớn nhất của một dãy số

b.Tìm ước số chung lớn nhất của 2 số nguyên dương a,b

c.Kiểm tra xem n có phải là số nguyên tố hay không ?

Trang 25

Chương 2

TÌM KIẾM VÀ SẮP XẾP

A.Tóm tắt lý thuyết

1.Phương pháp tìm kiếm

1.1.Bài toán tìm kiếm

Cho dãy n số nguyên a0,a2, ,an-1 và một số nguyên x Hãy tìm xem x có thuộc vào dãy số trên hay không ? Nếu tìm được ở vị trí thứ i thì xuất kết quả là i, ngược lại nếu không tìm thấy thì xuất kết quả là –1 (chú ý dãy bắt đầu từ chỉ số 0)

Sau đây là hai giải thuật tìm kiếm thường được sử dụng nhất

1.2.Tìm kiếm tuyến tính

Bắt đầu từ phần tử thứ nhất a[0], ta lần lượt so sánh x với các giá trị a[i] Nếu

có a[i] bằng x thì i chính là kết quả cần tìm và kết thúc giải thuật Nếu trong dãy không có số a[i] nào bằng x thì xuất kết quả là –1 và cũng kết thúc giải thuật

int LinearSearch ( int a[], int n, int x )

Hiệu quả của giải thuật được nâng cao bằng cách đặt thêm phần tử cầm canh (sentinel) ở cuối mảng (a[n]=x) để bảo đảm rằng trong dãy a[i] lúc này luôn có phần

tử bằng x và vòng lặp while luôn kết thúc Do đó không cần kiểm tra điều kiện (i<n) nữa

int LinearSearch ( int a[], int n, int x )

{

int i = 0; // mảng gồm n phần tử từ a[0] a[n-1]

a[n] = x; // thêm phần tử thứ n+1

Trang 26

while (a[i]!=x)

i++;

if( i==n)

return -1; // tìm hết nhưng không có x

return i; // tìm thấy x tại vị trí i

}

Giải thuật tìm kiếm tuyến tính có độ phức tạp tính toán là O(n)

1.3.Tìm kiếm nhị phân

(với phương pháp tìm kiếm nhị phân thì dãy n số a0,a1,a2, ,an-1 phải có thứ tự

- giả sử đó là thứ tự không giảm)

Giả sử dãy tìm kiếm hiện hành bao gồm các phần tử aleft,…,arịght

Gọi midle=(left+right)/2

Nhận xét rằng nếu x > a[i] thì x chỉ có thể xuất hiện bên phải a[i] - nghĩa là trong đoạn [amidle+1, aright] của dãy, ngược lại nếu x < a[i] thì x chỉ có thể xuất hiện bên trái a[i] - trong đoạn [aleft, amidle-1] của dãy, nhờ vậy giải thuật sẽ thu gọn phạm vi tìm kiếm một cách đáng kể Mỗi lần so sánh loại được một nửa thông tin không có ích

Ví dụ; Cho dãy số

1 3 4 5 6 7 8 9 10 12 Cần tìm phần tử x=3

Bước 1: left=0, right=9, mid=4, a[mid]= 6

Do x < a[mid] nên right=3

Do left<=right tiếp tục qua bước 2

Bước 2: left=0, right=3, mid=1, a[mid]= 3

Do x = a[mid] nên vị trí cần tìm là mid =1

Giả sử cần tìm phần tử x=11

Bước 1: left=0, right=9, mid=4, a[mid]= 6

Do x > a[mid] nên left=5

Do left<=right tiếp tục qua bước 2

Bước 2: left=5, right=9, mid=7, a[mid]= 9

Do x > a[mid] nên left=8

Trang 27

Do left<=right tiếp tục qua bước 3

Bước 3: left=8, right=9, mid=8, a[mid]= 10

Do x > a[mid] nên left=9

Do left<=right tiếp tục qua bước 4

Bước 4: left=9, right=9, mid=9, a[mid]= 12

Do x < a[mid] nên left=10

Do left> right vòng lặp kết thúc và kết quả trả về là -1

Cài đặt theo kiểu đệ quy

int BinarySearch_Recursive(int a[],int n,int x,int left,int right)

return BinarySearch_Recursive(a,n,x,mid+1,right);

}

Cài đặt theo kiểu không đệ quy

int BinarySearch(int a[],int n,int x)

{

int left=0,right=n-1,mid;

do {

mid=(left+right)/2;

if (x==a[mid]) return mid;

else

if (x<a[mid]) right=mid -1;

else left=mid+1;

Trang 28

} while (left<=right);

Cho một dãy n số, hãy sắp xếp dãy số theo thứ tự tăng dần (hoặc giảm dần)

Ví dụ dãy ban đầu : S1 = {5 6 1 9 8 6}

Dãy sau khi biến đổi: S2 = {1 5 6 6 8 9}

•Khái niệm nghịch thế

Xét một mảng n số a0, a1, , an-1 Nếu có i < j và ai > aj, thì ta gọi đó là một nghịch thế

Mảng chưa sắp xếp sẽ có nghịch thế, và ngược lại mảng đã có thứ tự sẽ không chứa nghịch thế Để sắp xếp một mảng, ta có thể tìm cách làm giảm số các nghịch thế trong mảng này bằng cách hoán vị các phần tử ai,aj nếu có i < j và ai > aj

theo một quy luật nào nào đó

Hai thao tác so sánh và gán là những thao tác cơ bản của hầu hết các giải thuật sắp xếp, các kết quả của các phép so sánh cho phép giải thuật quyết định những tính huống cần phải thay đổi vị trí trong dãy

Sau đây là một số phương pháp sắp xếp thường dùng nhất

2.2.Phương pháp đổi chổ trực tiếp

Như đã đề cập ở trên, để sắp xếp một dãy số, ta có thể xét các nghịch thế có trong dãy và làm triệt tiêu dần chúng đi Ý tưởng chính của giải thuật đổi chỗ trực tiếp là xuất phát từ đầu dãy, tìm tất cả nghịch thế chứa phần tử này, triệt tiêu chúng bằng cách đổi chỗ phần tử này với phần tử tương ứng trong cặp nghịch thế Lặp lại quá trình trên với các phần tử tiếp theo trong dãy

Ví dụ: Cho dãy số 5 6 1 9 8 6

Thì kết quả từng bước như sau:

dòng i j a[0] a[1] a[2] a[3] a[4] a[5]

0 0 2 5 6 1 9 8 6

Trang 29

for (int i=0; i<n-1;i++)

for (int j=i+1;j<n ;j++)

•Ví dụ :

Cho dãy số 5 6 1 9 8 6

Nếu dãy cần được sắp theo thứ tự tăng dần,

dòng i j a[0] a[1] a[2] a[3] a[4] a[5]

0 0 2 5 6 1 9 8 6

1 1 2 1 6 5 9 8 6

2 2 2 1 5 6 9 8 6

3 3 5 1 5 6 9 8 6

Trang 30

swap( a[min], a[i] );

}

}

Độ phức tạp tính toán của giải thuật là: O(n2)

2.4.Phương pháp nổi bọt (Bubble Sort)

Xuất phát từ cuối dãy (hoặc đầu dãy), đổi chỗ bất kỳ hai phần tử kế cận nào ngược thứ tự để đưa phần tử nhỏ nhất (hoặc lớn nhất) trong các cặp phần tử đó về vị trí đúng là đầu (cuối) dãy hiện hành, kế tiếp không xét đến nó nữa ở bước tiếp theo,

do vậy ở lần xử lý thứ i sẽ có vị trí đầu dãy là i Lặp lại quá trình trên cho đến khi không còn cặp phần tử nào để xét

•Ví dụ:

Cho dãy số 5 6 1 9 8 6

Nếu dãy cần được sắp theo thứ tự tăng dần,

dòng j-1 j a[0] a[1] a[2] a[3] a[4] a[5]

Trang 31

void bubblesort(int a[],int n)

•Ví dụ :

Cho dãy số 5 6 1 9 8 6

Nếu dãy cần được sắp theo thứ tự tăng dần,

Trang 32

Độ phức tạp tính toán của giải thuật là: O(n2)

2.6.Sắp xếp nhanh (Quick sort)

Quick Sort được thực hiện bằng cách phân hoạch dãy đã cho thành hai phần sau đó sắp các phần này riêng biệt nhau như sau:

Đầu tiên chọn phần tử tùy ý x=a[(l+r)/2] làm mốc - là phần tử sẽ rơi vào vị trí đặt cuối cùng của nó, kế tiếp quét từ đầu trái của mảng cho đến khi gặp một phần tử lớn hơn x và quét từ đầu phải của mảng cho đến khi gặp một phần tử bé hơn x, hai phần tử dừng việc quét dĩ nhiên là không đúng chỗ trong mảng kết quả cuối cùng nên phải hoán vị chúng

Sau khi thực hiện bước này thì bảo đảm rằng tất cả các phần tử ở bên trái con trỏ trái nhỏ hơn x và các phần tử ở bên phải con trỏ phải lớn hơn x

Ở đây x là phần tử phân hoạch; i, j lần lượt là con trỏ quét từ phía trái và phía phải

Sau bước này ta đã chia dãy thành hai dãy con; ta lại tiếp tục phân hoạch cho mỗi dãy con này

•Ví dụ :

Cho dãy số 5 6 1 9 8 6

Nếu dãy cần được sắp theo thứ tự tăng dần,

dòng l r x a[0] a[1] a[2] a[3] a[4] a[5]

Trang 33

Độ phức tạp tính toán của giải thuật là: O(nlogn)

2.7.Sắp xếp cây (Heap sort)

Để tìm phần tử nhỏ nhất ở bước i, phương pháp sắp xếp chọn trực tiếp đã không tận dụng được các thông tin đã có được do các phép so sánh ở bước i-1 Phương pháp Heap Sort khắc phục được nhược điểm này

Tính chất 1: Nếu al,.,ar là một Heap thì khi cắt bỏ một số phần tử ở hai đầu của

Heap thì dãy con còn lại vẫn là một Heap

Trang 34

Tính chất 2: Nếu các phần tử a1, ,an là một Heap thì phần tử a1 (đầu heap) luôn là phần tử lớn nhất trong Heap

Tính chất 3: Mọi dãy al,al+1,…,ar với 2l > r là một Heap

•Giải thuật

Giải thuật heap sort gồm hai giai đoạn sau:

Giai đoạn 1: Hiệu chỉnh dãy số ban đầu thành Heap

Bước 1:Đưa phần tử lớn nhất về vị trí đứng ở cuối dãy

r = n;

Hoán vị (a1,ar) Bước 2: Loại bỏ phần tử lớn nhất ra khỏi Heap r=r-1;

Hiệu chỉnh phần còn lại của dãy từ al đến ar thành một Heap

Bước 3:Nếu r >1 ( heap còn phần tử) : lặp lại bước 2

Ngược lại: dừng Dựa vào tính chất 3, ta có thể thực hiện giai đoạn 1 bằng cách bắt đầu từ heap mặc nhiên an/2+1, an/2+2,…,an, lần lượt thêm vào các phần tử an/2, an/2-1,…,a1 ta sẽ nhận được Heap theo mong muốn Như vậy giải đoạn 1 tương đương với n/2 lần thực hiện bước 2 của giai đoạn 2

•Cài đặt

Để cài đặt Heap sort cần xây dựng một số thủ tục phụ trợ:

Giả sử có al,al+1,…ar, trong đó đoạn al+1,…ar, đã là một heap ta cần xây dựng

al,al+1,…,ar thành một heap để làm điều này ta lần lượt xét quan hệ của một phần tử

ai nào đó với các phần tử liên đới của nó trong dãy là a2i và a2i+1, nếu nó vi phạm quan hệ của heap thì đổi chổ ai với phần tử liên đới thich hợp của nó – việc đổi này

có thể gây phản ứng dây chuyền

2.Hiệu chỉnh a o , ,a n-1 thành heap

Cho một dãy bất kỳ al,…,ar , theo tính chất 3 ta có dãy an/2+1, an/2+2,…,an đã là một heap Ghép thêm phần tử an/2 vào bên trái của heap hiện hành và hiệu chỉnh lại dãy an/2,an/2+1, ,ar thành heap

Trang 36

Độ phức tạp tính toán của giải thuật là: O(nlog2n)

2.8.Sắp xếp trộn trực tiếp (Merge sort)

Bước 1: Chuẩn bị

k=1;// k là chiều dài của dãy con trong bước hiện hành

Bước 2:Tách dãy a0,a1,…an-1 thành hai dãy b,c theo nguyên tắc luân phiên từng nhóm

Trang 38

{ i=1;j=n;k=n+1;q=2*n;

} else { i=n+1;j=2*n;k=1;q=n;

}

do {

{

} else

{

} k=k+d;

} while (s!=0)

{

} while (r!=0) {

Trang 39

a[k]=a[j];k=k+d;j=j-1;r=r-1;

} d=-d;t=k;k=q;q=t;

} while (m!=0);

for (i=0;i<n;i++) a[i]=a[i+1];

}

Độ phức tạp tính toán của giải thuật là: O(nlog2n)

B.Các dạng bài tập

Dạng 1: Ứng dụng tìm kiếm

Ví dụ 2-1.Cho dãy n số nguyên ai

a.Viết hàm tìm xem x có thuộc dãy ai hay không ? Nếu có trả về 1, nếu không có trả

về 0

b.Viết hàm tìm giá trị lớn nhì của dãy

c.Tìm các giá trị xuất hiện nhiều lần nhất

Dạng 2: Ứng dụng sắp xếp

Ví dụ 2-2.Cho dãy n số nguyên ai

a.Viết hàm tìm giá trị lớn thứ k của dãy

b.Hãy cho biết k giá trị khác nhau lớn nhất của dãy

C.Bài tập

Viết chương trình hoàn chỉnh cho các bài toán sau đây

BT2-1.a.Cài đặt hoàn chỉnh các giải thuật sau: Tìm kiếm tuyến tính, tìm kiếm nhị

phân

b.Hãy chứng minh độ phức tạp của các giải thuật trên

BT2-2.a.Cho dãy n số nguyên sau:

Trang 40

8 5 1 3 6 9 12 4 7 10 Hãy mô phỏng các bước sắp xếp tăng dần dãy số trên bằng các giải thuật đổi chỗ trực tiếp, chọn trực tiếp, chèn trực tiếp và nổi bọt

b.Cài đặt hoàn chỉnh các giải thuật: Sắp xếp đổi chỗ trực tiếp, sắp xếp chọn trực tiếp, sắp xếp chèn trực tiếp, sắp xếp nổi bọt

c.Hãy chứng minh độ phức tạp cho các giải thuật trên

BT2-3.Cho dãy gồm n số nguyên sau:

8 5 1 3 6 9 12 4 7 10 Hãy mô phỏng các bước sắp xếp tăng dần dãy số trên bằng các giải thuật sắp xếp nhanh, sắp xếp trộn trực tiếp và sắp xếp cây

b.Cài đặt hoàn chỉnh các giải thuật: Sắp xếp nhanh (quick sort), sắp xếp trộn trực tiếp (merge sort), sắp xếp cây (heap sort)

c.Hãy chứng minh độ phức tạp cho các giải thuật trên

BT2-4.Cho dãy n số nguyên a0,a1,…,an-1

a.Hãy cho biết vị trí của k phần tử có giá trị lớn nhất của dãy

b.Sắp xếp các phần tử tăng dần theo tổng các chữ số của từng phần tử

c.Hãy xóa tất cả các số nguyên tố có trong dãy

BT2-5.Cho ma trận hai chiều m dòng n cột; các phần tử là các số nguyên dương

a.Tìm số nguyên tố lớn nhất của mảng

b.Tìm những dòng của mảng có chứa giá trị nguyên tố

c.Tìm những dòng của mảng chỉ chứa các số nguyên tố

BT2-7.Cho ma trận hai chiều m dòng n cột; các phần tử là các số nguyên dương

a.Tìm dòng có tổng lớn nhất

b.Sắp xếp các dòng sao cho dòng có tổng các phần tử lớn hơn sẽ nằm phía trên

c.Sắp xếp sao cho các dòng có nhiều số nguyên tố hơn sẽ nằm phía trên

BT2-8.Cho mảng một chiều gồm n phần tử là các số nguyên không âm Hãy sắp xếp

các số chẵn trong mảng theo thứ tự tăng, sắp xếp các số lẻ theo thứ tự giảm dần, các

số 0 giữ nguyên vị trí

BT2-9.Cho mảng một chiều gồm n phần tử là các số nguyên dương Hãy sắp xếp sao

cho các phần tử chẵn ỏ đầu, các phần tử lẻ về cuối Yêu cầu độ phức tạp là O(n)

Ngày đăng: 27/03/2014, 12:51

Nguồn tham khảo

Tài liệu tham khảo Loại Chi tiết
[2]CTDL, phân tích giải thuật và phát triển phần mềm, NXB Giáo dục, 2007. Hồ Thuần, Hồ Cẩm Hà, Trần Thiên Thành [3]Cấu trúc dữ liệu và giải thuậtĐỗ Xuân Lôi - ĐHBK – ĐHQG Hà Nội Sách, tạp chí
Tiêu đề: CTDL, phân tích giải thuật và phát triển phần mềm
Tác giả: Hồ Thuần, Hồ Cẩm Hà, Trần Thiên Thành
Nhà XB: NXB Giáo dục
Năm: 2007
[5]Những viên ngọc trong kỹ thuật lập trình. Jhon Bentley Sách, tạp chí
Tiêu đề:
[1]Nhập môn cấu trúc dữ liệu và giải thuật Trần Hạnh Nhi–Dương Anh Đức–ĐHKHTN-ĐHQGTPHCM Khác
[4]Cấu trúc dữ liệu và giải thuật, ĐHQG Hà Nội, 2007 Đinh Mạnh Tường Khác
[6]Bộ đề thi môn Cấu trúc dữ liệu và giải thuật dành cho các lớp đại học Khoa Công nghệ thông tin, trường Đại học Sài Gòn Khác
[7]Bộ đề thi hoàn chỉnh đại học môn cấu trúc dữ liệu Đại học Khoa học tự nhiên, ĐHQG TPHCM Khác

TỪ KHÓA LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w