Câu 1 : Viết chương trình gồm: Hàm nhập vào số thực x và số nguyên dương n. Hàm tính giá trị biểu thức:
Trang 1TRƯỜNG ĐẠI HỌC CÔNG NGHIỆP HÀ NỘI
KHOA CÔNG NGHỆ THÔNG TIN
BÀI TẬP NHÓM
KỸ THUẬT LẬP TRÌNH
-Giáo viên hướng dẫn: Ths Mai Thanh Hồng Nhóm số : 2
Lớp: 20191IT6015003
Hà Nội, 2019
Trang 2TRƯỜNG ĐẠI HỌC CÔNG NGHIỆP HÀ NỘI
KHOA CÔNG NGHỆ THÔNG TIN
BÀI TẬP NHÓM
KỸ THUẬT LẬP TRÌNH
- - - - - -
Giáo viên hướng dẫn: Ths Mai Thanh Hồng Lớp: 20191IT6015003
Nhóm số 2:
1 Nguyễn Thị Ngọc Ánh
2 Phan Văn Chính
3 Bạch Quốc Đông
4 Phạm Thanh Nam
5 Nguyễn Đức Phong
6 Trần Thanh Phong
7 Hà Quốc Tuấn
Hà Nội, 2019
Trang 3Lời nói đầu
Ngôn ngữ C/C++ là ngôn ngữ lập trình phổ biến trên thế giới được nhiều lập trình viên lựa chọn Để củng cố kiến thức về bộ môn Kỹ Thuật Lập Trình (KTLT) nhóm 2 xin đưa ra hướng giải 3 bài tập cơ bản của bộ môn bằng ngôn ngữ C++
Khác với các cách giải khác, các bài tập dưới đây đều có hướng dẫn giải chi tiết Khi hướng dẫn giải bài tập, chúng tôi cố gắng:
✓ Thể hiện một góc nhìn riêng về kỹ thuật lập trình bằng ngôn ngữ C++, chú ý đến những đặc điểm của ngôn ngữ C++ Nói cách khác, chúng tôi chú ý đến lập trình theo phong cách của C++
✓ Phân tích quá trình tư duy khi giải quyết vấn đề, củng cố các kiến thức toán học cũng như lập trình cơ bản, nhằm làm nổi bật vai trò của ngôn ngữ lập trình như một công cụ hỗ trợ mang tính thực tế cao
✓ Lập trình thật ngắn gọn và rõ ràng giúp người đọc hiểu rõ vấn đề Nâng cao
kỹ năng lập trình Người đọc sẽ thấy thú vị và bất ngờ với một số kỹ thuật giải quyết vấn đề
Ở đây, nhóm sẽ giải 3 bài tập cơ bản sau:
1 Bài tập về tính giá trị biểu thức cơ bản
2 Bài tập về mảng và xử lý các phần tử của mảng
3 Bài tập về chuỗi ký tự
Nhóm tin rằng tập sách này sẽ giúp người đọc thật sự củng cố và nâng cao kiến thức lập trình với ngôn ngữ C++ Xin chân thành cảm ơn cô Mai Thanh Hồng
đã giúp chúng em hoàn thành các bài tập này
Phương pháp giải cũng như diễn đạt có thể gặp nhiều thiếu sót và hạn chế Nhóm thật sự mong nhận được các ý kiến góp ý từ thầy cô và bạn đọc để có thể hoàn thiện hơn
Trang 4Bài Tập Nhóm KTLT
Câu 1 : Viết chương trình gồm:
- Hàm nhập vào số thực x và số nguyên dương n
- Hàm tính giá trị biểu thức:
𝑆 = {√2019 + 2𝑥 + 4𝑥2+ ⋯ + 2𝑛𝑥𝑛 khi n > 2
|nx| khi n ≤ 2
- Hàm main() sử dụng các hàm trên để nhập vào số thực x, số nguyên dương n, tính
và hiển thị ra màn hình giá trị biểu thức S
Input : x = 5.5, n = 4
5.5
4
Output : S = 8495.68
𝑆 = √2019 + 2 ∗ 5.5 + 4 ∗ 5.5 2 + 6
∗ 5.5 3 + 8 ∗ 5.5 4 Giải:
# include <iostream>
# include <math.h>
using namespace std ;
void InputNumberXN ( double *x, int *n)
{
cout<<"Nhap vao so thuc: ";
cin>>*x;
cout<<"Nhap vao so nguyen duong: ";
cin>>*n;
}
double CalS ( double x, int n)
{
double ValueS = 0 ;
if (n> 2 )
{
ValueS += sqrt ( 2019 );
for ( int i = 1 ; i <= n; ++i)
ValueS += 2 *i* pow (x,i);
}
else if (n<= 2 )
{
ValueS = fabs (n*x);
}
return ValueS;
}
int main ( int argc, char const *argv[])
{
int n; double x;
InputNumberXN (&x,&n);
cout<<"Gia tri S = "<< CalS (x,n)<<endl;
return ;
}
Trang 5Để nhập giá trị cho số thực x và số nguyên dương n, ở đây ta sẽ viết một hàm
và sử dụng con trỏ để truyền 2 tham số cho hàm Trong hàm thì *x , *n là giá trị của biến, còn x,n sẽ là địa chỉ biến trong bộ nhớ
void InputNumberXN ( double *x, int *n)
{
cout<<"Nhap vao so thuc: ";
cin>>*x;
cout<<"Nhap vao so nguyen duong: ";
cin>>*n;
}
Khi truyền tham số cho hàm thì địa chỉ của biến được truyền vào hàm,bản chất của việc truyền tham số trong trường hợp này cũng như truyền tham chiếu
void InputNumberXN ( double &x, int &n)
{
cout<<"Nhap vao so thuc: ";
cin>>x;
cout<<"Nhap vao so nguyen duong: ";
cin>>n;
}
Trong trường hợp sử dụng con trỏ để truyền tham số cho hàm, khi khai báo tham
số, thêm dấu * vào trước tham số
Khi truyền tham số phải truyền vào địa chỉ của một biến cùng kiểu, con trỏ cùng kiểu, hoặc mảng cùng kiểu
int main ()
{
int n;
double x;
InputNumberXN (&x,&n);
return ;
}
Để tính giá trị biểu thức :
𝑆 = {√2019 + 2𝑥 + 4𝑥2+ ⋯ + 2𝑛𝑥𝑛 khi n > 2
|nx| khi n ≤ 2
Ta thấy sẽ có 2 trường hợp xảy ra:
- Nếu n > 2:
Tạm thời loại bỏ √2019 vì không có quy luật với các thành phần còn lại Ta thấy công thức cho vế đằng sau sẽ là: 𝑆𝑖 = 2𝑖𝑥𝑖, 𝑖 = 1 𝑛 Như vậy, ta cần thực hiện một vòng lặp với biến đếm i chạy từ 1 đến n Biểu thức trong thân vòng lặp:
Trang 6𝑆𝑖 = 2𝑖𝑥𝑖 = 2 ∗ 𝑖 ∗ 𝑝𝑜𝑤(𝑥, 𝑖) Khi này 𝑆 = √2019 + 𝑆𝑘 = 𝑠𝑞𝑟𝑡(2019) + 𝑆𝑘
- Nếu n ≤ 2:
𝑆 = |nx| = 𝑓𝑎𝑏𝑠(𝑛 ∗ 𝑥)
Trong đó pow, sqrt, fabs là các hàm toán học trong thư viện <math.h> Ở đây, ta chỉ cần truyền tham trị cho hàm
double CalS ( double x, int n)
{
double ValueS = 0 ; // Khai báo giá trị ban đầu của S bằng 0 nếu không kết quả
sẽ có thể không đúng
if (n> 2 )
{
ValueS += sqrt ( 2019 );
for ( int i = 1 ; i <= n; ++i) {
ValueS += 2 *i* pow (x,i);
} }
else if (n<= 2 )
{
ValueS = fabs (n*x);
}
return ValueS;
}
Trang 7Câu 2 : Viết chương trình theo các yêu cầu dưới đây:
- Nhập số nguyên dương n (n ≥ 5) và mảng a gồm n số thực (mảng a được cấp phát bộ nhớ động)
- Hiển thị ra màn hình các số thuộc đoạn [-5, 5] có trong mảng a, tổng và trung bình cộng của chúng Thông báo trường hợp mảng không có phần tử nào thỏa mãn điều kiện
- Nhập vào số nguyên có giá trị x rồi chèn x vào trước phần tử có giá trị là số chính phương đầu tiên trong mảng a, hiển thị kết quả (nếu mảng a không có
số chính phương thì thông báo)
- Xóa tất cả các số chẵn trong mảng
- Sao chép tất cả các số âm trong mảng a về đầu mảng, hiển thị lại mảng a Giải:
Input
9
1 2 3 -5 6 8 9 7 -4
99
Output
1 2 3 -5 -4 , Tổng = -3 TBC = -0.6 Chèn x=99: 1 2 3 -5 6 8 99 9 7 -4 Xóa số chẵn:1 3 -5 8 99 9 7 Copy số âm về đầu: -5 1 3 -5 8 99 9 7
# include <iostream>
# include <conio.h>
# include <math.h>
using namespace std ;
void Input ( int *n, double *a )
{
do {
cout<<"Nhap so nguyen duong n? ";
cin>>*n;
if (*n< 5 )
cout<<"Nhap lai!"<<endl;
} while (*n< 5 );
cout<<"Nhap "<<*n<<" so thuc trong mang a: "<<endl;
for ( int i = 0 ; i < *n; ++i)
cin>>*(a+i);
}
void OutPutArray ( int n, double *a)
{
for ( int i = 0 ; i < n; ++i)
cout<<*(a+i)<<" ";
cout<<endl;
}
Trang 8void FindNumberIn55 ( int n, double *a)
{
double SumNumberIn55= 0 ;
int countIn55= 0 ;
cout<<"Tim cac phan tu trong mang thuoc doan [-5,5]: "<<endl;
for ( int i = 0 ; i < n; ++i)
{
if (*(a+i) >= - 5 && *(a+i) <= 5 ) {
SumNumberIn55 += *(a+i);
countIn55++;
cout<<*(a+i)<<" ";
} }
if (countIn55 == 0 )
cout<<"Khong co phan tu nao trong mang thuoc doan [-5,5]!"<<endl;
else
cout<<endl<<"Tong cac so tren la: "<<SumNumberIn55<<", va TBC la:
"<<SumNumberIn55/countIn55<<endl;
}
bool isSquareNumber ( double x)
{
if (x> 3 )
{
if (( int ) sqrt (x) * ( int ) sqrt (x) == x)
return true ;
else
return false ; } else {
return false ; }
}
void InsertX ( int *n, double *a)
{
cout<<endl<<"Chen x vao truoc so chinh phuong"<<endl;
int x;
cout<<"Nhap vao so nguyen x? ";
cin>>x;
int haveSquareNumb = 0 ;
for ( int i = 0 ; i < *n; ++i)
{
if ( isSquareNumber (*(a+i))) {
for ( int j = *n; j >= i; j )
*(a+j) = *(a+j- 1 );
(*n)++;
*(a+i)=x;
haveSquareNumb = 1 ;
break ; }
}
if (haveSquareNumb)
{
// In mang ra
Trang 9OutPutArray (*n,a);
} else {
cout<<"Mang khong co chua bat ky phan tu nao la so chinh phuong!"; }
}
void deleteEvenNumber ( int *n, double *a)
{
cout<<"Xoa tat ca cac so chan trong mang:"<<endl;
for ( int i = 0 ; i < *n; ++i)
{
if (*(a+i) == ( int ) *(a+i) && ( int )*(a+i)% 2 == 0 ) {
for ( int j = i; j < *n- 1 ; ++j) {
*(a+j) = *(a+j+ 1 );
} (*n) ;
} }
OutPutArray (*n,a);
}
void copyNegativeNumber ( int *n, double *a)
{
cout<<"Sao chep tat ca cac so am ve dau mang:"<<endl;
int stt = 0 ;
for ( int i = 0 ; i < *n; ++i)
{
if (*(a+i)< 0 ) {
double temp = *(a+i);
for ( int j = *n; j > stt; j )
*(a+j) = *(a+j- 1 );
*(a+stt)=temp;
(*n)++;
i++;
stt++;
} }
OutPutArray (*n,a);
}
int main ( int argc, char const *argv[])
{
int n;
double *a = new double [ 100 ];
Input (&n,a);
FindNumberIn55 (n, a);
InsertX (&n, a);
deleteEvenNumber (&n, a);
copyNegativeNumber (&n, a);
return ;
}
Trang 10Để cấp phát động bộ nhớ cho mảng a ta dùng đoạn mã sau:
int main ()
{
double *a = new double [ 100 ];
}
Sau khi được cấp phát bộ nhớ động, mảng có thể được sử dungjnhuw mảng được cấp phát tĩnh
Ở hàm nhập ta sẽ sử dụng con trỏ để truyền tham số cho hàm Như đã giải thích ở bài tập 1, việc truyền tham số bằng con trỏ giống như việc dung tham chiếu giúp thay đổi được giá trị của biến trên hàm main()
void Input ( int *n, double *a )
Để giới hạn được giá trị của n thỏa mãn n ≥ 5 ta dùng vòng lặp do while để kiểm tra điều kiện nhập, nếu giá trị của n không hợp lệ ( tức n<5 ) thì yêu cầu
người dùng nhập lại
do {
cout<<"Nhap so nguyen duong n? ";
cin>>*n;
if (*n< 5 )
cout<<"Nhap lai!"<<endl;
} while (*n< 5 );
Để nhập mảng gồm n phần tử, ta nhập từng phần tử một rồi gán giá trị đó vào vị trí đang duyệt của mảng
for ( int i = 0 ; i < *n; ++i)
cin>>*(a+i);
Ở đây ta dung con trỏ để duyệt mảng một chiều Như bình thường ta sẽ có int a[100]; là một mảng a gồm 100 phầm tử bắt đầu từ a[0] Khi đó a là một con trỏ trỏ đến phần tử đầu tiên của mảng là &a[0] hoặc đơn giản là a Tức là khi này a chính
là địa chỉ của phần tử đầu tiên trong mảng a, các địa chỉ tiếp theo là các phần tử tiếp trong mảng ( cách nhau 1 đơn vị ) Như vậy chỉ cần biết địa chỉ đầu và số phần
tử của mảng đã khai báo là ta có thể duyệt được mảng đó
Tương tự, địa chỉ của từng phần tử mảng a là &a[i] hoặc (a+i)
Giá trị của từng phần tử mảng a là a[i] hoặc *(a+i)
Lưu ý: a là một con trỏ, tuy nhiên nó là một hằng con trỏ nên giá trị của nó không thể thay đổi trong chương trình
Để tìm những phần tử nằm trong khoảng [-5,5] ta duyệt từng phần tử của mảng và kiểm tra điều kiện a[i] >= -5 và a[i] <=5 Sau đó tính luôn số phần tử thỏa mãn và cộng vào biến tổng
Trang 11for ( int i = 0 ; i < n; ++i)
{
if (*(a+i) >= - 5 && *(a+i) <= 5 ) {
SumNumberIn55 += *(a+i); // cộng vào biến tổng countIn55++; //đếm số lần xuất hiện
cout<<*(a+i)<<" "; // xuất ra màn hình các số thuộc [-5,5] }
}
Nếu số lần xuất hiện countIn55 = 0 tức là không có phần tử nào thỏa mãn điều kiện thuộc đoạn [-5,5] Ngược lại in ra tổng và lấy tổng chia số phần tử thỏa mãn điều kiện ta được Trung Bình Cộng (TBC)
if (countIn55 == 0 )
cout<<"Khong co phan tu nao trong mang thuoc doan [-5,5]!"<<endl;
else
cout<<endl<<"Tong cac so tren la: "<<SumNumberIn55<<", va TBC la:
"<<SumNumberIn55/countIn55<<endl;
Để chèn số nguyên x đằng trước số chính phương đầu tiên trong mảng, sau khi nhập số nguyên x từ bàn phím, ta duyệt mảng và kiểm thử xem phần tử đó có phải số chính phương không Nếu đúng thì tiến hành chuyển các phần tử trong mảng về cuối ( a[j] = a[j-1] với j=i n , i là số hiệu của phần tử là số chính phương ) Sau đó chèn x vào vị trí của phần tử là số chính phương đó Sau khi chèn số phần
tử của mảng sẽ tăng lên 1 (*n)++;
void InsertX ( int *n, double *a)
{
cout<<endl<<"Chen x vao truoc so chinh phuong"<<endl;
int x;
cout<<"Nhap vao so nguyen x? ";
cin>>x;
int haveSquareNumb = 0 ; // biến kiểm tra trong mảng có số chính phương không?
for ( int i = 0 ; i < *n; ++i)
{
if ( isSquareNumber (*(a+i))) // nếu phần tử là số chính phương {
for ( int j = *n; j >= i; j ) // duyệt từ cuối mảng
*(a+j) = *(a+j- 1 ); // dịch lần lượt về cuối (*n)++; // mảng sẽ tang them 1 phần tử
*(a+i)=x; // gán x vào vị trí là số chính phương haveSquareNumb = 1 ; // mảng có xuất hiện số chính phương
break ; // thoát vòng lặp để chỉ chèn vào số chính phương đầu }
}
if (haveSquareNumb)
{
// In mang ra
OutPutArray (*n,a);
} else {
cout<<"Mang khong co chua bat ky phan tu nao la so chinh phuong!"; }
}
Trang 12Dịch phần tử khi chèn:
Ta biết, Số chính phương hay còn gọi là số hình vuông là số tự nhiên có căn
bậc 2 là một số tự nhiên, hay nói cách khác, số chính phương là bình phương (lũy thừa bậc 2) của một số tự nhiên Hay nói cách khác, một số tự nhiên là số chính phương khi bình phương căn bậc hai của nó bằng chính nó
Ví dụ: 4 = 2*2, 4 = √4 ∗ √4
bool isSquareNumber ( double x)
{
if (x> 3 )
{
if (( int ) sqrt (x) * ( int ) sqrt (x) == x)
return true ;
else
return false ; } else {
return false ; }
}
Do các phần tử của mảng là số thực nên ta ép kiểu (int) cho căn để được kết quả chính xác
Để xóa các phần tử chẵn trong mảng, giống như ý chèn trên, ta duyệt từng phần tử và kiểm tra xem phần tử đó có chia hết cho 2 không Sau đó tiến hành dịch các phần tử về bên trái và giảm số phần tử trong mảng đi
for ( int i = 0 ; i < *n; ++i)
if (*(a+i) == ( int ) *(a+i) && ( int )*(a+i)% 2 == 0 ) {
for ( int j = i; j < *n- 1 ; ++j) {
*(a+j) = *(a+j+ 1 );
} (*n) ;
}
Trang 13Do phần tử mảng là số thực nên ta không thể dùng phép chia lấy dư cho 2 được Vì vậy cần kiểm tra phần tử đó có phải số nguyên không (*(a+i) == ( int )
*(a+i) và phần nguyên của số đó có chia hết cho 2 không ( int )*(a+i)% 2 == 0
Để sao chép số âm về đầu mảng, ta cũng duyệt từng phần tử trong mảng và kiểm tra phần tử đó có < 0 hay không Sau đó giống như chèn phần tử, ta sẽ chèn phần tử âm đó về đầu mảng
void copyNegativeNumber ( int *n, double *a)
{
cout<<"Sao chep tat ca cac so am ve dau mang:"<<endl;
int stt = 0 ; // đánh dấu vị trí đầu mảng đã bị chèn
for ( int i = 0 ; i < *n; ++i)
{
if (*(a+i)< 0 ) {
double temp = *(a+i); // một biến tạm để lưu phần tử âm
for ( int j = *n; j > stt; j )
*(a+j) = *(a+j- 1 ); // dịch phần tử về cuối mảng
*(a+stt)=temp;//chèn phần tử âm về vị trí đầu mảng chưa chèn (*n)++; // tăng số phần tử của mảng lên
i++;//Xét vịtrí tiếp theo vì mảnh đã bị thêm 1 phần tử ở đầu stt++; // đánh dấu là vị trí đầu tiên của mảng đã bị chèn lần sau sẽ chèn vào vị trí tiếp theo
} }
OutPutArray (*n,a);
}
Tuy nhiên ở đây, ta sẽ đặc biệt một chút là sao chép số âm về đầu mảng lần lượt theo thứ tự xuất hiện của nó