PHẦN 1Các yêu cầu: - Chuẩn hoá chuỗi - Trích xuất chuỗi - Tìm kiếm, thay thế chuỗi - Chuỗi đảo ngược - Chuỗi đối xứng - Bài tập xử lý chuỗi - Bài toán ứng dụng : Cộng hai số lớn - Kiểm t
Trang 1BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƯỜNG ĐẠI HỌC PHÚ YÊN
ĐỒ ÁN MÔN HỌC 1
Họ và tên sinh viên: Ngô Thành Đạt
Mã sinh viên: 211CTT025
Lớp: DC21CTT01
Phú Yên , 7/2023
Trang 2PHẦN 1
Các yêu cầu:
- Chuẩn hoá chuỗi
- Trích xuất chuỗi
- Tìm kiếm, thay thế chuỗi
- Chuỗi đảo ngược
- Chuỗi đối xứng
- Bài tập xử lý chuỗi
- Bài toán ứng dụng : Cộng hai số lớn
- Kiểm tra biểu thức hợp lệ
Phân tích và cài đặt bài toán:
1 Chuẩn hoá chuỗi
- Input : Một chuỗi ký tự cần được chuẩn hoá (chuỗi bị thừa dấu cách hoặc dấu
tab ở đầu dòng, giữa dòng, cuối dòng)
Ví dụ input bài toán: " Đây là một ví dụ input ";
- Output: Chuỗi ký tự đưa vào đã được chuẩn hoá
Ví dụ output bài toán: "Đây là một ví dụ input"
- Cài đặt thuật toán bằng ngôn ngữ lập trình C
void chuanHoaChuoichar* chuoi) {
int n = strlen(chuoi);
int i = 0;
// Xoa dau cach dau
Trang 3while (chuoi[i] == ' ' && i < n) { for (int j = 0; j < n - 1; j++) { chuoi[j] = chuoi[j + 1];
}
chuoi[n - 1] = '\0';
n ;
}
// Xoa dau cach cuoi
i = n - 1;
while (i >= 0 && chuoi[i] == ' ') { chuoi[i] = '\0';
i ;
}
int j;
int demDauCach = 0;
i = 0;
// Xoa dau cach o giua
while (i < n) {
if (chuoi[i] == ' ') {
demDauCach++;
if (demDauCach > 1) {
for (j = i; j < n - 1; j++) { chuoi[j] = chuoi[j + 1];
}
Trang 4chuoi[n - 1] = '\0';
n ;
i ;
}
} else {
demDauCach = 0;
}
i++;
}
}
- Độ phức tạp của giải thuật :
Độ phức tạp của thuật toán là O(n), trong đó n là độ dài của chuỗi đầu vào
2 Trích xuất chuỗi
- Input: Cần đưa vào bài toán một chuỗi nguồn đề trích xuất , vị trí bắt đầu trích
xuất từ chuỗi nguồn và vị trí kết thúc
- Output: Nhận được chuỗi địch cần trích xuất từ chuỗi nguồn từ vị trí bắt đầu
đến vị tri kết thúc
- Cài đặt thuật toán bằng ngôn ngữ lập trình C
void trichXuatChuoi(char* chuoiDich, const char* chuoiNguon, int start, int end) {
int i, j = 0;
// Đảm bảo vị trí bắt đầu hợp lệ
if (start < 0) {
start = 0;
}
Trang 5// Xác định vị trí kết thúc hợp lệ
int doDaiChuoiNguon = strlen(source);
if (end >= sourceLength) {
end = sourceLength - 1;
}
if (end < start) {
end = start;
}
for (i = start; i <= end; i++) {
chuoiDich[j] = chuoiNguon[i];
j++;
}
// Kết thúc chuỗi đích bằng '\0'
chuoiDich[j] = '\0';
}
- Độ phức tạp của giải thuật :
Độ phức tạp của giải thuật trichXuatChuoi như trên là O(n), trong đó n là độ dài của phần trích xuất (end - start) Điều này bởi vì giải thuật chỉ duyệt qua các
ký tự từ start đến end của chuỗi nguồn một lần, không phụ thuộc vào độ dài tổng của chuỗi nguồn
3 Tìm kiếm , thay thế chuỗi
- Input: Đưa vào một chuỗi cha, một chuỗi con để tìm kiếm bên trong chuỗi cha,
một chuỗi thay thế chuỗi con
Trang 6- Output: Chuỗi mới thay thế chuỗi con bên trong chuỗi cha nếu như tìm thấy
chuỗi con trong chuỗi cha
- Cài đặt thuật toán bằng ngôn ngữ lập trình C
#include <stdio.h>
#include <string.h>
int TimViTriChuoi(const char* chuoiCha, const char* chuoiCon) {
int doDaiChuoiCha = strlen(chuoiCha);
int doDaiChuoiCon = strlen(chuoiCon);
for (int i = 0; i <= doDaiChuoiCha - doDaiChuoiCon; i++) {
int viTriChuoiCon = 0;
int timThay = 1;
for (int j = i; j < i + doDaiChuoiCon; j++) {
if (chuoiCha[j] != chuoiCon[viTriChuoiCon]) {
timThay = 0;
break;
}
viTriChuoiCon++;
}
if (timThay) {
return i;
}
}
return -1;
}
Trang 7void ThayTheChuoi(char* chuoiCha, const char* chuoiCon, const char* chuoiMoi) {
int viTriTimThay;
while ((viTriTimThay = TimViTriChuoi(chuoiCha, chuoiCon)) != -1) {
int doDaiChuoiCon = strlen(chuoiCon);
int doDaiChuoiMoi = strlen(chuoiMoi);
for (int i = viTriTimThay; i < viTriTimThay + doDaiChuoiMoi; i++) { chuoiCha[i] = chuoiMoi[i - viTriTimThay];
}
for (int k = viTriTimThay + doDaiChuoiMoi; k < strlen(chuoiCha); k++) { chuoiCha[k] = chuoiCha[k + doDaiChuoiCon - doDaiChuoiMoi]; }
}
}
int main() {
char chuoiCha[] = "Xin chao, dat, Xin chao Co";
char chuoiCon[] = "Xin chao";
char chuoiMoi[50];
printf("Nhap chuoi moi: ");
Trang 8scanf("%s", chuoiMoi);
ThayTheChuoi(chuoiCha, chuoiCon, chuoiMoi);
printf("Chuoi sau khi thay the: %s\n", chuoiCha);
return 0;
}
- Đánh giá độ phức tạp của thuật toán
Hàm TimViTriChuoi:
Vòng lặp ngoài cùng chạy từ 0 đến doDaiChuoiCha - doDaiChuoiCon, có thể chạy tối đa doDaiChuoiCha - doDaiChuoiCon + 1 lần
Trong vòng lặp ngoài cùng, chúng ta có một vòng lặp bên trong chạy từ 0 đến doDaiChuoiCon, có thể chạy tối đa doDaiChuoiCon lần
Do đó, độ phức tạp của TimViTriChuoi là O((doDaiChuoiCha -
doDaiChuoiCon + 1) * doDaiChuoiCon) = O(doDaiChuoiCha *
doDaiChuoiCon)
Hàm ThayTheChuoi:
Trong trường hợp tồi nhất, nếu phải thay thế tất cả các xuất hiện của chuỗi con trong chuỗi cha, thì ThayTheChuoi có thể chạy nhiều lần tương ứng với số lần xuất hiện của chuỗi con
Mỗi lần thay thế, chúng ta cần dời các ký tự sau chuỗi mới để làm cho độ dài của chuỗi cha không thay đổi
Vì vậy, độ phức tạp của ThayTheChuoi có thể ước tính là O(số lần xuất hiện của chuỗi con * (doDaiChuoiCha - doDaiChuoiMoi))
Trang 94 Chuỗi đảo ngược
- Input: Một chuỗi ký tự được đưa vào
- Output: Đảo ngược chuỗi được đưa vào
Ví dụ: chuỗi đưa vào là: ngo thanh dat
Chuỗi đảo ngược sẽ là: tad hnaht ogn
- Cài đặt thuật toán bằng ngôn ngữ lập trình C:
void daoNguocChuoi(char* chuoi){
int doDaiChuoi = strlen(chuoi);
char temp;
int i,j;
for(i=0 , j = doDaiChuoi -1 ;i<j;i++,j ){
temp = chuoi[i];
chuoi[i] = chuoi[j];
chuoi[j] = temp ;
}
}
- Đánh giá độ phức tạp của thuật toán:
Vòng lặp trong hàm chạy từ đầu chuỗi (i = 0) đến giữa chuỗi (i < doDaiChuoi / 2) và thực hiện hoán đổi ký tự tương ứng ở cả hai đầu Vì vậy, số lần lặp của vòng lặp là doDaiChuoi / 2
Do đó, độ phức tạp của thuật toán đảo ngược chuỗi này có thể xem như là O(doDaiChuoi/2), nhưng trong tính toán độ phức tạp thường bỏ đi hằng số, vì vậy độ phức tạp cuối cùng của hàm này là O(doDaiChuoi)
5 Chuỗi đối xứng
- Input: Một chuỗi ký tự được đưa vào
- Output: Kiểm tra và thông báo chuỗi vừa đưa vào có phải là chuỗi đối xứng
hay không
Trang 10- Cài đặt thuật toán bằng ngôn ngữ lập trình C:
int kiemTraChuoiDoiXung(char* chuoi){
int doDaiChuoi = strlen(chuoi);
char temp;
int i,j;
for(i=0 , j = doDaiChuoi -1 ;i<j;i++,j ){
if(chuoi[i]!=chuoi[j]){
return 0 ; }
}
return 1 ;
}
- Đánh giá độ phức tạp của thuật toán:
Độ phức tạp của thuật toán là O(doDaiChuoi)
6 Câu I 6đ Viết các hàm xử lý thực hiện yêu cầu sau
Cho chuỗi s chứa các thông tin một giao dịch bao gồm: mã, ngày, giờ và giá trị
đi kèm
Vidu: s=“ 1 15-09-2023 07:30:45 9.99”
Khoảng cách trống ở giữa các thành phần có thể là kí tự space hoặc tab
1 Viết hàm thay thế ký tự nào đó trong chuỗi trong chuỗi thành kí tự khác (1đ)
Áp dụng:
- Thay các kí tự tab ‘\t” thành kí tự space
- Thay kí tư nối ngày ‘-‘ thành kí tự ‘/’
2 Xóa 1 ký tự ở vị trí bất kỳ trong chuỗi (2đ)
Áp dụng:
- Xóa các ký tự trắng đầu và cuối chuỗi
- Xóa các ký tự trắng thừa bên trong chuỗi (giữa 2 từ chỉ có một khoảng trắng)
Trang 113 Tách các thành phần dữ liệu trong chuỗi được cách nhau bởi ký tự trắng vào các chuỗi riêng biệt, in ra màn hình theo mẫu: (2đ)
Ví dụ:
- Mã: 1
- Ngày 15 tháng 9 năm 2023
- 7 giờ 30 phút 45 giây - Giá trị nhận được: 9.99
Câu II Chuẩn hóa file (4đ)
Cho file text datal.txt, mỗi dòng chứa các thông tin như đã nêu ở câu 1
1 10-09-2023 07:30:45 9.99
2 15/09/2023 09:20:15 6.56
1 Áp dụng các hàm đã cho để xử lý các dòng trong datal.txt và xuất ra file data2 txt có dạng sau:
1;10-09-2023; 07:30:45:9.99
2;15/09/2023:09:20:15;6.56
2 Khai báo mảng cấu trúc, mỗi phần tử của mảng có kiểu cấu trúc bao gồm các thông tin mã, ngày, giờ và giá trị nhận được Đọc từ file data2.txt ra mảng, tính giá trị nhận được lớn nhất, nhỏ nhất và giá trị trung bình
- Input: Chuỗi ký tự đưa vào bao gồm các thành phần mã, ngày, giờ và giá trị
đi kèm , chuỗi chưa được chuẩn hoá nên thừa khoảng trắng
- Output:
Câu 1.1 và 1.2: Chuẩn hoá chuỗi được đưa vào, thay thế kí tự tab ‘\t” thành kí
tự space , kí tự nối ngày ‘-‘ thành kí tự ‘/’ và xoá các khoảng trắn dư thừa ở đầu, giữa, cuỗi chuỗi
Câu 1.3 Tách các thành phần trong chuỗi được ngăn cách nhau bởi dấu khoảng trắng, sau đó in ra màn hình theo mẫu
Trang 12Câu 2.1: Xử lý chuỗi đưa vào về định dạng
1;10-09-2023; 07:30:45:9.99
2;15/09/2023:09:20:15;6.56
Sau đó đưa vào file
Câu 2.2 Đọc từ file data2.txt ra mảng cấu trúc mã, ngày, giờ và giá trị nhận được , xuất ra giá trị nhận được lớn nhất, nhỏ nhất và giá trị trung bình
- Cài đặt thuật toán bằng ngôn ngữ lập trình C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Date {
int d;
int m;
int y;
} Date;
typedef struct Time {
int hour;
int minute;
int second;
} Time;
typedef struct data {
int id;
Date date;
Time time;
Trang 13float diem;
} data;
void replaceTabsWithSpaces(char *str) { for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == '\t') {
str[i] = ' ';
}
}
}
void removeExtraSpaces(char *str) { int len = strlen(str);
int i, j;
while (len > 0 && str[0] == ' ') { memmove(str, str + 1, len); len ;
}
while (len > 0 && str[len - 1] == ' ') { len ;
str[len] = '\0';
}
Trang 14
for (i = 0, j = 0; i < len; i++) {
if (str[i] != ' ' || (i > 0 && str[i - 1] != ' ')) { str[j] = str[i];
j++;
}
}
str[j] = '\0';
}
int demSoPhanTuTrongFile( char *filename) { FILE *file = fopen(filename, "r");
if (file == NULL) {
printf("Khong the mo tap tin");
return -1;
}
int count = 0;
char line[256];
while (fgets(line, sizeof(line), file)) { count++;
}
fclose(file);
return count;
Trang 15int main() {
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
printf("Khong the mo tap tin");
return 1;
}
data data[10];
int length = demSoPhanTuTrongFile("data.txt"); char line[256];
int i=0;
while (fgets(line, sizeof(line), file)) {
replaceTabsWithSpaces(line);
removeExtraSpaces(line);
char *token = strtok(line, " ");
if (token != NULL) {
data[i].id = atoi(token);
token = strtok(NULL, " ");
char StringDate[20];
strcpy(StringDate,token);
Trang 16
token = strtok(NULL, " "); char StringTime[20]; strcpy(StringTime,token);
token = strtok(NULL, " "); data[i].diem = atof(token);
if (StringDate != NULL) { char *dateToken = strtok(StringDate, "/"); if (dateToken != NULL) { data[i].date.d = atoi(dateToken); dateToken = strtok(NULL, "/"); if (dateToken != NULL) { data[i].date.m = atoi(dateToken); dateToken = strtok(NULL, " "); if (dateToken != NULL) { data[i].date.y = atoi(dateToken); }
}
}
}
if (StringTime != NULL) {
Trang 17
char *timeToken = strtok(StringTime, ":"); if (timeToken != NULL) { data[i].time.hour = atoi(timeToken); timeToken = strtok(NULL, ":"); if (timeToken != NULL) { data[i].time.minute = atoi(timeToken); timeToken = strtok(NULL, " "); if (timeToken != NULL) { data[i].time.second = atoi(timeToken); }
printf("ID: %d\n", data[i].id); printf("Date: %d/%d/%d\n", data[i].date.d, data[i].date.m, data[i].date.y); printf("Time: %d:%d:%d\n", data[i].time.hour, data[i].time.minute, data[i].time.second); printf("Diem: %.2f\n", data[i].diem); printf(" -\n");
}
}
}
Trang 18i++;
}
float minValue = data[0].diem;
float maxValue = data[0].diem ;
float sumValue = 0;
for(int i=0 ;i<length ; i++){
sumValue += data[i].diem;
if(minValue>data[i].diem){
minValue = data[i].diem;
}
if(maxValue < data[i].diem){
maxValue = data[i].diem;
}
}
float giaTriTrungBinh = sumValue/length ;
printf("\nGia tri nho nhat la: %.2f",minValue); printf("\nGia tri lon nhat la: %.2f",maxValue); printf("\nGia tri trung binh la: %.2f",giaTriTrungBinh);
fclose(file);
FILE *file2 = fopen("data1.txt", "r");
if (file2 == NULL) {
perror("Khong the mo tep tin");
Trang 19return 1;
}
FILE *outputFile = fopen("data2.txt", "w");
if (outputFile == NULL) {
perror("Không th? t?o ho?c m? t?p tin data2.txt");
fclose(file2);
return 1;
}
char line2[256];
while (fgets(line2, sizeof(line2), file2)) {
replaceTabsWithSpaces(line2);
removeExtraSpaces(line2);
for (int i = 0; line2[i] != '\0'; i++) {
if (line2[i] == ' ') {
line2[i] = ';';
}
}
fprintf(outputFile, "%s\n", line2);
}
printf("\nDA CHUAN HOA CHUOI VAO FILE DATA2.TXT!"); fclose(file2);
fclose(outputFile);
return 0;
}
- Đánh giá độ phức tạp của thuật toán:
Trang 20Độ phức tạp của hàm demSoPhanTuTrongFile là O(n), trong đó n là số dòng trong tệp tin đầu vào "data.txt"
Vòng lặp trong while (fgets(line, sizeof(line), file)) chạy theo số dòng trong tệp tin, nên có độ phức tạp là O(n)