Hai đoạn cùng nằm trong dãy A
```python
def mergeSort_into(A, left, right):
if left < right:
mid = (left + right) // 2
mergeSort_into(A, left, mid)
mergeSort_into(A, mid + 1, right)
merge_into(A, left, mid, right)
```
Gọi mergeSort_into(A,0,len(A)−1). Đoạn trái gồm left…mid; đoạn phải gồm mid+1…right. Cả hai đều tính cả biên. Sau khi hai lời gọi đã sắp xếp xong các đoạn, merge_into trộn và ghi lại đúng vùng đó.
Cơ sở left>=right không làm gì; hàm sửa trực tiếp A và không trả một dãy kết quả. Vì vậy không gán A=mergeSort_into(...).
Dãy phụ giữ dữ liệu trong khi trộn
```python
def merge_into(A, left, mid, right):
# Hai đoạn đã sắp xếp; dãy phụ chỉ lớn bằng đoạn đang trộn.
B = [0] * (right - left + 1)
i, j, k = left, mid + 1, 0
while i <= mid and j <= right:
if A[i] <= A[j]:
B[k] = A[i]
i += 1
else:
B[k] = A[j]
j += 1
k += 1
while i <= mid:
B[k] = A[i]
i += 1
k += 1
while j <= right:
B[k] = A[j]
j += 1
k += 1
A[left:right + 1] = B
```
Dãy phụ B có right−left+1 chỗ. i,j chạy theo chỉ số gốc trong A; k chạy từ 0 trong B. Khi trộn xong, A[left:right+1]=B ghi lại đoạn gồm cả right, không đổi phần nằm ngoài đoạn.
Bản này sửa A nhưng **vẫn dùng dãy phụ**; không gọi là chỉ cần bộ nhớ hằng số. Việc tạo dãy phụ theo độ dài đoạn đang trộn giúp mỗi bước trộn có công việc tuyến tính theo đoạn ấy.
Kiểm dãy sau lời gọi
Dùng cùng tệp dãy mẫu và chạy:
```text
python3 g11-cs-sap-xep-tron.py truc-tiep g11-cs-day-can-sap-xep.inp
```
Kết quả cần là `1 2 3 6 7 8`, khớp chế độ sap. Trong mã, sau lời gọi cần đọc A, vì A đã được sửa; giá trị trả về mặc định là None. Thử dãy rỗng, một phần tử, dãy giảm và nhiều giá trị trùng. Nếu thử sắp xếp riêng một đoạn, kiểm cả các phần tử ngoài đoạn vẫn giữ nguyên.
Bài luyện
Khi left=1,mid=3,right=5, hai đoạn cần trộn là gì?
Hai đoạn liền nhau, không trùng mid và gồm right.
Đã đổi sai biên và bỏ A[5].
Vừa lấy ngoài miền vừa lặp A[3].
Bỏ các phần tử ở giữa miền.
Lời giải
Bản chỉ số dùng các đoạn gồm cả hai biên: trái từ left tới mid, phải từ mid+1 tới right. Thay số được 1…3 và 4…5.
Bài luyện
Sau mergeSort_into(A,0,len(A)−1), cần lấy kết quả bằng cách nào?
Bản này không có return dãy.
Hàm ghi kết quả trực tiếp vào A.
Hàm không trả dãy; phép gán ấy làm A thành None.
Kết quả cần gồm toàn dãy.
Lời giải
Các phép trộn ghi lại từng vùng trong A. Sau lời gọi, A đã được sắp xếp; hàm trả None theo mặc định nên không thay A bằng giá trị trả về.
Bài luyện
Bản sửa trực tiếp A trong bài có dùng bộ nhớ phụ không?
Đoạn đang trộn có thể dài nên B không có kích thước hằng số.
Mã chỉ cấp chỗ theo đoạn đang trộn, không theo toàn dãy mọi lần.
B có độ dài right−left+1.
Cách lưu kết quả và việc dùng bộ nhớ phụ là hai điều khác nhau.
Lời giải
merge_into giữ các giá trị trong B rồi chép B vào đúng vùng A. Nhờ vậy tránh ghi đè dữ liệu chưa đọc; sửa A không đồng nghĩa thuật toán không dùng dãy phụ.
Đang học