Tài liệu trình bày các kiến thức về một số thuật toán sắp xếp và một số kỹ thuật xử lý xâu để áp dụng cho bài toán sắp xếp trong quản lý sinh viên. Mời các bạn cùng tham khảo. Tài liệu trình bày các kiến thức về một số thuật toán sắp xếp và một số kỹ thuật xử lý xâu để áp dụng cho bài toán sắp xếp trong quản lý sinh viên. Mời các bạn cùng tham khảo.
Thực tập KỸ THUẬT LẬP TRÌNH Tuần 7-9: Thực chức xếp Yêu cầu: Với liệu sinh viên gồm thông tin: Mã lớp Mã sinh viên Họ tên Ngày sinh Điểm trung bình tích lũy nhập lưu trữ file Ví dụ nhập danh sách sinh viên sau: Mã lớp 13A 13C 13B Mã sinh viên 2014000001 2014000002 2014000003 Họ tên Nguyễn Đình Giang Trịnh Văn Anh Hoàng Xuân Đạt Ngày sinh 02/12/1996 24/10/1996 15/06/1996 ĐTBTL 3.4 2.8 3.2 Hãy thự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 sau xếp theo mã lớp ta được: Mã lớp 13A 13B 13C Mã sinh viên 2014000001 2014000003 2014000002 Họ tên Nguyễn Đình Giang Hoàng Xuân Đạt Trịnh Văn Anh Ngày sinh 02/12/1996 15/06/1996 24/10/1996 ĐTBTL 3.4 3.2 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ọ tên Họ tên sinh viên so sánh theo tên đến họ đệm Ví dụ danh sách sinh viên đặc xếp lại theo họ tên Mã lớp 13C 13B 13A Mã sinh viên 2014000002 2014000003 2014000001 Họ tên Trịnh Văn Anh Hoàng Xuân Đạt Nguyễn Đình Giang Ngày sinh 24/10/1996 15/06/1996 02/12/1996 ĐTBTL 2.8 3.2 3.4 - Sắp xếp danh sách sinh viên theo Ngày sinh Ngày sinh so sánh theo năm, đến tháng, cuối đến ngày Ví dụ danh sách sau xếp ta được: Mã lớp 13B 13C 13A Mã sinh viên 2014000003 2014000002 2014000001 Họ tên Hoàng Xuân Đạt Trịnh Văn Anh Nguyễn Đình Giang Ngày sinh 15/06/1996 24/10/1996 02/12/1996 ĐTBTL 3.2 2.8 3.4 - Sắp xếp danh sách sinh viên theo mã lớp, mã lớp xếp theo họ tên, họ tên 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 xếp thường mô tả sau: Cho danh sách X chứa n phần tử X[1], X[2], , X[n] Giả thiết phần tử danh sách X so sánh với theo tiêu chí Theo tiêu chí chọn trước, cần xếp lại mảng X theo thứ tự không giảm (hoặc không tăng) - Trong mục xét trường hợp phần tử mảng X số thực yêu cầu xếp X cho thành dãy không giảm Có nhiều thuật toán xếp để giải toán nêu Trong phần xem xét số thuật toán xếp đơn giản xếp chọn (selection sort) , xếp chèn (insertion sort) xếp bọt (buble sort) 5.2.1 Sắp xếp chọn Ý tưởng: - Xét vị trí, từ đến n-1, vị trí tìm phần tử thích hợp chuyển đến Như vậy, phần tử thích hợp với vị trí thứ phải phần tử bé danh sách (với toán xếp thành dãy không tăng phần tử phải phần tử lớn dãy) Ở vị trí thứ hai phải phần tử bé phần tử lại (với toán xếp thành dãy không tăng phần tử thứ hai phải phần tử lớn phần tử lại dãy) - Cứ vậy, giả sử chọn phần tử thích hợp cho vị trí từ thứ đến vị trí thứ i-1 Rõ ràng phần tử thích hợp với vị trí thứ i phải phần tử bé (hoặc phần tử lớn toán xếp thành dãy không tăng) phần tử lại {X[i], X[i+1], , X[n]} Việc chọn phần tử thứ i mô tả sau: Kí hiệu X[k] = {X[i], X[i+1], , X[n]}; Nếu k > i đổi chỗ hai phần tử X[k] X[i]; Do xét vị trí i từ nên mô tả thuật toán 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; ii) swap (X[k], X[i]); } - Kỹ thuật đổi chỗ X[k] 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 xếp chọn vị trí đầu dãy: 1) i = 1: 13 22 30 14 21 21 12 15 19 k=6, X[6] = {X[1], , X[10]} Vị trí xét, i=1 Đổi chỗ X[1], X[6]: 22 30 14 21 13 21 12 15 19 2) i = 2: 22 30 14 21 13 21 12 15 19 Vị trí xét, i=2 k=8, X[8] = {X[2], , X[10]} Đổi chỗ X[2], X[8]: 12 30 14 21 13 21 22 15 19 3) i = 3: 12 30 14 21 13 21 22 15 19 Vị trí xét, i=3 k=6, X[6] = {X[3], , X[10]} Đổi chỗ X[3], X[6]: 12 13 14 21 30 21 22 15 19 - Như vậy, sau thực bước thuật toán, dãy có phần tử đứ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 14 = X[8] đổi chỗ X[7] X[8] 14 14 15 14 21 15 19 14 14 15 14 21 15 19 j= 13 22 Kết quả: 13 22 j=7 X[6] =15 > 14 = X[ 7] đổi chỗ X[6] X[7] 14 14 14 15 21 15 19 14 14 14 15 21 15 19 21 15 19 21 15 19 j= 13 22 j= 13 22 14 j= 13 22 14 14 j=6 X[5] =14 = X[6] không đổi chỗ 14 12 j=5 X[4] =14 = X[5] không đổi chỗ 14 14 12 j=4 X[3] =3 < 14 = X[4] không đổi chỗ j= 13 22 14 14 14 12 21 15 19 j=3 X[2] =22 > = X[2] đổi chỗ X[2] X[3] Kết 13 22 14 14 14 12 21 15 19 13 22 14 14 14 12 21 15 19 12 21 15 19 j= j=2 X[1] =13 > = X[2] đổi chỗ X[1] X[2] Kết 13 22 14 14 14 Trong ví dụ trên, sau kiểm tra từ số j = 10 đến j = để đổi chỗ cặp “nghịch biến", X[j-1] > X[j], thuật toán chuyển phần tử nhỏ vào vị trí i=1 Không khó để chứng minh phép toán b) bước thứ i nêu chuyển phần tử nhỏ số phần tử {X[i], , X[n]} 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; ii; 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), phải thực (n-1)(n+1) phép so sánh nhiều 3n(n-1)/2 phép hoán đổi vị trí phần tử 5.2.3 Sắp xếp chèn Ý tưởng: - Giả sử có phần đầu mảng B(i) = { X[1], ,X[i] } 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 dãy (5.1) Đặt tg = X[i+1] Có ba khả xảy ra: a) X[i] ≤ X[i+1]: Giữ nguyên X[i+1] vị trí thứ i+1 b) Tồn số j, 1< j i, cho X[j-1] ≤ tg < X[j]: Kéo toàn phần tử từ X[j], , X[i] phía sau Chèn giá trị X[i+1] vào vị trí thứ j c) X[i+1] < X[1] Kéo toàn phần tử từ X[1], , X[i] phía sau Chèn giá trị X[i+1] vào vị trí thứ Trường hợp b) mô tả 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, số j nhận giá trị tương ứng với trường hợp c) Vì vậy, trường hợp b) 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; - Để ý X[i] X[i+1], tức X[j-1] tg j = i+1 rõ ràng vòng lặp không thực bước nào, số j không thay đổi, nghĩa phép gán X[j] = tg thực gán X[i+1] cho nó, không làm thay đổi giá trị phần tử - Trong trường hợp, coi B(1) = { X[1] } xếp không giảm Như vậy, thuật toán xếp chèn mô tả 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; i1) && (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 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 = Đặt tg = 14, j= X 13 22 30 14 21 21 12 15 19 j X[j-1] = 30 > tg =14 Đặt X[j] = X[j-1], tức X[4] = X[3], j =j -1= X 13 22 30 30 21 21 12 15 19 j X[j-1] = 22 > tg=14 Đặt X[j] = X[j-1], tức X[3] = X[2], j =j -1= X 13 22 22 30 21 21 12 15 19 j X[j-1] = 13 < tg=14 Đặt X[j] = tg Ta có dãy B(4) không giảm X 13 14 22 30 21 21 12 15 19 j - Thuật toán xếp chèn có độ phức tạp O(n 2), đó, trường hợp xấu nhấtphải thực (n-1)(n+1) phép so sánh n(n+1)/2 phép đổi chỗ B MỘT SỐ KỸ THUẬT XỬ LÝ XÂU Trong thực tiễn việc xử lý chuỗi ký tự xảy thường xuyên máy tính, nhu cầu định nghĩa kiểu liệu đặc biệt cho chuỗi ký tự đặt cho ngôn ngữ lập trình Trong ngôn ngữ lập trình C, chuỗi ký từ mảng ký tự với ký tự đặc biệt đánh dấu kết thúc – mã Do đặc trưng riêng nhu cầu xử lý thường xuyên nên ngôn ngữ lập trình xây dựng thư viện hàm xử lý chuỗi ký tự 2.2.1 Khai báo nhập xuất liệu Khai báo - Cú pháp: char Tên_biến_1[Số_phần_tử_1], … ,Tên_biến_n[Số_phần_tử_n]; - Trong đó: - char: từ khóa kiểu liệu cho chuỗi - Tên_biến_1, …, Tên_biến_n: Tên biến người sử dụng tự định nghĩa, lưu ý tên biến phải tuân theo qui tắc đặt tên qui định ngôn ngữ lập trình - Số_phần_tử_1,…, Số_phần_tử_n: Hằng số nguyên dương xác định số phần tử của chuỗi Tùy theo hỗ trợ hệ điều hành trình biên dịch mà số lượng phần tử chuỗi khác Ví dụ 2.1: Khai báo chuỗi char x[10]; - Khai báo chuỗi x có nhiều 10 ký tự, số để truy xuất đến ký tự chuỗi x từ đến - Chú ý: Bản chất chuỗi mảng ký tự với ký tự kết thúc ‘\0’ quan niệm mảng với chuỗi ký tự - Khai báo chuỗi với giá trị khởi tạo theo cú pháp sau - Cú pháp: char Tên_biến_1[ Số_phần_tử_1 ] = {chuỗi_khởi_tạo_1}, … Tên_biến_n[ Số_phần_tử_n ] = {chuỗi_khởi_tạo_n}; - Trong đó: - Tên_biến_1, …, Tên_biến_n, Số_phần_tử_1, …, Số_phần_tử_n hiểu trên; - chuỗi_khởi_tạo_1, …, chuỗi_khởi_tạo_n chuỗi khởi tạo cho giá trị biến - Trong trường hợp khai báo có khởi tạo giá trị, độ dài chuỗi để trống, lúc hệ thống xác định độ dài chuỗi theo độ dài chuỗi khởi tạo - Ví dụ 2.2: Khai báo mảng có khởi tạo giá trị char s[100]= "Xin chao den voi ky thua lap trinh"; char a[]="Ky thuat lap trinh co ban"; - Khai báo chuỗi s có độ dài tối đa 100 ký tự, khởi tạo chuỗi ban đầu “Xin chao den voi ky thua lap trinh” Chuỗi a khởi tạo “Ky thuat lap trinh co ban” với độ dài tối đa chuỗi độ dài chuỗi khởi tạo - Chú ý: Cách khai báo chuỗi ký tự hoàn toàn khác với khai báo char *b="Con tro den hang so chuoi"; trường hợp khai báo trỏ kiểu ký tự khởi tạo trỏ trỏ đến địa chứa số chuỗi chương trình Vì số chuỗi nên thay đổi liệu trỏ đến trỏ b nảy sinh lỗi - Truy xuất phần tử - Truy xuất phần tử chuỗi thông qua cặp ngoặc [, ] truy xuất phần tử mảng Mỗi phần tử chuỗi ký tự - Ví dụ 2.3: Ví dụ truy xuất phần tử chuỗi char s[100]= "Xin chao den voi ky thua lap trinh"; s[0]='x'; Nhập xuất liệu xâu - Chuỗi kiểu mảng đặc biệt xem kiểu liệu nên ngôn ngữ lập trình C hỗ trợ hàm nhập xuất xâu a) Nhập xâu - Sử dụng hàm scanf() với tham số %s Ví dụ 2.4: Nhập xâu hàm scanf() char s[100]; scanf("%s",s); - Sử dụng hàm gets() Cú pháp: char *gets(char *s); Tham số đầu vào s trỏ xâu Giá trị trả về: trỏ đến xâu nhập vào Ví dụ 2.5: Nhập xâu hàm gets() char a[100]; char *b; b=gets(a); b) Xuất chuỗi - Xuất xâu lên hình hàm printf() với tham số %s Ví dụ 2.6: Xuất xâu hàm printf() char s[100]= "Xin chao den voi ky thua lap trinh"; printf("Loi chao: %s",s); - Xuất xâu lên hình sử dụng hàm puts() Cú pháp: int puts(const char *s); Trong s xâu cần đưa lên hình, đưa ký tự lên hình đến gặp ký tự kết thúc có mã ASCII Giá trị trả hàm số ký tự xuất lên hình Ví dụ 2.7: Xuất xâu hàm puts() char s[100]= "Xin chao den voi ky thua lap trinh"; int c; c=puts(s); - Xây dựng xâu từ hàm sprintf() Cú pháp: int sprintf (char *buffer, const char *format [, argument, ]); Trong buffer xâu nhận kết Hàm sprintf() tương tự hàm printf() kết thay đưa lên hình đưa vào xâu buffer Ví dụ 2.8: Xuất xâu hàm sprintf() #include #include int main() { char s[100]; int a=5, b=7; sprintf(s,"Tich cua %d va %d la %d",a,b,a*b); puts(s); getch(); return 0; } 2.2.2 Các hàm xử lý liệu xâu - Trong ngôn ngữ lập trình C hàm xử lý xâu định nghĩa thư viện string.h a) Các hàm chuyển đổi kiểu chữ, chuyển đổi thứ tự - Chuyển ký tự thành chữ thường Cú pháp: char *strlwr(char *s); Trong đó: s xâu đầu vào, hàm chuyển ký tự xâu s thành chữ thường Giá trị trả hàm trỏ chứa xâu chuyển thành chữ thường - Chuyển ký tự thành chữ hoa Cú pháp: char *strupr(char *s); Trong đó: Tham số s xâu đầu vào, hàm chuyển ký tự xâu s thành chữ hoa Giá trị trả hàm trỏ chứa xâu chuyển thành chữ hoa - Đảo ký tự xâu Cú pháp: char *strrev(char *s); Trong đó: Tham số s xâu đầu vào, hàm đảo ngược thứ tự xuất ký tự Giá trị trả hàm trỏ đến xâu đảo ngược - Ví dụ 2.9: Hàm chuyển đổi ký tự #include #include #include int main(void) { char a[]="Chuyen Thanh Chu Hoa"; char b[]="Chuyen Thanh Chu Thuong"; char c[]="Dao nguoc thu tu"; strupr(a); strlwr(b); strrev(c); puts(a); puts(b); puts(c); getch(); getch(); return 0; } b) Hàm xác định chiều dài xâu - Xác định chiều dài xâu văn Chiều dài xâu văn kết thúc ký tự có mã - Cú pháp: size_t strlen(const char *s); - Trong đó: - Tham số s xâu cần kiểm tra độ dài - Giá trị trả hàm độ dài xâu c) Hàm chép, ghép xâu - Sao chép xâu Cú pháp: char *strcpy(char *dest, const char *src); Trong đó: Tham số dest địa xâu nhận giá trị chép Tham số src địa xâu nguồn chép Giá trị trả hàm trỏ xâu chép Hàm strcpy tiến hành chép ký tự từ xâu src sang xâu dest đến gặp ký tự có mã (ký tự kết thúc xâu) Hàm chép ký tự kết thúc xâu - Nối xâu Cú pháp: char *strcat(char *dest, const char *src); Trong đó: Tham số dest xâu cộng thêm xâu src vào cuối Tham số src xâu cộng thêm vào xâu dest Giá trị trả hàm trỏ đến vùng nhớ xâu cộng vào Hàm strcat thực nối xâu src vào xâu dest - Tạo xâu Cú pháp: char *strdup(const char *s); Trong đó: Tham số s xâu tạo Giá trị trả hàm trỏ trỏ đến vùng nhớ cấp phát để lưu trữ xâu Hàm strdup thực việc cấp pháp vùng nhớ có độ lớn độ dài xâu, tiến hành sang vùng Vì hàm cấp phát nhớ nên sau sử dụng phải sử dụng hàm free() để giải phóng vùng nhớ - Chú ý: Các hàm strcpy(), strcat() không giới hạn số lượng ký tự đưa vào xâu dest trường hợp xâu src lớn tạo tượng tràn đệm (vùng nhớ lưu trữ không đủ) trường hợp không giới hạn xâu đầu vào nên sử dụng hàm strncpy(), strncat() thay - Ví dụ 2.10: Copy nối xâu #include #include #include int main(void) { char t[100]; char a[10]; char b[20]= "Thu"; 10 char c[10]= "123456789"; char d[]="Chuoi dai hon vung dem"; strcpy(a,b); puts(a); strcat(b,c); puts(b); strncpy(a,d,10); a[9]=0; puts(a); strncat(b,d,20); b[19]=0; puts(b); //loi tran bo dem printf("\nLoi\n"); strcpy(a,d); strcat(b,d); puts(a); puts(b); getch(); return 0; } d) Hàm so sánh hai xâu phân biệt chữ hoa chữ thường - Cú pháp: int strcmp(const char *s1, const char*s2); - Trong đó: - Tham số s1 xâu cần so sánh thứ - Tham số s2 xâu cần so sánh thứ hai - Giá trị trả hàm bé xâu s1 bé xâu s2, xâu s1 xâu s2, lớn xâu s1 lớn xâu s2 - Hàm so sánh từ trái sang phải theo mã ký tự Hai xâu xâu có độ dài nhau, giá trị giống Nếu từ trái sang phải gặp ký tự khác ký tự thuộc xâu s1 có mã lớn ký tự từ xâu s2 chuối s1 lớn xâu s2 ngược lại - Ví dụ 2.11: So sánh xâu char a[]="xin chao"; char b[]="xin chao"; char c[]="xin don mung cac ban"; int i1, i2; i1=strcmp(a,b); i2=strcmp(a,c); - Sau thực hiện: i1 có giá trị (xâu a bàng xâu b), i2 có giá trị bé (xâu a bé xâu c - xét từ trái sang đến ký tự thứ ký tự 'd' có mã lớn ký tự 'c' nên xâu c lớn xâu a) - Ngoài ra, để so sánh hai xâu không phân biệt chữ hoa, chữ thường sử dụng cú pháp sau - Cú pháp: int stricmp(const char *s1, const char *s2); - Hàm giống hàm strcmp so sánh không biệt chữ hoa 11 chữ thường có nghĩa hai ký tự 'A' 'a' thứ tự so sánh e) Hàm tìm xuất ký tự xâu - Cú pháp: char *strchr(const char *s, int c); - Trong đó: - Tham số s xâu tìm kiếm ký tự - Tham số c ký tự cần tìm kiếm - Nếu xuất ký tự cần tìm kiếm (tính từ trái qua) hàm trả trỏ trỏ đến vị trí ký tự xuất đầu tiên; không xuất ký tự cần tìm kiếm trỏ trỏ đến NULL - Ngoài ra, để tìm ký tự xuất bên phải sử dụng cú pháp sau - Cú pháp: char *strrchr(const char *s, int c); - Hàm làm việc tương tự hàm strchr() hướng tìm kiếm từ phải sang f) Tìm kiếm xâu xuất xâu khác - Cú pháp: char *strstr(const char *s1, const char *s2); - Trong đó: - Tham số s1 xâu tìm kiếm - Tham số s2 xâu cần tìm kiếm xâu s1 - Nếu tìm thấy xuất xâu s2 xâu s1 hàm trả trỏ trỏ đến ký tự xuất xâu con; ngược lại trả lại giá trị NULL g) Các hàm biến đổi kiểu xâu thành số - Chuyển xâu thành số nguyên - Cú pháp: int atoi(const char *s); long atol(const char *s); - Trong đó: - Tham số s xâu có định dạng kiểu số - Giá trị trả hàm số tương ứng với xâu Nếu hàm atoi() trả kiểu int, atol() trả kiểu long Nếu lỗi trả lại giá trị - Chuyển đổi xâu thành số thực - Cú pháp: double atof(const char *s); - Trong đó: - Tham số s xâu có định dạng kiểu số - Giá trị trả hàm số Nếu có lỗi trả lại giá trị 2.2.3 Một số ví dụ Loại bỏ ký tự trắng (spacebar) cạnh nhau, đầu xâu, cuối xâu - Bài toán: Cho xâu đoạn văn loại bỏ dấu cách cạnh (nếu có nhiếu dấu cách cạnh để lại dấu cách), loại bỏ dấu cách đầu, cuối văn - Ý tưởng: Tìm ký tự khác ký tự trắng st Tìm vị trí cuối xâu khác ký tự trắng en Chuyển ký tự từ khoảng st đến en sang xâu ký tự không đồng thời ký tự trắng ký tự trước ký tự trắng Thuật toán: Dữ liệu vào: Xâu cần loại bỏ ký tự trắng dư thừa Dữ liệu ra: Xâu loại bỏ ký tự trắng 12 len=strlen(s); st=0; en=len-1; while(stst && s[en]==' ') en ; mo=1; s[0]=s[st]; for(i=st+1 -> en) if(!(s[i]==' ' && s[i-1]==' ')) { s[mo]=s[i]; mo++; } s[mo]=0; - Cài đặt chương trình: #include #include #include int main(void) { char s[]=" chuoi co du nhieu dau trang "; int st=0, len, en, mo=1,i; len=strlen(s); en=len; while(stst && s[en]==' ') en ; s[0]=s[st]; for(i=st+1;i N) if(s[i-1]==' ') s[i]=toupper(s[i]); - Cài đặt chương trình: #include #include #include #include int main(void) { char s[]="nguyen LAN ANH"; int i; strlwr(s); s[0]=toupper(s[0]); for(i=1;icml) { i1=0; i2=0; 14 if(i