Professional Documents
Culture Documents
GIÁO TRÌNH
CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT
ĐỒNG NAI
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 1
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
MỤC LỤC
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 3
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Cấu trúc dữ liệu và giải thuật là một môn học bắt buộc trong chương trình đào tạo nghề
Quản Trị Mạng. Giáo trình này được hình thành dựa trên nội dung giảng dạy nhiều năm tại
khoa Công Nghệ Thông Tin Trường TCN Cơ Điện Đông Nam Bộ của nhiều Giảng viên.
Chương 1: Trình bày một số kiến thức về cấu trúc dữ liệu và giải thuật;
Giáo trình được soạn trên cơ sở chương trình đào tạo của Khoa. Một số kiến thức về
thuật toán và kỹ thuật lập trình sinh viên đã được học trong các môn học trước đó nên
không được đề cập trong giáo trình này. Giáo trình dùng làm tài liệu học tập cho sinh
viên năm thứ hai, học kỳ 2 của năm thứ hai ngành Quản Trị Mạng với thời lượng 75 tiết.
Trong mỗi chương của giáo trình, các kiến thức lý thuyết được trình bày cơ bản, rõ
ràng, được minh hoạ chi tiết cùng với những ứng dụng cụ thể giúp cho người học dễ đọc,
dễ hình dung những ứng dụng của các cấu trúc dữ liệu trong một số ứng dụng điển hình.
Do đó giáo trình có thể dùng làm tài liệu tự học cho những người đã có những kiến thức
cơ bản về thuật toán và lập trình trên một ngôn ngữ lập trình bậc cao. Nội dung trong
giáo trình bám sát những nội dung cơ bản về các cấu trúc dữ liệu mà các chương trình
đào tạo cử nhân Tin học và Công nghệ thông tin yêu cầu. Cuối mỗi chương đều cung cấp
một hệ thống các bài tập từ cơ bản đến nâng cao nhằm giúp cho sinh viên rèn luyện tư
duy, kỹ thuật lập trình và hiểu rõ hơn những nội dung lý thuyết.
Trong giáo trình sử dụng ngôn ngữ lập trình Pascal để minh hoạ các cấu trúc dữ liệu
và thuật toán để giúp sinh viên dễ hình dung hơn trong cài đặt thành chương trình. Các cấu
trúc dữ liệu được tổ chức dưới hình thức bao gói thông tin, mỗi cấu trúc dữ liệu được xem
như một kiểu dữ liệu độc lập. Các thuật toán trình bày dưới dạng ngôn ngữ tự nhiên và
được hoàn chỉnh bằng những thủ tục viết bằng Pascal nên rất thuận tiện cho sinh viên trong
thực hành bằng Pascal hay bất kỳ một ngôn ngữ lập trình bậc cao nào mà mình ưa thích.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 4
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Để hoàn thành giáo trình này tác giả đã nhận được nhiều ý kiến đóng góp và động
viên của các đồng nghiệp.
Do thời gian và khả năng còn hạn chế nên giáo trình không thể tránh khỏi những
khiếm khuyết nhất định. Chúng tôi chân thành và mong đón nhận những ý kiến đóng góp
của độc giả.
Tác giả
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 5
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
NỘI DUNG
Mối quan hệ giữa cấu trúc dữ liệu và giải thuật;
Tiêu chuẩn đánh giá cấu trúc dữ liệu và giải thuật;
Các kiểu dữ liệu cơ bản, kiểu dữ liệu cấu trúc, kiểu dữ liệu con trỏ;
Độ phức tạp của thuật toán;
Câu hỏi và bài tập.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 6
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Mục tiêu:
- Trình bày được nội dung của: dữ liệu, giải thuật, mối quan hệ giữa cấu trúc
dữ liệu và giải thuật ;
- Trình bày được các kiểu dữ liệu (cơ bản, có cấu trúc, kiểu con trỏ) và đánh
giá được độ phức tạp của thuật toán.
Trong khi giải một bài toán, thông thường ta chỉ chú trọng đến giải thuật (hay
cách giải của bài toán) mà ít khi quan tâm đến việc tổ chức dữ liệu. Tuy nhiên giữa việc tổ
chức dữ liệu và thuật toán có mối liên hệ chặt chẽ nhau.
Theo cách tiếp cận của lập trình cấu trúc, Niklaus Wirth đưa ra công thức thể hiện
được mối liên hệ giữa cấu trúc dữ liệu và giải thuật:
Một thuật toán giải bài toán bao giờ cũng được thao tác trên một cấu trúc dữ liệu
cụ thể và các thao tác phải được cấu trúc dữ liệu đó hỗ trợ.
Khi tổ chức dữ liệu cho bài toán thay đổi thì thuật toán giải cũng phải thay đổi
theo cho phù hợp với cách tổ chức dữ liệu mới. Ngược lại, trong quá trình xây dựng,
hoàn chỉnh thuật toán cũng gợi mở cho người lập trình cách tổ chức dữ liệu phù hợp với
thuật toán và tiết kiệm tài nguyên hệ thống. Chẳng hạn dùng thêm các ô nhớ phụ để lưu
các kết quả trung gian để giảm thời gian tính toán.
Quá trình giải một bài toán trên máy tính là một quá trình hoàn thiện dần cách tổ
chức dữ liệu và thuật toán để tiết kiệm tài nguyên của hệ thống.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 7
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
tg := x;
x:= y;
y := tg;
x := x + y;
y := x - y;
x := x - y;
Qua ví dụ đơn giản trên, ta nhận thấy việc tổ chức dữ liệu khác nhau (dùng hay
không dùng biến trung gian) ảnh hưởng rất lớn đến thuật toán và gần như thay đổi toàn
bộ thuật toán. Hơn nữa nó còn ảnh hưởng đến tính hiệu quả và phạm vi ứng dụng của
thuật toán.
Để đánh giá một cấu trúc dữ liệu chúng ta thường dựa vào một số tiêu chí sau:
Mọi dữ liệu lưu trữ trên máy tính đều được biểu diễn dưới dạng các số nhị phân.
Việc sử dụng trực tiếp các số nhị phân trên máy tính là một công việc khó khăn cho
người nlập trình. Chính vì lý do này mà các ngôn ngữ lập trình cấp cao đã xây dựng nên
các kiểu dữ liệu. Một kiểu dữ liệu là sự trừu tượng hóa các thuộc tính bản chất của các
đối tượng trong thực tế và phù hợp với cách tổ chức thông tin trên máy tính, chẳng hạn
như các kiểu số nguyên, số thực, logic,...
Một kiểu dữ liệu T là một bộ T = <V, O>, trong đó V là tập các giá trị hợp lệ của
kiểu T và O là tập các phép toán trên kiểu T.
Ví dụ: Kiểu dữ liệu Byte = <VByte, OByte>, với VByte = {0, 1, ..., 255}, OByte =
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 8
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Kiểu số nguyên
- Kiểu số nguyên thường được thực hiện với các phép toán: O = {+, -, *, /, DIV,
MOD, <, >, <=, >=, =, …}
Kiểu số thực
- Kiểu số thực thường được thực hiện với các phép toán: O = {+, -, *, /, <, >, <=, >=, =, …}
- Kiểu ký tự byte
- Kiểu ký tự 2 bytes
- Kiểu ký tự thường được thực hiện với các phép toán: O = {+, -, <, >, <=, >=, =, ORD, CHR, …}
- Kiểu chuỗi ký tự: Có kích thước tùy thuộc vào từng ngôn ngữ lập trình
- Kiểu chuỗi ký tự thường được thực hiện với các phép toán: O = {+, <, >, <=, >=, =, Length, Trunc, ..}
Kiểu luận lý thường được thực hiện với các phép toán: O = {NOT, AND, OR, XOR, <, >, <=, >=, =, }
Kiểu dữ liệu có cấu trúc là các kiểu dữ liệu được xây dựng trên cơ sở các kiểu dữ
liệu đã có (có thể lại là một kiểu dữ liệu có cấu trúc khác). Tùy vào từng ngôn ngữ lập
trình song thường có các loại sau:
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 9
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Kiểu mảng hay còn gọi là dãy: kích thước bằng tổng kích thước của các phần tử.
Kiểu bản ghi hay cấu trúc: kích thước bằng tổng kích thước các thành phần (Field).
Các ngôn ngữ lập trình thường cung cấp cho chúng ta một kiểu dữ liệu đặc biệt để
lưu trữ các địa chỉ của bộ nhớ, đó là con trỏ (Pointer). Tùy vào loại con trỏ gần (near
pointer) hay con trỏ xa (far pointer) mà kiểu dữ liệu con trỏ có các kích thước khác nhau:
Việc đánh giá thời gian thực hiện của thuật toán phụ thuộc vào nhiều yếu tố :
Do đó việc đo, đếm chính xác thời gian thực hiện thuật toán là bao nhiêu đơn vị
thời gian gần như không thể thực hiện được. Để có thể so sánh thời gian chạy của các
thuật toán, trên phương diện lý thuyết thời gian thực hiện thuật toán được đánh giá là
một hàm phụ thuộc vào kích thước của dữ liệu vào gọi là độ phức tạp thuật toán.
Để đánh giá độ phức tạp của thuật toán thông thường người ta tính số phép toán cơ
bản thuật toán thực hiện. Các phép toán cơ bản thường dùng để đánh giá như các phép
toán: +, -, *, /, các phép so sánh, phép gán, thao tác đọc, ghi file,... Tùy thuộc vào thuật
toán, độ phức tạp là một hàm phụ thuộc vào kích thước của dữ liệu vào, ký hiệu T(n),
với n là đại lượng đặc trưng cho kích thước của dữ liệu vào. Trong thường hợp thuật toán
thực hiện nhiều phép toán cơ bản ta có thể đánh giá độ phức tạp trên từng loại phép toán
hoặc tổng hợp của các phép toán. Chẳng hạn thuật toán sắp xếp thường được đánh giá
trên 2 phép toán thường dùng là so sánh và phép gán.
Trong nhiều thường hợp, việc tính toán chính xác độ phức tạp thuật toán T(n) là
không thể thực hiện được vì còn tùy thuộc vào sự phân bố của dữ liệu vào. Chẳng hạn
thuật toán tìm một phần tử trong một danh sách cho trước không chỉ phụ thuộc vào số
phần tử của danh sách mà còn phụ thuộc vào vị trí của phần tử cần tìm có trong danh
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 10
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
sách hay không, nếu có thì phụ thuộc vào vị trí của phần tử do đó số phép so sánh phụ
thuộc vào từng danh sách và phần tử cần tìm. Trong những thường hợp như thế này
thông thường độ phức tạp được đánh giá trong trường hợp xấu nhất của dữ liệu vào.
Trong một số tình huống cụ thể có thể tính trung bình hoặc tính theo xác suất.
Ví dụ 1 Thuật toán tìm một phần tử x trong danh sách L có n phần tử bằng cách
tìm tuần tự
TimThay= False;
For i:=1 To n Do
If L[i] = x then
begin
TimThay:=True;
Exit;
End
Độ phức tạp của thuật toán được đánh giá trên 2 phép toán cơ bản là phép so
sánh trong biểu thức điều kiện của lệnh If và phép gán, ký hiệu tương ứng là C(n) và
M(n). Độ phức tạp được đánh giá trong trường hợp "xấu" nhất của dữ liệu vào là dãy số
ở tình trạng thứ tự giảm. Khi đó ta tính được:
Câu 1: Trình bày tầm quan trọng của Cấu trúc dữ liệu và Giải thuật đối với người
lập trình?
Câu 2: Các tiêu chuẩn để đánh giá cấu trúc dữ liệu và giải thuật?
Câu 3: Khi xây dựng giải thuật có cần thiết phải quan tâm tới cấu trúc dữ liệu hay
không? Tại sao?
Câu 4: Liệt kê các kiểu dữ liệu cơ sở, các kiểu dữ liệu có cấu trúc trong C, Pascal?
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 11
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 12
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Mục tiêu:
- Trình bày được giải thuật và chương trình sử dụng giải thuật đệ quy;
- So sánh giải thuật đệ quy với các giải thuật khác để rút ra tính ưu việt hoặc
nhược điểm của giải thuật;
Đệ quy (recursion) là một phương pháp lập trình được sử dụng rộng rãi để giải
quyết các bài toán có cấu trúc đệ quy (được định nghĩa đệ quy) các bài toán sử dụng
chiến lược chia để trị, các bài toán tìm kiếm vét cạn quay lui.
Một thuật toán được gọi là đệ quy nếu nó yêu cầu thực hiện lại chính nó với mức dữ
liệu nhỏ hơn.
Thuật toán đệ quy phải được mô tả thông qua tên gồm hai phần như sau :
Gắn liền với các bài toán có đặc trưng đệ quy là công thức truy hồi
3.1. ƯU ĐIỂM
Mô tả bài toán đơn giản, ngắn gọn và gần như thuật toán bất kỳ đều có thể đưa về
dạng đệ quy.
- Tốn bộ nhớ ;
- Một thuật toán đệ quy thường khó hình dung thuật toán.
Có nhiều thuật toán khác nhau để giải bài toán này, ở đây ta sử dụng một tính chất
của ƯCLN là: nếu a > b thì ƯCLN(a,b)=ƯCLN(a-b,b). Thuật toán được mô tả như sau:
If a < b then
Ucln:=ucln(a-b,b);
Bài toán 2: Định nghĩa các số Fibbonacci như sau: f0=1, f1=1, fn=fn-1+fn-2 với n>1.
Tính fn với n cho trước.
Thuật toán đệ qui sử dụng ngay định nghĩa đệ qui của các số Fibbonacci, vì thế
thuật toán chỉ là diễn đạt lại định nghĩa.
Function Fib(n);
Fib:=1
Else Fib:=Fib(n-1)+Fib(n-2);
Bài toán 3: Tháp Hà Nội. Có 3 cột 1, 2, 3. Trên cột 1 có n đĩa bán kính khác nhau
được xếp theo thứ tự đĩa lớn nằm dưới, đĩa nhỏ nằm trên. Các đĩa có thể được chuyển từ
cột này sang cột khác. Qui tắc chuyển như sau:
Mỗi lần chỉ được chuyển 1 đĩa. Không được để đĩa lớn nằm trên đĩa nhỏ.
Viết thuật toán chuyển n đĩa từ cột 1 sang cột 3 dùng cột 2 làm trung gian.
Để giải quyết bài toán ta chỉ cần giả thiết đã chuyển được n -1 đĩa nhỏ nhất từ cột 1
tới cột 2. Khi đó ta chỉ cần chuyển đĩa lớn nhất từ cột 1 tới cột 3 sau đó chuyển n -1 đĩa
từ cột 2 tới cột 3.
Như vậy ta cần một thủ tục có thể chuyển m đĩa nhỏ nhất từ cột i tới cột j. Thủ tục
này sẽ làm việc như sau: đầu tiên chuyển m-1 đĩa từ cột i tới cột 6-i-j, sau đó chuyển 1
đĩa từ cột i tới cột j, cuối cùng chuyển m-1 đĩa từ cột 6-i-j tới cột j.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 14
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Procedure ThapHN(m,i,j);
If m > 0 then
ThapHN(m-1,i,6-i-j);
Writeln(i,’ ‘,j);
ThapHN(m-1,6-i-j,j);
Với bài toán đã cho chỉ việc gọi thủ tục ThapHN(n,1,3).
Câu 1: Sử dụng tính chất sau của ƯCLN để đưa ra một thuật toán đệ qui tìm
ƯCLN(a,b): Nếu a>b thì ƯCLN(a,b)=ƯCLN(a mod b,b) và ƯCLN(a,0)=a với a>0. Khử
đệ qui của thuật toán này.
Câu 3: Thuật toán sau có đạt được ý định tìm và in ra số lớn nhất trong n số hay
không? Giải thích.
Procedure Max(n);
Else
Else Max(n-1);
Câu 4: Thuật toán sau nhằm sửa lại thuật toán của bài tập 3. Thuật toán này có đạt
được mục đích không?
Function MaxNew(n);
Else
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 15
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Else max:=MaxNew(n-1);
Return max;
Câu 5: Viết 2 thuật toán đệ qui tính tổng các số hạng của một dãy số.
Câu 7: Viết thuật toán đệ qui in ra chuỗi đảo ngược của một chuỗi cho trước.
Câu 8: Cho dãy m số nguyên tuỳ ý. Viết thuật toán đệ qui tìm và gán cho B giá trị
lớn nhất trong dãy, đồng thời tìm và gán cho N giá trị lớn thứ nhì trong dãy.
Câu 9: Hàm f(n) xác định trên tập các số nguyên không âm như sau:
Mô tả hai thuật toán đệ qui và không đệ qui tính f(N) với N cho trước .
Câu 10: *Xét bài toán Josephus: Có một nhóm N người. Để chọn một người đi
làm một nhiệm vụ đặc biệt người ta cho N người này đứng thành vòng tròn. Bắt đầu đếm
từng người từ một vị trí nào đó theo chiều kim đồng hồ. Mỗi khi gặp người thứ M thì loại
người đó ra khỏi vòng tròn. Tiếp tục quá trình đếm cho tới khi chỉ còn lại một người. Đó
chính là người được chọn. Ví dụ với N=9, M=5 và đếm từ 1. Khi đó thứ tự người bị loại
ra lần lượt là: 5, 1, 7, 4, 3, 6, 9, 2. Người còn lại là người thứ 8.
Có thể tìm được một thuật toán không đệ qui giải bài toán này không?
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 16
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 17
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Mục tiêu :
- Trình bày được định nghĩa được danh sách liên kết, ngăn xếp, hàng đợi;
- Trình bày được cách tổ chức dữ liệu bằng danh sách liên kết ;
- Cài đặt các thao tác trên danh sách liên kết đơn, liên kết kép, ngăn xếp,
hàng đợi.
Danh sách là một dãy hữu hạn các phần tử cùng loại được xếp theo một thứ tự
tuyến tính.
Danh sách L gồm các phần tử a1, a2, ..., an được ký hiệu: L = (a1, a2, ..., an).
Trong đó n gọi là chiều dài của danh sách, ai gọi là phần tử thứ i của danh sách. a1
gọi là phần tử đầu tiên của danh sách, an gọi là phần tử cuối cùng của danh sách.Nếu
n= 0 thì danh sách được gọi là rỗng.
Một tính chất quan trọng của danh sách là các phần tử được sắp xếp tuyến tính theo
vị trí của chúng trong danh sách. Với n>1, i =1, 2,..., n-1, phần tử ai là phần tử ngay
trước phần tử ai+1 và ai+1 là phần tử ngay sau phần tử ai.
Danh sách liên kết là một cách tổ chức dữ liệu cho mô hình danh sách trong đó các
phần tử được liên hệ với nhau nhờ vào vùng liên kết.
Danh sách liên kết sử dụng cơ chế cấp phát động nên thích hợp với các thao tác
thêm vào, loại bỏ, ghép nhiều danh sách.
Mỗi phần tử của danh sách liên kết gồm hai thành phần:
- Phần Data chứa dữ liệu thực sự của từng phần tử trong danh sách.
- Phần Link dùng để liên kết một phần tử với phần tử ngay sau nó.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 18
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Data Link
Từ một phần tử ta chỉ duy trì một liên kết đến phần tử ngay sau nó nên danh sách
liên kết được tổ chức như vậy được gọi là danh sách liên kết đơn. Trong phần này ta chỉ
xét cấu trúc dữ liệu danh sách liên kết đơn nên không gây nhầm lẫn khi ta gọi là danh
sách liên kết.
Hình ảnh một danh sách liên kết L = (a1, a2, a3, .. ,an) được biểu diễn như sau:
Để quản lý danh sách biểu diễn bởi danh sách liên kết ta chỉ cần quản lý phần tử
đầu tiên của danh sách. Từ phần tử này ta có thể thao tác được với các phần tử của
danh sách nhờ liên kết giữa các phần tử.
Begin
Head:=Nil;
End;
Thêm phần x vào vị trí p trong danh sách có phần tử đầu tiên là phần tử Head
Thủ tục thêm một phần tử vào vị trí sau p. Trong thủ tục ta xét trường hợp khi
danh sách rỗng thì phần tử thêm vào chính là phần tử duy nhất của danh sách. Chi tiết
thủ tục như sau:
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 19
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
var q : ListLink;
Begin
New(q);
q^.Data := x;
begin
q^.Link:=nil; Head:=q;
end
else
begin
q^.Link := p^.Link;
p^.Link := q;
end;
End;
Giả sử cần loại bỏ phần tử ngay sau phần tử ở vị trí p trong danh sách có phần tử
đầu là Head.
Cài đặt
var q : ListLink;
Begin
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 20
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
q := p^.Link;
if q<>nil then
begin
p^.Link := q^.Link;
Dispose(q);
end;
End;
Cho danh sách liên kết có phần tử đầu Head. Cần tìm một phần tử có khóKey bằng
một giá trị x cho trước.
Với cách tổ chức dữ liệu của danh sách liên kết, việc truy xuất các phần tử là tuần tự
nên thao tác tìm kiếm phải dùng thuật toán tìm tuần tự.
Thủ tục tìm khóa x trong danh sách Head, kết quả trả về qua giá trị found và vị trí
của phần tử tìm được p
Begin
p:=Head;
found:=false;
if p^.Data.Key = x then
found:=true
else
p:=p^.link;
End;
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 21
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Cho 2 danh sách có phần tử đầu tương ứng là Head1 và Head2. Ghép danh sách
Head2 vào sau
danh sách
Head1.
Để ghép
được danh sách 2 sau danh sách 1 phải tìm được vị trí của phần tử cuối danh sách 1 (nếu
có) và liên kết với phần tử đầu của danh sách thứ 2. Trong trường hợp danh sách 1 rỗng
thì kết quả ghép là danh sách 2.
Danh sách liên kết kép là danh sách liên kết mà việc thao tác trên một phần tử của
nó liên quan đến phần tử ngay trước và ngay sau nó.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 22
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
2.2. KHAI BÁO DỮ LIỆU CHO DANH SÁCH LIÊN KẾT KÉP
Vì danh sách liên kết kép có thể duyệt theo cả hai chiều nên cần quản lý cả hai
phần tử đầu và cuối danh sách. Khai báo dữ liệu cho danh sách liên kết kép như sau:
Type
DLink = ^Cell2L;
Cell2L = Record
Data : ElementType;
End;
List2Link = Record
End;
Var l : List2Link;
2.3. CÁC THAO TÁC TRÊN DANH SÁCH LIÊN KẾT KÉP
Begin
End;
Hình 6: Thêm một phần tử vào vị trí p trong danh sách liên kết kép
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 23
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Thủ tục thêm một phần tử vào trước phần tử ở vị trí p như sau:
Procedure InsertBefore(var l:List2Link;p:DLink; x:ElementType);
var q,p1 : DLink;
Begin
New(q);
q^.Data:= x;{danh sách rỗng}
if (l.Left=nil) and (l.Right=nil) then
begin
q^.LLink:=nil;
q^.RLink:=nil; l.Left:=q;
l.Right:=q;
end
else
Begin
if l.Left = p then {thêm vào đầu}
begin
q^.LLink:=nil;
q^.RLink:=p;
p^.LLink:=q;
l.Left:=q;
end
else
begin
p1:=p^.LLink;
q^.LLink:=p1;
p1^.Rlink:=q;
q^.RLink:=p;
p^.LLink:=q;
end;
end;
End.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 24
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Begin
l.Left := p^.RLink
else
l.Right:=p^.LLink
else
begin
p^.LLink^.RLink:=p^.RLink;
p^.RLink^.LLink:=p^.LLink;
end;
dispose(p);
End;
Có thể duyệt từ trái sang phải hoặc ngược lại. Thủ tục duyệt từ trái sang phải được
thực hiện như sau:
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 25
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Trong một số trường hợp chúng ta sử dụng một mô hình dữ liệu nhưng chỉ dùng
một số trong các thao tác trên mô hình đó. Khi đó mô hình dữ liệu cùng với một số phép
toán cụ thể trên mô hình đó gọi là một kiểu dữ liệu trừu tượng (abstract data type). Trong
phần sau ta xét hai kiểu dữ liệu trừu tượng có ứng dụng nhiều trong các thuật toán tin học
là ngăn xếp và hàng đợi.
Ngăn xếp là một dạng danh sách đặc biệt chỉ được thực hiện hai thao tác: thêm
một phần tử vào cuối danh sách (push) và lấy phần tử cuối ra khỏi danh sách (pop).
Như vậy trong một ngăn xếp phần tử đưa vào sau sẽ được lấy ra trước nên còn gọi
là danh sách kiểu LIFO (Last in First out). Vị trí của phần tử cuối cùng của ngăn xếp còn
gọi là đỉnh (top) của ngăn xếp.
Trong các ngôn ngữ lập trình bậc cao bao giờ cũng dành riêng một vùng nhớ gọi
là Stack dùng để lưu lại các giá trị của biến, hằng,... mỗi khi có lời gọi thủ tục, các giá trị
này được lấy lại mỗi khi có một lời gọi thực hiện xong. Việc lưu các giá trị như trên
phải theo nguyên tắc hoạt động của ngăn xếp vì lời gọi thủ tục cuối cùng sẽ kết thúc
trước. Do đó ngăn xếp là một cách tổ chức dữ liệu được dùng nhiều trong các chương
trình chuyển từ đệ quy sang lặp.
Trong các chương trình dịch (compiler) thường phải biến đổi các biểu thức trung tố
thành các biểu thức tương đƣơng ở dạng hậu tố. Chẳng hạn biểu thức (3 +4) * 2 được
chuyển thành 3 4 + 2 *. Việc chuyển các biểu thức từ trung tố thành hậu tố và tính giá trị
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 26
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
các biểu thức hậu tố phải dùng cấu trúc dữ liệu kiểu ngăn xếp để lưu các kết quả trung
gian. Chi tiết các thuật toán này sẽ được trình bày trong phần sau.
Như đã đề cập ở khái niệm của ngăn xếp, các thao tác trên ngăn xếp gồm hai thao
tác cơ bản là :
Tương tự như mô hình danh sách, trên ngăn xếp cũng có thể tổ chức bằng mảng và
danh sách liên kết. Trong phần sau trình bày hai cách tổ chức dữ liệu cho ngăn xếp.
Một ngăn xếp tổ chức bằng danh sách liên kết cũng giống như những danh sách
khác, trong đó đỉnh của ngăn xếp chính là con trỏ của danh sách liên kết. Hình ảnh
của ngăn xếp S = (a1, a2, ..., an) tổ chức bằng danh sách liên kết như sau:
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 27
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Type
StackLink = ^Cell;
Cell = Record
End;
Var
S : StackLink;
Begin
S := Nil;
End;
Hàm Empty
Begin
Empty := S = Nil;
End;
Thêm vào một phần tử: thêm phần tử x vào ngăn xếp S
Hình 10: Thêm vào một phần tử: thêm phần tử x vào ngăn xếp S
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 28
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
var p:StackLink;
Begin
begin
end;
End;
Hình 11: Lấy một phần tử từ ngăn xếp tổ chức bằng danh sách liên kết
Thủ tục lấy một phần tử từ ngăn xếp tổ chức bằng danh sách liên kết:
var p : StackLink;
Begin
begin
p := S; S:=p^.Link; Dispose(p);
end;
End;
Giải thuật đệ qui là một trong những giải thuật thường dùng trong lập trình, tuy
nhiên các thủ tục đệ qui khi cài đặt trên các ngôn ngữ lập trình phụ thuộc vào kích thước
vùng nhớ dành cho Stack mà cho phép các thủ tục đệ qui được gọi bao nhiêu lần. Hơn
nữa các thủ tục đệ qui dễ cài đặt nhưng khó hình dung chi tiết các bước thực hiện. Một số
dạng thuật toán đệ qui có thể khử đệ qui bằng cách dùng một ngăn xếp để điều khiển quá
trình gọi đệ qui.
Tính giá trị của biểu thức là công việc thường làm của các ngôn ngữ lập trình.
Thông thường các ngôn ngữ lập trình tính giá trị biểu thức bằng cách:
- Chuyển biểu thức từ dạng trung tố (infix) sang dạng hậu tố (posfix).
Biểu thức trung tố là cách con người thường sử dụng, trong biểu thức trung tố các
phép toán hai ngôi được viết giữa hai toán hạng. Việc tính trực tiếp các biểu thức trung tố
gặp khó khăn vì phải dùng các cặp dấu ngoặc đơn để qui định thứ tự thực hiện các biểu
thức con. Để tính các biểu thức, người Balan đã đưa ra một ký pháp qui định cách viết
các biểu thức (gọi là ký pháp Balan) trong đó các phép toán được đặt sau toán hạng.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 30
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Việc dùng ký pháp Balan không cần dấu ngoặc nhưng vẫn thể hiện được thứ tự ưu tiên
khi tính giá trị biểu thức nên dễ dàng xây dựng thuật toán tính.
Ví dụ: Biểu thức dạng trung tố 3+(5-2)*3/7-4 được viết dưới dạng biểu thức hậu tố :
352-3*7/4+-
Giả sử ta có một biểu thức E dạng trung tố trong đó ta có thể phân tích thành
các thành phần của biểu thức là các toán hạng và phép toán.
Dùng một ngăn xếp S mỗi phần tử là phép toán hoặc dấu ngoặc mở. Kết quả đưa
ra biểu thức hậu tố E1.
Thuật toán:
1. Khởi tạo biểu thức E1 rỗng
2. Duyệt lần lượt các thành phần của biểu thức E, với mỗi thành phần x thực hiện
2.1 Nếu x là toán hạng thì nối vào bên phải biểu thức E1
2.2 Nếu x là dấu ngoặc mở thì đưa vào ngăn xếp
2.3 Nếu x là phép toán thì
a. Đọc phần tử y ở đầu ngăn xếp
b. Nếu độ ưu tiên của y cao hơn x thì
Lấy y ra khỏi ngăn xếp
Nối y vào bên phải E1
Lặp lại bước a.
c. Nếu độ ưu tiên của x cao hơn y thì đưa x vào ngăn xếp
2.4 Nếu x là dấu ngoặc đóng thì
a. Đọc phần tử y ở đầu ngăn xếp b. Nếu y là phép toán thì
Lấy y ra khỏi ngăn xếp
Nối y vào bên phải biểu thức E1
Lặp lại bước a.
c. Nếu y là dấu ngoặc mở thì lấy ra khỏi ngăn xếp
3. Lặp lại bước 2 cho đến hết biểu thức E
4. Lấy lần lượt các phần tử của ngăn xếp và nối vào bên phải biểu thức E1
cho đến khi ngăn xếp rỗng.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 31
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Ví dụ: Với biểu thức E = (2+7*3-8)*4-(3+2)*3-2, thuật toán chuyển thành biểu
thức hậu tố thực hiện qua các bước thể hiện qua các kết quả ở bảng sau:
(
(
( 2
2
(+ 2
+
(+ 27
7
(+* 27
*
(+* 273
3
(- 273*+
-
(- 273*+8
8
273*+8–
)
* 273*+8–
*
* 273*+8–4
4
- 273*+8–4*
-
-( 273*+8–4*
(
-( 273*+8–4*3
3
-(+ 273*+8–4*3
+
-(+ 273*+8–4*32
2
- 273*+8–4*32+
)
-* 273*+8–4*32
*
-* 273*+8–4*323
3
- 273*+8–4*323*-
-
- 273*+8–4*323*-2
2
273*+8–4*323*-2-
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 32
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Hàng đợi là một kiểu dữ liệu trừu tượng xây dựng trên mô hình danh sách với hai
thao tác cơ bản:
Hàng đợi được thực hiện theo nguyên tắc: các phần tử đưa vào trước lấy ra trước nên
còn gọi là danh sách FIFO (First In First Out). Hàng đợi Q = (a1, a2, ..., an) được thể hiện
bằng hình dưới.
Trong thực tế ta thường gặp những công việc thực hiện theo nguyên tắc của hàng
đợi, chẳng hạn việc đăng ký mua vé tàu, việc chuyển các toa tàu trên một đƣờng sắt,...
Trong máy tính mô hình hàng đợi được dùng khá phổ biến. Những hàng đợi được tạo
ra khi có nhiều hơn một quá trình đòi hỏi được xử lý, chẳng hạn như máy in, ổ đĩa hay bộ
xử lý trung tâm. Khi các quá trình đòi hỏi một tài nguyên, chúng được đặt trong một
hàng đợi để chờ phục vụ. Ví dụ, nhiều máy tính có thể được phân phối để sử dụng một
máy in, và một hàng đợi spool (Simultanous Peripherial Output On Line - đưa ra đồng
thời với quá trình tính toán) được dùng để lập kế hoạch cho các yêu cầu đầu ra theo
kiểu “đến trước được phục vụ trước”. Nếu có một yêu cầu cho máy in và máy in rỗi, nó
sẽ được cấp phát ngay lập tức công việc này. Trong khi in, một số công việc khác có thể
cần đến máy in, chúng được đặt trong spool để chờ đến lượt. Khi công việc hiện thời của
máy in kết thúc, máy in được giải phóng khỏi công việc ấy và được cấp phát cho công
việc đầu tiên trong hàng spool.
Một ứng dụng quan trọng khác của hàng đợi trong máy tính là tổ chức vùng đệm
cho các đầu vào/ra (input/output buffering). Việc truyền thông tin từ một thiết bị vào
hay đến một thiết bị ra là một thao tác tương đối chậm, do đó nếu phải tạm dừng
chương trình trong khi truyền dữ liệu thì ảnh hưởng rất lớn đến tốc độ thực hiện
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 33
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
chương trình. Một cách giải quyết thường dùng trên máy tính là dùng các phần của
bộ nhớ trong, gọi là vùng đệm (buffer) và việc truyền dữ liệu từ một chương trình sẽ
được truyền qua vùng đệm mà không thao tác trực tiếp với các thiết bị vào/ra. Chẳng
hạn, một chương trình đọc dữ liệu từ một tệp trên đĩa, dữ liệu sẽ được truyền từ đĩa
sang vùng đệm đầu vào trong bộ nhớ chính, trong khi bộ xử lý trung tâm đang thực
hiện một nhiệm vụ khác nào đó. Khi chương trình đòi hỏi dữ liệu, những giá trị tiếp
theo trong hàng đợi này được lấy ra. Trong khi dữ liệu này đang xử lý thì các dữ liệu
khác có thể được truyền từ tệp sang vùng đệm. Rõ ràng vùng đệm phải được thực hiện
theo kiểu vào trước ra trước.
4.2.1. Tổ chức
Cũng như ngăn xếp, ta có thể dùng danh sách liên kết để biểu diễn hàng đợi. Do
thao tác thêm vào và lấy ra trên hàng đợi được lấy ra ở hai vị trí khác nhau nên ta dùng
hai con trỏ front và rear để lưu hai vị trí này.
Hình 12: Hình ảnh tổ chức hàng đợi bằng danh sách liên kết
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 34
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Khởi tạo
Begin
Q.front:=Nil;
Q.rear:=Nil;
End;
Hình 13: Thêm vào hàng đợi biểu diễn danh sách bằng liên kết
var p : ListLink;
Begin
If Empty(Q) Then
begin
Q.front:=p; Q.rear:=p;
end
Else
begin
Q.rear^.Link:= p; Q.rear:=p;
end;
End;
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 35
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Hình 14: Lấy một phần tử từ hàng đợi biểu diễn bằng danh sách liên kết
var p : ListLink;
Begin
begin
x:=Q.front^.Data;
P:=Q.front;
Q.front:=p^.Link;
Dispose(p);
If Q.front=Nil Then
Q.rear:=Nil;
end;
End;
Câu 1: Bài 1. Cho một dãy số nguyên a1, a2, ..., an. Hãy tổ chức dữ liệu kiểu
danh sách liên kết đơn để lưu dãy số và cài đặt các thủ tục thực hiện các công việc sau:
- Thủ tục thêm một số x vào dãy đã sắp tăng sao cho vẫn giữ được thứ tự.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 36
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Dựa vào các thủ tục trên viết chương trình tổ chức dạng menu cho phép chọn
thực hiện các công việc sau:
- Chèn một số
Câu 2: Dùng ngăn xếp khử đệ quy của hàm tính Cnm được viết như sau:
Function combo(n,m :
integer):longint; Begin
Combo:=1
Else
combo:=combo(n-1,m)+combo(n-1.m-1);
End;
Câu 3: (Danh sách liên kết bội) Để quản lý một danh sách các danh sách liên
kết người ta tổ chức dữ liệu dạng danh sách bội. Mỗi phần tử trong danh sách bội quản
lý một danh sách liên kết gồm các thành phần sau :
- Thành phần head trỏ đến một danh sách liên kết đơn.
- Thành phần link liên kết tới danh sách tiếp theo (nếu có) Hãy tổ chức dữ liệu
và trình bày các thuật toán thực hiện.
- Tạo một danh sách bội trống : danh sách chưa có danh sách nào.
- Thêm một danh sách mới (trống) vào đầu danh sách bội.
- Thêm một phần tử x vào đầu danh sách trỏ bởi con trỏ plist trong danh sách bội.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 37
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
- Xóa phần tử sau vị trí p trong danh sách plist trong danh sách liên kết bội.
- Xóa danh sách sau danh sách trỏ bởi con trỏ plist trong danh sách bội.
- Tìm một khóa x trong danh sách bội. Kết quả trả về con trỏ trỏ đến ô chứa
phần tử có khóa x tìm được đầu tiên.
- Xóa tất cả các phần tử có khóa x trong danh sách bội.
Cài đặt các thao tác trên cho danh sách bội chứa các số nguyên.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 38
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 39
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Mục tiêu:
- Trình bày được giải thuật, cài đặt được thuật toán, đánh giá độ phức tạp
của thuật toán sắp xếp;
- Giải được các bài toán sắp xếp sử dụng các phương pháp sắp xếp đã
khảo sát.
Sắp xếp là là quá trình tổ chức lại một danh sách các đối tượng theo một thứ tự
nhất định.
Mục đích của sắp xếp là giúp cho việc tìm kiếm trên danh sách các đối tượng
được dễ dàng hơn. Vì vậy sắp xếp là một bài toán cơ bản và được ứng dụng khá rộng
rãi trong các bài toán tin học. Sắp xếp là là quá trình tổ chức lại một danh sách các đối
tượng theo một thứ tự nhất định. Mục đích của sắp xếp là giúp cho việc tìm kiếm trên
danh sách các đối tượng được dễ dàng hơn. Vì vậy sắp xếp là một bài toán cơ bản và
được ứng dụng khá rộng rãi trong các bài toán tin học.
Người ta chia các phương pháp sắp xếp thành hai lớp: sắp xếp trong và sắp xếp
ngoài. Sắp xếp trong được thực hiện trên danh sách các đối tượng được lưu ở bộ nhớ
trong của máy tính dưới dạng mảng. Do đó phương pháp này còn gọi là sắp xếp mảng.
Khi số các đối tượng trong danh sách cần sắp xếp quá lớn, không thể lưu ở bộ nhớ trong
được thì phải lưu ở bộ nhớ ngoài dưới dạng các file. Khi đó phương pháp sắp xếp trong
không thể sử dụng cho các dữ liệu lưu ở bộ nhớ ngoài vì có những khác biệt cơ bản về
các thao tác truy cập các đối tượng. Do đó phải dùng phương pháp khác gọi là sắp xếp
ngoài.
7.1. PHƯƠNG PHÁP SẮP XẾP CHỌN TRỰC TIẾP (SELECTION SORT)
Chọn phần tử nhỏ nhất chưa đúng vị trí và đặt nó vào vị trí i
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 40
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Khi sử dụng phương pháp sắp xếp chọn ta giả thiết các vị trí từ 1 đến i-1 trong
mảng đã chọn được các phần tử đúng vị trí. Ta chọn phần tử nhỏ nhất chưa đúng vị trí
nằm trong khoảng từ vị trí i đến vị trí n và sắp nó vào vị trí i.
Mô tả chi tiết
Procedure SXChon;
min:=i;
For j:=i+1 to n do
min:= j; {phần tử tại vị trí min là nhỏ nhất chưa được sắp}
Ví dụ: Giả sử mảng đã cho là A = (3, 6, 2, 8, 4, 5). Trong mỗi dòng dưới đây là tình
trạng của mảng sau khi kết thúc một vòng lặp ứng với i
i=1 2, 6, 3, 8, 4, 5
i=2 2, 3, 6, 8, 4, 5
i=3 2, 3, 4, 8, 6, 5
i=4 2, 3, 4, 5, 6, 8
i=5 2, 3, 4, 5, 6, 8
For i:=2 to n do
chèn A[i] vào vị trí thích hợp trong các phần tử A[1],…, A[i-1]
Trong phương pháp này, ở bước thứ i ta có các phần tử từ A[1] đến A[i-1] đã được
sắp thứ tự. Để chèn A[i] vào vị trí thích hợp trong các phần tử A[1],…, A[i-1] ta sẽ tìm vị
trí j nhỏ nhất thỏa mãn A[i] < A[j] và chèn A[i] vào vị trí j. Khi đó các phần tử từ vị trí j
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 41
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
đến i-1 sẽ dịch sang phải 1 vị trí. Trong quá trình tìm vị trí j ta đồng thời dịch các phần tử
lớn hơn A[i] sang phải một vị trí.
Procedure SXChen;
For i:=2 to n do
x:=A[i]; j:=i-1;
A[j]:= A[j-1]
j:=j-1;
A[j+1] :=x;
Với mỗi i vòng lặp While dừng lại khi j=0 hoặc khi j>0 và x >= A[j]. Nếu j=0 có
nghĩa là x được xếp vào đầu mảng (vị trí j+1). Nếu j>0 thì x được xếp vào sau vị trí j.
Ví dụ: Giả sử mảng đã cho là A = (3, 6, 2, 8, 4, 5). Trong quá trình sắp thứ tự theo
thuật toán sắp xếp chèn, mảng biến đổi như sau (j nhận giá trị sau khi kết thúc vòng lặp
While):
Thuật toán sắp xếp bằng cách đổi chỗ trực tiếp được thực hiện bằng cách duyệt
các phần tử trong mảng, nếu hai phần tử liền nhau sai vị trí thì đổi chỗ cho nhau. Sau
mỗi lần duyệt phần tử nhỏ nhất được đưa lên đầu (hoặc phần tử lớn nhất đưa về cuối tùy
thuộc vào cách duyệt từ 1 đến n hay ngược lại). Sau mỗi bước lặp danh sách các phần tử
cần sắp xếp sẽ giảm đi 1.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 42
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Ví dụ: Giả sử mảng đã cho là A = (4, 6, 3, 8, 2, 5). Trong mỗi dòng dưới đây là tình
trạng của mảng sau khi kết thúc một vòng lặp ứng với i
i=5 4, 3, 6, 2, 5, 8
i=4 3, 4, 2, 5, 6, 8
i=3 3, 2, 4, 5, 6, 5
i=2 2, 3, 4, 5, 8, 6
i=1 2, 3, 4, 5, 6, 8
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 43
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Phương pháp sắp xếp đổi chỗ trực tiếp ứng với mỗi i, so sánh a[i] với các phần tử
còn lại trong mảng nếu thấy phần tử nào nhỏ hơn thì đổi chỗ a[i] và a[j] cho nhau.
begin
for j=i+1 to n do
end;
Ví dụ: Giả sử mảng đã cho là A = (4, 6, 3, 8, 2, 5). Trong mỗi dòng dưới đây là tình
trạng của mảng sau khi kết thúc một vòng lặp ứng với i
i=5 4, 3, 6, 2, 5, 8
i=4 3, 4, 2, 5, 6, 8
i=3 3, 2, 4, 5, 6, 5
i=2 2, 3, 4, 5, 8, 6
i=1 2, 3, 4, 5, 6, 8
Khác với sắp xếp trộn, phần không đệ qui của thuật toán này không kết hợp các lời
giải con mà là đi xây dựng các bài toán con.
Bước đầu tiên thuật toán chọn một phần tử trong mảng làm mốc (pivot). Sau đó
mảng được chia thành hai phần ở hai phía của mốc: các phần tử lớn hơn mốc được đưa
sang phải và các phần tử không lớn hơn mốc được đưa sang trái mốc. Nếu bây giờ mỗi
phần được sắp thứ tự nhờ lời gọi đệ qui thì toàn bộ mảng sẽ được sắp thứ tự mà không
cần trộn.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 44
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Lưu ý rằng có nhiều biến thể của thuật toán QuickSort, chủ yếu khác nhau ở
phương pháp chọn phần tử để đặt mốc. Ở đây ta sẽ chọn phần tử đầu tiên của mảng làm
mốc.
Mô tả thuật toán:
Procedure QuickSort(T[i..j]);
Else
Datmoc(T[i..j],m);
{sau khi đặt mốc thì T[k] T[m] với ik<m và T[k] > T[m] với m<kj }
QuickSort(T[i..m-1]); QuickSort(T[m+1..j]);
Trong đó thủ tục Datmoc sẽ chia mảng T thành 2 phần như mong muốn. Ta sẽ thực
hiện điều này bằng cách duyệt mảng T đồng thời từ hai đầu. Dùng 2 biến k và h để duy
trì 2 vị trí duyệt, khởi tạo k:=i và h:=j+1. Tăng k cho đến khi T[k] > p và giảm h cho tới
khi T[h] p. Khi đó đổi chỗ T[k] và T[h]. Quá trình này còn tiếp tục khi nào mà k<h.
Cuối cùng đổi chỗ T[i] và T[h] để đặt mốc đúng chỗ.
Trong thuật toán này ta đã chọn thuật toán sắp xếp chèn làm thuật toán sắp xếp cơ sở
while k<h do
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 45
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Giả thiết mảng đã cho có kích thước n = 2k và giả sử ở mỗi lần đặt mốc mảng được
chia làm hai phần có kích thước gần bằng nhau. Dễ thấy độ phức tạp của thủ tục Datmoc
là n. Gọi thời gian chạy của thuật toán QuickSort với mảng kích thước n là h(n).
Do đó ta có h(n) = O(n.logn)
Giả sử T[1..n] là mảng, ta đã biết một số thuật toán sơ cấp sắp xếp mảng với độ
phức tạp là O(n2). Theo cách tiếp cận chia để trị ta sẽ chia T thành hai phần có kích thước
gần bằng nhau và sắp xếp các phần này bằng lời gọi đệ qui, sau đó trộn các kết quả, lưu ý
bảo toàn thứ tự. Công việc chủ yếu chỉ là trộn 2 mảng sắp thứ tự thành 1 mảng sắp thứ
tự. Mô tả thuật toán như sau:
Procedure SXTron(T[i..j]);
Else
SXTron(U); SXTron(V);
Tron(T,U,V);
Trong đó Insert(T) là thuật toán sắp xếp chèn đã biết, còn Tron(T,U,V) là thủ tục
trộn 2 mảng U, V đã sắp thứ tự thành mảng sắp thứ tự T.
Thuật toán này phù hợp với mô tả tổng quát của kỹ thuật chia để trị, trong đó thao
tác Tron chính là việc kết hợp các lời giải của bài toán con để được lời giải của bài toán
ban đầu.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 46
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Câu 1 : Đánh giá độ phức tạp trong trường hợp tồi nhất của các thuật toán sắp xếp
sơ cấp đã nêu.
Câu 2 : Trong các thuật toán sắp xếp sơ cấp trên, thuật toán nào có tính ổn định?
Giải thích.
Câu 3 : Chạy từng bước các thuật toán sắp xếp đã nêu trên các mảng cụ thể có kích
thước 10.
Câu 4: Mô tả một thuật toán thích hợp sắp xếp một mảng các bit. Cho biết độ phức
tạp của thuật toán được sử dụng.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 47
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 48
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Để tìm kiếm tuần tự một phần tử T cho trước trong mảng A ta sử dụng một vòng
lặp, tại mỗi bước của vòng lặp ta thao tác với một phần tử xác định của mảng, ở đây cụ
thể là so sánh lần lượt mỗi phần tử của mảng với T (hay kiểm tra xem phần tử tương ứng
có tính chất P hay không). Thao tác này được gọi là duyệt mảng. Việc duyệt mảng được
dừng lại khi bắt gặp một phần tử bằng T hoặc đã so sánh hết các phần tử của mảng. Khi
gặp một phần tử bằng T (hay có tính chất P) ta sẽ ghi nhận sự kiện này.
Mô tả 1 :
Bước 1: i = Vị trí đầu;
Bước 2: Nếu a[i] = x : Tìm thấy. Dừng, vị trí xuất hiện: i
Bước 3 : i = Vị trí kế(i);// xét tiếp phần tử kế trong mảng
Bước 4: Nếu i >Vị trí cuối: //Hết mảng
Không tìm thấy. Dừng.
Ngược lại: Lặp lại Bước 2.
Mô tả 2:
Procedure TimTT(A,T);
Found:= False;
For i:=1 to n do
If A[i]=T then
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 49
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Found:=True;
Exit;
If A[i]=T
Mô tả 1
Bước 1: left = VTĐ; right = VTC;
Bước 2: Trong khi left right lặp: //đoạn tìm kiếm chưa rỗng
Bước 2.1: mid = (left+right)/2; // lấy mốc so sánh
Bước 2.2: Nếu a[mid] = x: //Tìm thấy.
Dừng, vị trí xuất hiện: mid
Bước 2.3: Nếu a[mid] > x: //tìm x trong dãy con aleft .. amid -1
right = mid - 1;
Ngược lại //tìm x trong dãy con amid +1 .. aright
left = mid + 1;
//Hết lặp
Bước 3: Dừng, không tìm thấy.
Procedure TimNP(A,T);
g:=(d+c) div 2;
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 50
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
Else
Else d:=g+1;
If co then
Nếu T < A[g] thì với mọi chỉ số k > g ta có T < A[g] < A[k] (do mảng sắp thứ tự
tăng), do đó ta chỉ cần tìm T trong mảng ứng với các chỉ số k < g. Lúc này ta thu hẹp
phạm vi tìm kiếm bằng cách xác định lại vị trí cuối của phạm vi là g-1.
Nếu T > A[g] thì ta thực hiện một hành động tương tự là tìm T trong mảng ứng với
các chỉ số k > g. Lúc này ta thu hẹp phạm vi tìm kiếm bằng cách xác định lại vị trí đầu
của phạm vi là g+1.
Ví dụ
- Với T = 14 ta có các bước tìm kiếm được thể hiện như sau
1 1 4 5 22 F
2 3 4 2 6 F
3 3 4 3 14 T
- Với T = 50 ta có các bước tìm kiếm được thể hiện như sau
1 5 9 5 22 F
2 6 9 7 25 F
3 8 9 8 30 F
4 9 9 9 45 F
5 10 9 9 45 F
Kết luận giá trị T không có trong mảng vì giá trị của biến co là False.
Câu 1 : Đánh giá độ phức tạp của các thuật toán tìm kiếm sơ cấp
Câu 2 : Mô tả thuật toán Tìm phần tử lớn thứ nhì trong một dãy tuỳ ý có n phần tử
và đánh giá độ phức tạp của thuật toán.
Câu 3 : Chạy từng bước thuật toán tìm nhị phân trên một mảng cụ thể có 16 phần
tử, xét hai trường hợp: phần tử cần tìm có trong mảng và không có trong mảng.
Câu 4 : Mô tả thuật toán Tìm phần tử xuất hiện nhiều lần nhất trong một dãy tuỳ ý
có n phần tử và đánh giá độ phức tạp của thuật toán.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 52
Trường Trung Cấp Nghề Cơ Điện Đông Nam Bộ Khoa Công nghệ thông tin
1. Niklaus Wirth, Cấu trúc dữ liệu + Giải thuật = Chương trình, bản dịch
tiếng Việt của Nguyễn Quốc Cường, NXBGD, 1993.
3. Đinh Mạnh Tường, Cấu trúc dữ liệu và thuật toán, NXBKHKT, 2001
4. Trần Hạnh Nhi, Trương Anh Đức, Giáo trình Cấu trúc dữ liệu 1, Khoa CNTT,
ĐHKHTN, ĐHQGHCM, 1996.
Publishing, 1993.
6. Alfred V. Aho, Jeffrey D. Ullman, Cơ sở của khoa học máy tính, Tập 1, 2,
Bản dịch tiếng Việt của Trần Đức Quang, NXB Thống kê, 1999.
7. Larry Nyhoff, Sanford Leestma, Lập trình nâng cao bằng Pascal với các cấu
trúc dữ liệu, Tập 1, 2, Bản dịch tiếng Việt của Lê Minh Trung, Công ty Scitec, 1991.
Giáo trình môn học Cấu Trúc Dữ Liệu & Giải Thuật Trang 53