Trang 1 BÀI GIẢNG Trang 2 NỘI DUNGCHƯƠNG I: MỞ ĐẦUCHƯƠNG II: NGĂN XẾP VÀ HÀNG ĐỢICHƯƠNG III GIẢI THUẬT SẮP XẾPCHƯƠNG IV: CÂY Trang 3 CHƯƠNG I: MỞ ĐẦU1.1.Giải thuật và cấu trúc dữ liệu
Trang 1BÀI GIẢNG CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT
Trang 2NỘI DUNG
CHƯƠNG I: MỞ ĐẦU
CHƯƠNG II: NGĂN XẾP VÀ HÀNG ĐỢI CHƯƠNG III GIẢI THUẬT SẮP XẾP
CHƯƠNG IV: CÂY
CHƯƠNG V: GIẢI THUẬT ĐỆ QUI
Trang 3CHƯƠNG I: MỞ ĐẦU
1.1.Giải thuật và cấu trúc dữ liệu
- Thông thường khi nói đến việc giải quyết bài toán người ta chỉ chú ý tới giải thuật (algorithms)
- Vì vậy: giải thuật là một dãy các câu lệnh (statements) chặt chẽ và rõ ràng xác định một tuần tự các thao tác trên một đối tượng nào đó sao cho sau một số hữu hạn bước thực hiện ta đạt được kết quả mong muốn
- Xét cho cùng giải thuật chỉ phản ánh các phép xử lý trên máy tính điện tử, còn chính dữ liệu với biểu diễn các thông tin cần thiết cho bài toán
- Như vậy giữa cấu trúc dữ liệu và giải thuật có mối quan hệ mật thiết với nhau Không thể nói tới cấu trúc dữ liệu mà
không nói tới giải thuật và ngược lại
Trang 41.2.Cấu trúc dữ liệu và các vấn đề liên qua
1.2.1.Trong một bài toán dữ liệu bao gồm một tập các
phần tử cơ sở mà ta gọi là dữ liệu nguyên tử Chúng có thể là một chữ số, một kí tự nhưng cũng có thể là một con số hay một từ
1.2.2.Cách biểu diễn một cấu trúc dữ liệu trong bộ nhớ được gọi là cấu trúc lưu trữ
1.2.3.Trong ngôn ngữ lập trình bao giờ cũng có cấu trúc
dữ liệu tiền định, chẳng hạn như cấu trúc mảng.
1.3.Ngôn ngữ diễn đạt giải thuật
Bao gồm Pascal, C, C++…nhưng chúng ta sẽ gặp một số hạn chế
- Phải luôn tuân thủ các quy tắc chặt chẽ về cú pháp của ngôn ngữ đó dẫn đến việc trình bày về giải thuật và cấu trúc dữ liệu có phần gò bó và nặng nề.
Trang 5- Phải phụ thuộc vào cấu trúc dữ liệu tiền định của ngôn ngữ nên đôi khi ta không thể hiện được đầy
đủ các ý về cấu trúc mà ta muốn biểu đạt
- Ngôn ngữ nào được chọn cũng chưa chắc khiến mọi người yêu thích và muốn sử dụng
Vì vậy ta sẽ dùng một ngôn ngữ “thô hơn” có đủ
khả năng biểu đạt được giải thuật trên các cấu trúc
đề cập đến đó là “giả ngôn ngữ” hay là ngôn ngữ
“tựa Pascal”
1.3.1.Quy cách về cấu trúc chương trình
Mỗi chương trình thì được gán một tên để phân biệt
và tên chương trình thì đứng sau từ khóa “Program”
Trang 6- Độ dài của tên chương trình không hạn chế Sau tên có thể kèm theo lời thuyết minh được đặt giữa cặp dấu {…}
1.3.2.Kí tự và biểu thức
- 26 chữ cái Latinh in hoa hoặc in thường
- 10 chữ số thập phân
- Các dấu phép toán số học: +, -,*,/, lũy thừa
- Các dấu phép toán quan hệ: <, >, =,<=, >= ,<>
- Giá trị logic: true, false
- Dấu phép toán logic: and, or, not
- Tên biến: dãy chữ cái và chữ số, bắt đầu bằng
chữ cái
- Biến chỉ số có dạng:A[i], B[i,j]
Trang 81.3.3.3.Câu lệnh điều kiện
Có dạng; if B then S
Trong đó: B là biểu thức logic
S là kết quả hoặc câu lệnh khác
Có thể diễn tả bởi sơ đồ.
S2 S1 B
Trang 9false false… false
true B1 true B2 true Bn-1
Sn-1
Trang 10Hoặc : for i :=n down to m do S
*Lặp với số lần không biết trước
While B do S
true false
Khi nào B có giá trị bằng True thì thực hiện S
Hoặc : Repeat S until B Lặp lại S tới khi B nhận giá trị True
true false
Trang 11Read (<danh sách biến>)
Write (<danh sách biến hoặc dòng kí tự>)
Chú ý: Các biến trong danh sách cách nhau bởi dấu phẩy “,”
Dòng kí tự là một dãy các kí tự được đặt giữa hai dấu nháy đơn ‘…’
1.3.3.8.Câu lệnh kết thúc chương trình
End
Trang 12Call<tên thủ tục>(<danh sách tham số thực sự>)
Trang 13CHƯƠNG II: NGĂN XẾP VÀ HÀNG ĐỢI
I Ngăn xếp
1 Định nghĩa về ngăn xếp (stack)
Ngăn xếp là một kiểu danh sách tuyến tính đặc biệt mà phép
bổ sung và loại bỏ luôn luôn thực hiện ở một đầu gọi là đỉnh
Nguyên tắc lưu trữ của stack là vào sau ra trước (LIFO)
Stack có thể rỗng hoặc bao gồm một số phần tử
2 Lưu trữ danh sách bằng mảng (lưu trữ kế tiếp)
* Trường hợp có 1 stack
S là một vectơ dùng để lưu trữ n phần tử
T là một biến trỏ, khi stack rỗng thì T =0, một phần tử mới được
bổ sung thì T tăng lên 1, loại bỏ một phần tử T giảm đi 1
Mô hình lưu trữ cấu trúc dữ liệu của stack như sau:
S1 S2 S3 S4 S5 S6 S7 Sn
Đáy của stack T
Trang 14Giải thuật thêm phần tử vào stack
Trang 15Giải thuật loại bỏ phần tử
Procedure Pop (S,T,Y)
{xét xem stack đã rỗng chưa}
Trang 16*Trường hợp từ 3 stack trở lên:
Đáy1 Đỉnh1 Đáy 2 Đỉnh 2 Đáy 3 Đỉnh 3
Trang 18II Hàng đợi
1 Định nghĩa hàng đợi (queue)
Queue là kiểu danh sách tuyến tính mà phép bổ sung được thực hiện ở một đầu và loại bỏ ở một đầu khác
Quy tắc lưu trữ của queue là FIFO (vào trước ra trước)
2 Lưu trữ kế tiếp
- Sử dụng một vectơ Q có n phần tử
- R là con trỏ trỏ tới lối trước (phải)
- L là con trỏ trỏ tới lối sau (trái)
- Khi Queue rỗng thì R=L=0, khi bổ sung một phần tử thì R tăng lên 1, khi loại bỏ một phần tử thì L tăng lên 1
Trang 20Giải thuật bổ sung phần tử trong Queue
Procedure Them(Q,L,R,X);
{Trường hợp queue đầy}
If L=1 and R=n or L=R+1 then begin Write (‘đã đầy’);
Trang 21Giải thuật loại bỏ
Procedure Delete (Q,L,R,Y);
Trang 22CHƯƠNG III
GIẢI THUẬT SẮP XẾP
Trang 231.Sắp xếp chọn (Selection sort)
Tư tưởng:
Chọn phần tử nhỏ nhất trong n phần tử ban đầu, đưa phần tử này về vị trí đúng là đầu tiên của dãy hiện hành Sau đó không quan tâm đến nó nữa, xem dãy hiện hành chỉ còn n-1 phần tử của dãy ban đầu, bắt đầu từ vị trí thứ
2 Lặp lại quá trình trên cho dãy hiện hành đến khi dãy hiện hành chỉ còn 1 phần tử Dãy ban đầu có n phần tử, vậy tóm tắt ý tưởng thuật toán là thực hiện n-1 lượt việc đưa phần tử nhỏ nhất trong dãy hiện hành về vị trí đúng ở đầu dãy.
Trang 24Các bước tiến hành như sau:
Trang 25Ví dụ: Cho dãy a = (12,2,8,5,1,6,4,15)
• 12 2 8 5 1 6 4 15
Bước 1: 1 2 8 5 12 6 4 15 Bước 2: 1 2 8 5 12 6 4 15 Bước 3: 1 2 4 5 12 6 8 15 Bước 4: 1 2 4 5 12 6 8 15 Bước 5: 1 2 4 5 6 12 8 15 Bước 6: 1 2 4 5 6 8 12 15 Bước 7: 1 2 4 5 6 8 12 15
Trang 282 S p x p n i b t (Bubble_sort) ắp xếp nổi bọt (Bubble_sort) ếp nổi bọt (Bubble_sort) ổi bọt (Bubble_sort) ọt (Bubble_sort)
Sắp xếp nổi bọt (bubble sort) là một thuật toán sắp xếp đơn giản, với thao tác cơ bản là lần lượt cho phần tử nhẹ hơn (áp dụng cho sắp xếp tăng dần) nổi lên trên.
Tư tưởng:
Bước 1: đi từ cuối dãy lên đầu dãy:
Lần lượt so sánh hai phần tử kề nhau là aj và aj-1
nếu aj < aj-1 thì hoán đổi aj < > aj-1
Cứ như thế cho đến đầu dãy, khi đi hết dãy thì số nào nào nhỏ nhất sẽ được sắp xếp (nổi bọt) lên vị trí trên cùng.
Bước 2: Không quan tâm đến phẩn tử đầu tiên đã được sắp xếp Ta áp dụng
bước 1 cho các phần tử còn lại của dãy.
Qúa trình lặp lại cho đến khi tất cả các số trong dãy được sắp xếp theo thứ tự tăng dần.
Trang 29Giải thuật sắp xếp nổi bọt
For i:=1 to (n-1) do
For j:=n downto (i+1) do
If a[j] < a[j-1] then
tg:=a[j];
a[j]:=a[j-1];
a[j-1]:=tg;
Trang 309 5
3
0 1 2 3 4 5 6
8 7
9
0 1 2 3 4 5 7
8 6
9
0 1 2 3 4 5 6
8 7
9
0 1 2 3 4 5 6
8 7
9
0 1 2 3 4 7 5
8 6
9
0 1 2 3 7 4 6
8 5
9
0 1 2 7 4 6 3
8 5
9
0 1 7 4 6 2 3
5 8
9
Bước 1 2 3 4 5 6 7 8 9
Trang 313 Sắp xếp kiểu thêm dần
(insertion sort)
(Insertion sort) là một thuật toán sắp xếp rất hiệu quả với các
danh sách nhỏ Nó lần lượt lấy các phần tử của danh sách chèn vào vị trí thích hợp trong một danh sách mới đã được sắp
Tư tưởng:
Giả sử đã có dãy được sắp xếp theo thứ tự Lần lượt chèn
từng phần tử vào dãy theo đúng quy định đã được sắp xếp
Trang 32Nguyên tắc sắp xếp:
Bước 1: Khởi tạo với dãy chỉ có 2 phần tử đã được sắp xếp
Bước 2: Lần lượt lấy từng phần tử chèn vào dãy đã được sắp xếp theo đúng vị trí
của nó=> ta được dãy mớI được sắp xếp theo thứ tự.
Qúa trình cứ tiếp tục cho đến khi tất cả các phần tử được sắp xếp.
Trang 333. a[j+1]:=x;
Trang 340 5 4 8
9 2
7
0 1 2 3 4 5 6
8
7
9
0 1 3 4 5 6
9
8
7
0 1
2
3 4 5 6
9 8
7
0 1 3
4
5 6 8
9 2
7
0 1 3
5
6 4
8
9 2
7
0
1 3 6 5
4 8
9 2
7
1 3
6
0
5 4 8
9 2
7
-∞
Bước 0 1 2 3 4 5 6 7 8 9
Trang 35II.CÁC PHƯỚNG PHÁP SẮP XẾP CẢI TIẾN
Các phương pháp sắp xếp cảI tiến nhanh hơn về mặt thời gian, nhưng về mặt thuật toán thì phức tạp hơn.
Trang 364 Phương pháp sắp xếp nhanh Quick_ sort
(hay còn gọi là Sắp xếp phân đoạn)
ý tưởng:
Lấy phần tử đầu tiên, cuối cùng hoặc ở giữa làm khóa chốt.Phần tử ở giữa: int(n/2)+1
So sánh các phần tử trong dãy với khóa:
- nếu phần tử nào < khóa: sắp xếp cho nó về vị trí trước
chốt
- nếu phần tử nào > khóa: sắp xếp cho nó về vị trí sau chốt
Trang 37=> dãy khóa được phân làm hai đoạn:
- đoạn trước khóa bao gồm những phần tử nhỏ hơn khóa
- đoạn sau khóa bao gồm những phần tử lớn hơn khóa
Quá trình phân đoạn tiếp tục cho đến khi gặp phân đoạn chỉ gồm hai phần tử, ta thực hiện sắp xếp cho hai phân đoạn này, và thực hiện sắp xếp lên cho các phân đoạn lớn hơn
giải thuật kết thúc khi phân đoạn cuối cùng được xử lí
Trang 38Giải thuật Quick Sort
j:=j-1
if i<j then
doicho(x[i],x[j])3.doicho(x[key],x[j])
4 Phandoan (d,j-1)
Phandoan(j+1,c)
Trang 391 1
8
8
6 7
8 8
7 6
5 5
5
5
5
5 5
5 4
4
4 4
4
0
3
3 3
3
3 3
3 3
3
6
2 2
2
2
2 2
2 2
Trang 41Lần lượt đi từ các dãy chỉ có một phần tử:
- Trộn hai dãy có độ dài là 1 thành một dãy có độ dài 2 bằng cách so sánh phần tử của 2 dãy;
- Trộn hai dãy có độ dài 2 thành một dãy có độ dài 4 bằng cách so sánh phần
Trang 42Ví dụ 1: Cách trộn hai dãy bất kì thành một dãy:
Trang 43* Ví dụ sắp xếp dãy số theo giải thuật Merge_ sort:
Trang 44Lần lượt trộn 2 dãy con như sau:
lần
trộn [3] [1] [6] [0] [5] [4] [8] [2] [9] [7]lần 1 [1 3] [6] [0] [5] [4] [8] [2] [9] [7] lần 2 [1 3] [6] [0 5] [4] [8] [2] [9] [7] lần 3 [1 3] [0 5 6] [4] [8] [2] [9] [7] lần 4 [0 1 3 5 6] [4] [8] [2] [9] [7]
Trang 45* Giải thuật Merge_ Sort:
• Procedure mergesort(A, r, B, s, C);
{A, B la mang da duoc sap xep, r, s lan luot la cac phan tu cua A va B, C la day moi se duoc sap xep} {Khoi tao cac chi so}
i:=1; j:=1; k:=1;
{so sanh de chon ptu nho hon}
While i<=r and j<=s do
Trang 46ví dụ: sắp xếp dãy số: 3 1 6 0 5 4 8 2 9 7
Dãy
số [3] [1] [6] [0] [5] [4] [8] [2] [9] [7]lần 1 [1 3] [0 6] [4 5] [2 8] [7 9]
lần 2 [0 1 3 6] [2 4 5 8] [7 9]
lần 4 [0 1 2 3 4 5 6 7 8 9]
Trang 476 Sắp xếp kiểu vun đống (Heap_sort)
Ta thường sử dụng Heap sort để sắp xếp dãy số a1, a2, …,an theo thứ tự giảm dần
Tư tưởng:
Để giải quyết bài toán ta sử dụng cơ chế heap (vun đống): heap
là cây nhị phân đầy đủ với tính chất: đỉnh cha luôn lớn hơn hai đỉnh con
Để sắp xếp dãy gồm n phần tử: ta xây dựng dãy số thành một
cấu trúc dữ liệu Heap
Ta vun các phần tử thành một đống Khi đó phần tử gốc có giá trị lớn nhất
Trang 48Bước 1: Lấy phần tử gốc ra khỏi cây, (Lúc này cây còn (n-1) phần tử).
Bước 2: Tạo heap cho (n-1) phần tử còn lại và lặp lại bước 1 cho đến khi được một
dãy số sắp xếp giảm dần.
Trong giải thuật ta sử dụng 4 thủ tục:
+ Insert: nhập một phần tử mới vào cây;
+ Upheap: Tạo heap cho cây khi thêm phần tử mới;
+ Downheap: Điều chỉnh lại tính chất head cho cây khi tách phần tử gốc;
+ Remove: tách phần tử gốc (phần tử lớn nhất) ra khỏi cây;
Trang 51Function Remove: integer;
Trang 53Ví dụ:
Sắp xếp dãy số theo thứ tự giảm dần:
3 1 6 0 5 4 8 2 9 7Thực hiện các bước của giải thuật:
Sử dụng thủ tục Insert và Upheap để bổ sung phần tử vào cây và tạo đống:
gọi insert(3) để đưa 3 vào cây, gọi upheap(1) để vun đống cho 3Gọi insert(1) để đưa 1 vào cây, gọi upheap(2) để vun đống cho 1
3 1
Trang 54- Gọi insert(6) để đưa 6 vào cây, gọi upheap(3) để vun đống cho 6:
3
6
Trang 55gọi insert(0) để đưa 0 vào cây, gọi upheap(4) để vun đống cho 0:
Trang 56Cuối cùng ta được cây được vun đống: 3 1 6 0 5 4 8 2 9 7
Sử dụng thủ tục Remove và Downheap để lần lượt đưa từng phần tử
ra khỏi cây và vun đống lại:
Trang 57- Gọi Remove đưa 9 ra khỏi cây: {9}
Và lấy phần tử cuối cùng lên làm gốc; Gọi Downheap để vun đống lại:
Trang 58- Gọi Remove đưa 8 ra khỏi cây: {9 8}
Và lấy phần tử cuối cùng lên làm gốc; Gọi Downheap để vun đống lại:
Trang 59Tiếp tục loại bỏ các phần tử ra khỏi cây, cuối cùng ta được dãy sắp xếp:
9 8 7 6 5 4 3 2 1 0
Trang 60CHƯƠNG IV: CÂY
*Định nghĩa và các khái niệm
Một cây là tập hợp hữu hạn các nút trong đó có một
nút đặc biệt gọi là nút gốc, giữa các nút có quan hệ phân cấp gọi là quan hệ “ cha – con”
*Định nghĩa cây theo cách đệ quy như sau:
a Một nút là một cây, nút đó cũng chính là gốc của cây
b Nếu T1 ,T2 Tk là các cây, với n1,n2,…,nk lần lượt là
các gốc, n là một nút gốc có quan hệ “cha – con” với
n1,n2,…,nk thì lúc đó một cây T mới được tạo lập với n
là gốc của cây T, n được gọi là cha của n1,n2,…,nk, các cây T1 ,T2 Tk được gọi là con của cây T
Trang 61I.CÁC KHÁI NIỆM VỀ CÂY TỔNG QUÁT
• Cây tổng quát:
– Các nút trên cây tổng quát có cấp tuỳ ý
– Số lượng con của mỗi nút trên cây là tuỳ ý.
• Nút là các phần tử trên cây để lưu trữ dữ liệu
– Mỗi nút chứa một thành phần dữ liệu và các liên kết đến các nút khác
• T2 = {c, d, e, f, g}
– Gốc của cây T2 là c – T2 có các cây con là {d}, {e}, {f,g}.
Trang 62• Cấp của nút: Số lượng cây con của một nút
• Với cây tổng quát, số lượng cây con là tuỳ ý, tức là mỗi nút đều có thể có cấp tuỳ ý.
• Cấp của cây là cấp cao nhất của nút trên cây
• Nút lá (hay còn gọi là nút tận cùng): Là nút không có cây con gọi là nút lá
• Đường đi là một chuỗi duy nhất các nút n1, n2, …, nktrong đó ni+1 là con của ni với i=1, 2,… , k-1 (khi đi từ trên xuống) hoặc ni+1 là cha của ni với i= 1, 2, … , k-1 (khi đi từ dười lên) Độ dài của đường đi bằng số nút trên đường đi trừ 1
• Chiều cao của cây là số mức lớn nhất của nút nào đó trên cây
Trang 63• Mức của một nút là giá trị nguyên để đo khoảng cách từ nút đó tới gốc (mỗi cung được tính là 1 đơn vị)
– Nút gốc có mức là 0
– Mức của một nút trên cây được định nghĩa bằng mức của cha của nút đó + 1
II CÁC KHÁI NIỆM VỀ CÂY NHỊ PHÂN
• Cây nhị phân là một cây mà mỗi nút có hai con đó là cây nhị phân trái và phải độc lập nhau Như vậy cây nhị phân
là cây có thứ tự
1.Cây nhị phân bao gồm:
- Cây nhị phân lệch trái là cây mà các nút tương ứng với các mức đều đạt về phía trái
- Cây nhị phân lệch phải là cây mà các nút tương ứng với các mức đều đạt về phía phải
Trang 64- Cây nhị phân zic-zắc là cây nếu nút thứ i đạt về phía trái thì nút i+1 sẽ đạt về phía phải
- Cây nhị phân hoàn chỉnh là cây mà các nút ứng với các mức trừ mức cuối cùng đều đạt tối đa và ở mức cuối cùng các nút đều đạt về phía trái
- Cây nhị phân đầy đủ là cây mà tất cả các nút ứng với các mức đều đạt tối đa (là trường hợp đặc biệt của cây nhị phân hoàn chỉnh)
- Cây nhị phân gần đầy là cây mà các nút ứng với các mức trừ mức cuối đều đạt tối đa và ở mức cuối cùng các nút không đạt hoàn toàn về phía phải
=> Trong các cây nhị phân có cùng một số lượng nút thì cây nhị phân hoàn chỉnh và cây nhị phân gần đầy có chiều cao nhỏ nhất, còn cây nhị phân suy biến có chiều cao lớn nhất
Trang 652.Biểu diễn cây nhị phân
2.1.Lưu trữ kế tiếp
• Trường hợp cây nhị phân đầy đủ thì ta dễ dàng lưu trữ bằng cách đánh số cho các nút theo thứ tự lần lượt từ 1 trở lên hết mức này đến mức khác và từ trái sang phải đối với các nút ở mỗi mức
Trang 662.2.Lưu trữ móc nối
Quy cách một nút của cây nhị phân: gồm 3 trường
Trong đó
• INFO: Thông tin của nút
• LPTR: Con trỏ trỏ đến cây con trái
• RPTR: Con trỏ trỏ đến cây con phải
Trang 673 Thao tác duyệt cây
• Thao tác duyệt cây bắt đầu từ nút gốc và tới thăm các nút trên cây đúng một lần, “thăm” một nút có nghĩa là xử lý dữ liệu chứa trên nút đó.
• Có 3 cách duyệt cây nhị phân:
– Duyệt theo thứ tự trước
– Duyệt theo thứ tự sau
– Duyệt theo thứ tự giữa