Thực tập KỸ THUẬT LẬP TRÌNH
Tuần 7-9: Thực hiện các chức năng sắp xếp
Yêu cầu: Với dữ liệu sinh viên gồm các thông tin:
Mã lớp
Mã sinh viên
Họ và tên
Ngày sinh
Điểm trung bình tích lũy
đã nhập và lưu trữ trên file. Ví dụ đã nhập được danh sách sinh viên như sau:
Mã lớp
|
Mã sinh viên
|
Họ và tên
|
Ngày sinh
|
ĐTBTL
|
13A
|
2014000001
|
Nguyễn Đình Giang
|
02/12/1996
|
3.4
|
13C
|
2014000002
|
Trịnh Văn Anh
|
24/10/1996
|
2.8
|
13B
|
2014000003
|
Hoàng Xuân Đạt
|
15/06/1996
|
3.2
| Hãy thực hiện các các yêu cầu sau: Sắp xếp danh sách sinh viên theo Mã lớp. Ví dụ danh sách trên sau khi xếp theo mã lớp ta được:
Mã lớp
|
Mã sinh viên
|
Họ và tên
|
Ngày sinh
|
ĐTBTL
|
13A
|
2014000001
|
Nguyễn Đình Giang
|
02/12/1996
|
3.4
|
13B
|
2014000003
|
Hoàng Xuân Đạt
|
15/06/1996
|
3.2
|
13C
|
2014000002
|
Trịnh Văn Anh
|
24/10/1996
|
2.8
| Sắp xếp danh sách sinh viên theo Mã sinh viên (như sanh sách đã cho). Sắp xếp danh sách sinh viên theo Họ và tên. Họ và tên sinh viên được so sánh theo tên rồi đến họ đệm. Ví dụ danh sách sinh viên ở trên đặc xếp lại theo họ tên là
Mã lớp
|
Mã sinh viên
|
Họ và tên
|
Ngày sinh
|
ĐTBTL
|
13C
|
2014000002
|
Trịnh Văn Anh
|
24/10/1996
|
2.8
|
13B
|
2014000003
|
Hoàng Xuân Đạt
|
15/06/1996
|
3.2
|
13A
|
2014000001
|
Nguyễn Đình Giang
|
02/12/1996
|
3.4
| Sắp xếp danh sách sinh viên theo Ngày sinh. Ngày sinh được so sánh theo năm, đến tháng, và cuối là đến ngày. Ví dụ danh sách trên sau khi sắp xếp ta được:
Mã lớp
|
Mã sinh viên
|
Họ và tên
|
Ngày sinh
|
ĐTBTL
|
13B
|
2014000003
|
Hoàng Xuân Đạt
|
15/06/1996
|
3.2
|
13C
|
2014000002
|
Trịnh Văn Anh
|
24/10/1996
|
2.8
|
13A
|
2014000001
|
Nguyễn Đình Giang
|
02/12/1996
|
3.4
| Sắp xếp danh sách sinh viên theo mã lớp, cùng mã lớp sắp xếp theo họ tên, cùng họ tên thì sắp xếp theo ngày sinh. Kiến thức liên quan: A. MỘT SỐ THUẬT TOÁN SẮP XẾP
Bài toán sắp xếp thường được mô tả như sau:
Cho danh sách X chứa n phần tử X[1], X[2], ..., X[n]. Giả thiết là các phần tử của danh sách X có thể so sánh hơn kém với nhau theo một tiêu chí nào đó. Theo tiêu chí được chọn trước, cần sắp xếp lại mảng X theo thứ tự không giảm (hoặc không tăng).
Trong mục này chúng ta xét trường hợp các phần tử của mảng X là số thực và yêu cầu sắp xếp X sao cho thành dãy không giảm. Có khá nhiều thuật toán sắp xếp để giải quyết bài toán đã nêu. Trong phần tiếp theo chúng ta xem xét một số thuật toán sắp xếp đơn giản như sắp xếp chọn (selection sort) , sắp xếp chèn (insertion sort) và sắp xếp nổi bọt (buble sort).
5.2.1. Sắp xếp chọn
Ý tưởng:
Xét từng vị trí, từ 1 đến n-1, tại mỗi vị trí tìm phần tử thích hợp và chuyển đến. Như vậy, phần tử thích hợp với vị trí thứ nhất phải là phần tử bé nhất trong danh sách (với bài toán sắp xếp thành dãy không tăng thì phần tử đầu tiên phải là phần tử lớn nhất trong dãy). Ở vị trí thứ hai phải là phần tử bé nhất trong các phần tử còn lại (với bài toán sắp xếp thành dãy không tăng thì phần tử thứ hai phải là phần tử lớn nhất trong các phần tử còn lại của dãy).
Cứ như vậy, giả sử đã chọn được các phần tử thích hợp cho các vị trí từ thứ nhất đến vị trí thứ i-1. Rõ ràng phần tử thích hợp với vị trí thứ i phải là phần tử bé nhất (hoặc phần tử lớn nhất đối với bài toán sắp xếp thành dãy không tăng) trong các phần tử còn lại {X[i], X[i+1], ..., X[n]}. Việc chọn phần tử thứ i có thể mô tả như sau:
Kí hiệu X[k] = min {X[i], X[i+1], ..., X[n]};
Nếu k > i thì đổi chỗ hai phần tử X[k] và X[i];
Do có thể xét vị trí i từ 1 nên có thể mô tả thuật toán như sau:
Dữ liệu vào: Dãy X[1], X[2], ...., X[n]
Dữ liệu ra: Dãy X không giảm: X[1] X[2] .... X[n];
for (i = 1; i
{
X[k] = min { X[i], ,..., X[n]};
if (k>i) swap (X[k], X[i]);
}
Kỹ thuật đổi chỗ X[k] và X[i]:
{
tg = X[k];
X[k]= X[i];
X[i] = tg;
}
Ví dụ 5.1: Sắp xếp dãy số sau thành không giảm:
13, 22, 30, 14, 21, 5, 21, 12, 15, 19
Áp dụng thuật toán sắp xếp chọn đối với 3 vị trí đầu của dãy:
1) i = 1:
-
13
|
22
|
30
|
14
|
21
|
5
|
21
|
12
|
15
|
19
|
Đổi chỗ X[1], X[6]:
-
5
|
22
|
30
|
14
|
21
|
13
|
21
|
12
|
15
|
19
|
2) i = 2:
-
5
|
22
|
30
|
14
|
21
|
13
|
21
|
12
|
15
|
19
|
Đổi chỗ X[2], X[8]:
-
5
|
12
|
30
|
14
|
21
|
13
|
21
|
22
|
15
|
19
|
3) i = 3:
-
5
|
12
|
30
|
14
|
21
|
13
|
21
|
22
|
15
|
19
|
Đổi chỗ X[3], X[6]:
-
5
|
12
|
13
|
14
|
21
|
30
|
21
|
22
|
15
|
19
|
Như vậy, sau khi thực hiện 3 bước của thuật toán, dãy đã có 3 phần tử đầu tiên đứng đúng vị trí (trong thứ tự không giảm).
Thuật toán chi tiết:
Dữ liệu vào: Dãy X[1], X[2], ...., X[n]
Dữ liệu ra: Dãy X không giảm: X[1] X[2] .... X[n];
for (i=1; i
{
k = 1;
for (j=k+1; j<=n; j++) if (X[j]
if (k>i) {tg = X[k]; X[k]= X[i]; X[i] = tg;}
}
Thuật toán có độ phức tạp O(n2), trong đó có (n-1)(n+2) phép so sánh và nhiều nhất là 3(n-1) phép hoán đổi vị trí các phần tử.
5.2.2. Sắp xếp nổi bọt
Tại mỗi bước lớn của thuật toán sắp xếp nổi bọt một phần tử được đưa về đúng vị trí của nó. Như vậy, thuật toán sắp xếp nổi bọt cũng chỉ có n-1 bước lớn. Đây là điểm giống với thuật toán sắp xếp chọn.
Điểm khác biệt là ở chỗ trong mỗi bước lặp của thuật toán sắp xếp chọn chỉ thông qua các phép toán so sánh để xác định vị trí hiện thời của phần tử thích hợp với vị trí đang được xét đến tại bước lặp, sau đó có thể thực hiện phép đổi chỗ để đưa phần tử về vị trí thích hợp; trong khi đó, với thuật toán sắp xếp nổi bọt, sẽ phải thực hiện liên tiếp một số phép toán so sánh và đổi chỗ để đưa được phần tử thích hợp về vị trí đang xét đến trong bước lặp của thuật toán. Chẳng hạn, xét bước thứ i, 1 i n:
Các phần tử ở vị trí trước i đều đã được chọn thích hợp;
Xét lần lượt các cặp (X[j-1], X[j]), j = n, ..., i+1, nếu X[j-1] > X[j] thì đổi chỗ X[j-1] và X[j].
Ví dụ 5.2: Xét dãy có 10 phần tử
-
13
|
22
|
3
|
14
|
14
|
15
|
21
|
14
|
15
|
19
|
Xét bước thứ i = 1
j = 10
-
13
|
22
|
3
|
14
|
14
|
15
|
21
|
14
|
15
|
19
|
j = 9
-
13
|
22
|
3
|
14
|
14
|
15
|
21
|
14
|
15
|
19
|
j = 8
-
13
|
22
|
3
|
14
|
14
|
15
|
21
|
14
|
15
|
19
|
Kết quả:
-
13
|
22
|
3
|
14
|
14
|
15
|
14
|
21
|
15
|
19
|
j = 7
-
13
|
22
|
3
|
14
|
14
|
15
|
14
|
21
|
15
|
19
|
Kết quả:
-
13
|
22
|
3
|
14
|
14
|
14
|
15
|
21
|
15
|
19
|
j = 6
-
13
|
22
|
3
|
14
|
14
|
14
|
15
|
21
|
15
|
19
|
j = 5
-
13
|
22
|
3
|
14
|
14
|
14
|
12
|
21
|
15
|
19
|
j = 4
-
13
|
22
|
3
|
14
|
14
|
14
|
12
|
21
|
15
|
19
|
j = 3
-
13
|
22
|
3
|
14
|
14
|
14
|
12
|
21
|
15
|
19
|
Kết quả
-
13
|
3
|
22
|
14
|
14
|
14
|
12
|
21
|
15
|
19
|
j = 2
-
13
|
3
|
22
|
14
|
14
|
14
|
12
|
21
|
15
|
19
|
Kết quả
-
3
|
13
|
22
|
14
|
14
|
14
|
12
|
21
|
15
|
19
|
Trong ví dụ trên, sau khi kiểm tra từ chỉ số j = 10 đến j = 2 để đổi chỗ các cặp “nghịch biến", X[j-1] > X[j], thuật toán đã chuyển được phần tử nhỏ nhất vào vị trí i=1. Không khó để chứng minh rằng phép toán b) ở bước thứ i nêu trên chuyển được phần tử nhỏ nhất trong số các phần tử {X[i], ..., X[n]} về vị trí thứ i.
Thuật toán chi tiết:
Dữ liệu vào: Dãy X[1], X[2], ...., X[n]
Dữ liệu ra: Dãy X không giảm: X[1] X[2] .... X[n];
for (i=1; i
{
for (j=n; j>i; j- -)
if (X[j-1] >X[j])
{tg = X[j-1]; X[j-1]= X[j]; X[j] = tg;}
}
Thuật toán có độ phức tạp O(n2), trong đó phải thực hiện (n-1)(n+1) phép so sánh và nhiều nhất là 3n(n-1)/2 phép hoán đổi vị trí các phần tử.
5.2.3. Sắp xếp chèn
Ý tưởng:
Giả sử có phần đầu của mảng là B(i) = { X[1],...,X[i] } đã được sắp xếp không giảm:
X[1] ≤ ... ≤ X[i], (5.1)
xét phần tử thứ i+1. Đưa (chèn) X[i+1] vào vị trí thích hợp trong dãy (5.1). Đặt tg = X[i+1]. Có ba khả năng xảy ra:
X[i] ≤ X[i+1]: Giữ nguyên X[i+1] ở vị trí thứ i+1.
Tồn tại chỉ số j, 1< j i, sao cho X[j-1] ≤ tg < X[j]: Kéo toàn bộ các phần tử từ X[j],..., X[i] về phía sau. Chèn giá trị X[i+1] vào vị trí thứ j.
X[i+1] < X[1]. Kéo toàn bộ các phần tử từ X[1],..., X[i] về phía sau. Chèn giá trị X[i+1] vào vị trí thứ 1.
Trường hợp b) có thể mô tả như sau:
j = i+1;
tg = X[i+1];
while (X[j-1] > tg)
{ X[j] = X[j-1];
j = j-1;
}
X[j] = tg;
Trong đoạn mã trên, khi chỉ số j nhận giá trị 1 tương ứng với trường hợp c). Vì vậy, trường hợp b) và c) có thể được mô tả:
j = i+1;
tg = X[i+1];
while ((j>1) && (X[j-1] > tg))
{ X[j] = X[j-1];
j = j-1;
}
X[j] = tg;
Để ý rằng nếu X[i] X[i+1], tức là X[j-1] tg ngay khi j = i+1 thì rõ ràng là vòng lặp không được thực hiện bước nào, chỉ số j không thay đổi, nghĩa là phép gán X[j] = tg thực ra là gán X[i+1] cho chính nó, không làm thay đổi giá trị phần tử nào.
Trong mọi trường hợp, luôn có thể coi B(1) = { X[1] } đã được sắp xếp không giảm. Như vậy, thuật toán sắp xếp chèn có thể được mô tả như sau:
Dữ liệu vào: Dãy X[1], X[2], ...., X[n]
Dữ liệu ra: Dãy X không giảm: X[1] X[2] .... X[n];
for (i=2; i<=n;i++)
{ j = i+1;
tg = X[i+1];
while ((j>1) && (X[j-1] > tg))
{ X[j] = X[j-1];
j = j-1;
}
X[j] = tg;
}
Ví dụ 5.3: Xét dãy X:
-
X
|
13
|
22
|
30
|
14
|
5
|
21
|
21
|
12
|
15
|
19
|
Ta có đoạn B(3) = {X[1], X[2], X[3]} = {13, 22, 30} không giảm. Xét i = 4.
Đặt tg = 14, j= 4.
-
X
|
13
|
22
|
30
|
14
|
5
|
21
|
21
|
12
|
15
|
19
|
j
|
|
|
|
4
|
|
|
|
|
|
|
X[j-1] = 30 > tg =14. Đặt X[j] = X[j-1], tức là X[4] = X[3], j =j -1= 3.
-
X
|
13
|
22
|
30
|
30
|
5
|
21
|
21
|
12
|
15
|
19
|
j
|
|
|
3
|
|
|
|
|
|
|
|
X[j-1] = 22 > tg=14. Đặt X[j] = X[j-1], tức là X[3] = X[2], j =j -1= 2.
-
X
|
13
|
22
|
22
|
30
|
5
|
21
|
21
|
12
|
15
|
19
|
j
|
|
2
|
|
|
|
|
|
|
|
|
X[j-1] = 13 < tg=14. Đặt X[j] = tg. Ta có dãy con B(4) được sắp không giảm.
-
X
|
13
|
14
|
22
|
30
|
5
|
21
|
21
|
12
|
15
|
19
|
j
|
|
2
|
|
|
|
|
|
|
|
|
Thuật toán sắp xếp chèn có độ phức tạp O(n2), trong đó, trong trường hợp xấu nhấtphải thực hiện (n-1)(n+1) phép so sánh và n(n+1)/2 phép đổi chỗ.
Chia sẻ với bạn bè của bạn: |