Bab 6: Fungsi II
6.1 Fungsi Rekursi
Fungsi yang ditulis sebelum ini adalah berbentuk hirarki atau iteratif. Dalam sesetengah situasi, masalah akan lebih muda diselesaikan jika fungsi itu di tulis dalam bentuk memanggil dirinya sendiri secara terus atau sebaliknya. Bentuk ini dikenali sebagai fungsi rekursi.
Fungsi rekursi adalah satu topik yang kompleks. Walaubagaimanapun, kita lihat contoh-contoh mudah bagaimana fungsi rekursi ini digunakan.
Bentuk umum:
if(mempunyai kes yang mudah)
Selesaikannya;
else
Takrif semula masalah menggunakan fungsi rekursi.
Kita patut tahu bahawa sesuatu fungsi titu hanya boleh menyelesaikan masalah yang paling ringkas atau dikenali sebagai kes asas. Melalui kes asas ini, fungsi tersebut hanya akan terus memulangkan nilai keputusan. Sekiranya terdapat masalah yang lebih kompleks, fungsi itu akan membahagikan masalah tersebut kepada dua keping konsep: konsep yang tahu menyelesaikan masalah dan konsep yang tidak tahu menyelesaikan masalah. Dengan ini, konsep yang kedua mestilah menggambarkan masalah sebenar (original/root problem). Oleh kerana masalah yang baru nampak seperti masalah sebenar, fungsi tersebut akan memanggil dirinya sendiri untuk menyelesaikan masalah yang lebih kecil. Ini dikenali sebagai panggilan rekursi dan langkah rekursi. Langkah rekursi mestilah memasukkan kata kunci return kerana nilai keputusannya akan dicantumkan dengan sebahagian masalah bagi fungsi yang tahu menyelesaikan untuk membentuk satu keputusan yang akan dipulangkan pada fungsi pemanggil (caller).
Diagram:
![]() | |||
Contoh:
#include <iostream.h>
int darab(int k, int n)
{
int j;
if (n==1)
j=k;
else
j=k+darab(k,n-1);
return j;
}
int main()
{
cout<<darab(2,6);
return 0;
}
Output:
12
Penjelasan:
Fungsi darab(…) akan memanggil dirinya sendiri dengan memberikan hujah yang semakin berkurangan sehinggalah sampai ke tahap yang terkecil yang mempunyai nilai pulangan tertentu seperti dalam kes ini memulangkan nilai j. Kemudian setipa satu panggilan boleh dinilaikan dan memulangkan nilai kepada panggilan fungsi tersebut sebelumnya hingga sampai ke panggilan yang pertama.
Bentuk seperti fungsi rekursi ini boleh juga ditulis dalam bentuk gelung tetapi lebih menarik jika ditulis menggunakan fungsi rekursi kerana ia kurang menggunakan pembolehubah berbanding dengan fungsi biasa yang banyak menyimpan nilai perkiraan untuk memastikan yang gelungan itu berjalan. Fungsi rekursi walaubagaimanapun menggunakan ruang dan masa mesin berbanding dengan fungsi lain.
Latihan:
Tuliskan satu program menggunakan fungsi rekursi untuk mengira dan mencetak nombor factorial 0 hingga 10.
Jawapan:
#include <iostream.h>
#include <iomanip.h>
unsigned long factorial(unsigned long);
int main()
{
for (int i=0;i<=10;i++)
cout<<setw(2)<<i<<"!="<<factorial(i)<<endl;
return 0;
}
unsigned long factorial(unsigned long number)
{
if (number <=1)
return 1;
else
return number *factorial(number-1);
}
6.2 Parameter Rujukan
Penghantaran hujah ke fungsi boleh dibuat sama ada menggunakan panggilan ikut nilai (call by value) ataupun panggilan ikut rujuk (call by reference).
Apabila hujah dihantar menggunakan panggilan ikut nilai, hujah tersebut dibuat dan dihantar ke fungsi yang dipanggil (callee). Perubahan pada hujah yang dibuat tidak akan mempengaruhi nilai pembolehubah pada fungsi pemanggil (caller). Ini menghalang kesan-sampingan yang boleh memperlahankan sistem pembangunan perisian.
Contoh:
#include <iostream.h>
inline double cube(const double s) { return s*s*s;}
int main()
{
cout<<"Enter the side length of your cube: ";
double side;
cin>>side;
cout<<"Volume of cube with side "
<<side<<"is "<<cube(side)<<endl;
return 0;
Output:
Enter the side length of your cube: 3.5
Volume of cube with side 3.5 is 42.875
Bagi panghantaran hujah menggunakan panggilan ikut rujukan, panggilan mestilah dibuat dengan penggunakan penunding (pointer). Bagi setiap pengisytiharan fungsi prototaip dan pembolehubah, hujah mestilah didahulukan dengan simbol &. Nilai yang diubah di dalam fungsi Gandadua yang dipanggil itu mempengaruhi nilai hujah di dalam fungsi pemanggil.
Contoh:
#include <iostream.h>
void Gandadua(int *a)
{
*a = *a * *a;
}
void main()
{
int N=6;
cout<<”Nilai sebelum bagi N ialah”<<N<<endl;
Gandadua(&N);
cout<<”Nilai selepas panggilan Gandadua ialah”<<N<<endl;
}
Output:
Nilai sebelum bagi N ialah 6
Nilai selepas panggilan Gandadua ialah 36
6.3 Fungsi Inline
C++ menyediakan funsi inline untuk membantu mengurangkan prapemproses define. Biasanya prapemproses define digunakan untuk mentakrif sesuatu makro seperti:
#define Max(x,y) ((x>y)? x:y)
Katakunci inline ialah satu permohonan kepada pengkompil supaya sesuatu fungsi diganti bagi setiap kali panggilan kepada fungsi inline dibuat.
Biasanya, fungsi yang ditulis sebagai fungsi inline perlulah fungsi yang ringkas yang ingin menjimatkan masa dan storan.
Contoh:
#include <iostream.h>
inline double cube(const double s) { return s*s*s;}
int main()
{
cout<<"Enter the side length of your cube: ";
double side;
cin>>side;
cout<<"Volume of cube with side "
<<side<<"is "<<cube(side)<<endl;
return 0;
6.4 Pengendali Resolusi Skop Unari
Pengendali resolusi skop unari (::) membolehkan pembolehubah sejagat diakses apabila pembolehubah tempatan yang sama nama berada di dalam skop. Skop unari ini tidak boleh digunakan untuk mengakses oembolehubah tempatan yang sama nama di luar blok.
Contoh:
#include <iostream.h>
int size=10;
void CountSquare(int length)
{
int size=length;
int square = size * (::size);
cout<<"Square is"<<square<<endl;
}
void main()
{
int i=4;
CountSquare(i);
}
Output:
Square is 40
6.5 Penyaratan Fungsi
C++ membenarkan pengisytiharan beberapa fungsi dengan nama yang sama asalkan parameternya berbeza (sekurang-kurangnya jenis data bagi setiap parameter itu berbeza). Kebolehan ini dinamakan penyaratan fungsi yang menggunakan konsep polimorfisma (*rujuk kaedah teknik berorientasikan objek dan 6.51 ). Apabila penyaratan fungsi ini dipanggil, pengkompil akan memilih fungsi yang sesuai dengan memeriksa nombor, jenis dan aturan “argument” si pemanggil (caller). Penyaratan fungsi selalunya digunakan untuk membina beberapa fungsi yang sama nama tetapi menjalankan kerja ke atas jenis data yang berbeza.
Contoh:
#include <iostream.h>
int square(int x){return x*x;}
double square(double y) {return y*y;}
int main()
{
cout<<"The square of integer 7 is"<< square(7)
<<"\nThe square of double 7.5 is "<<square(7.5)<<endl;
return 0;
}
Penjelasan:
Terdapat dua fungsi yang sama nama iaitu square tetapi mengawal jenis data yang berbeza. Satu mengawal jenis data integer int square(…) dan satu lagi mengawal jenis data double double square(…).
Apabila fungsi ini dipanggil dari fungsi main(), pengkompil akan memeriksa parameter fung si square(..) di dalam fungsi main() i.e square(7) dan menentukan sama ada ia akan dilaksanakan menggunakan int square(…) atau double square(…) yang kemudiannya akan memulangkan nilai kepada fungsi main().
6.51 Polimorfisma
Polimorfisma merujuk kepada fenomenan yang mana satu mesej yang sama jika diberi dua objek yang berbeza menghasilkan tindakbalas yang berbeza. Konsep ini lebih mudah dilaksanakan bersama konsep pewarisan.
6.6 Hujah Lalai
Sesuatu hujah di dalam fungsi boleh dinyatakan nilai lalainya. Sekiranya hujah tidak diberi nilai semasa panggilan kepada fungsi itu, secara otomatik nilai lalai yang telah diberikan semasa pentakrifan fungsi itu digunakan sebagai nilai menggantikannya.
(*rujuk Bab 5: Fungsi I- Function Argument)
contoh:
#include <iostream.h>
int PrintBox(int H=1, int W=1);
void main()
{
int x=4, y=6;
PrintBox();
PrintBox(x);
PrintBox(x,y);
}
int PrintBox(int H, int W);
{
for (nt I=0; I<H;I++)
{
for (int j=0; j<W;j++)
cout<<”*”;
cout<<endl;
}
}
Output:
*
*
*
*
*
******
******
******
******
6.7 Templet Fungsi
Templet fungsi digunakan sekiranya anda mahu lakukan satu proses yang sama tetapi ke atas nilai-nilai yang mempunyai jenis data yang berbeza.
Untuk mengelakkan dari membina beberapa fungsi, C++ membenarkan templet fungsi dibina. Untuk mentakrif templet fungsi, gunakan katakunci template dan diikuti dengan satu senarai jenis parameter formal dalam kurungan < dan >.
Bentuk umumnya:
Template<class J>
Jenis_pulangan nama_fungsi(J hujah)
{ }
J ialah parameter templet kerana ia dirujuk kepada jenis data yang akan diberi semasa panggilan kepada fungsi itu.
Contoh:
Template <class J>
void Paparan(J Nilai1, J Nilai2)
{
cout<<”Nilai yang dicetak ialah”<<Nilai1<<”dan”<<Nilai2<<endl;
}
void main()
{
int x=3;
float z=4.5;
Paparan(x,x+3);
Paparan(z, z+5);
}
Output:
Nilai yang dicetak ialah 3 dan 6
Nilai yang dicetak ialah 4.5 dan 9.5
6.8 Fungsi Perpustakaan
Selain dari fungsi-fungsi yang anda telah takrifkan, kebanyakan daripada perlaksanaa C++ ada menyediakan perpustakaan piawai yang terdapat banyak fungsi di dalamnya. Secara asasnya, C piawai menyediakan 15 pengepala yang setiap satunya mengandungi banyak fungsi di dalamnya.
<assert.h> <stype.h> <errno.h> <float.h> <limits.h>
<locale.h> <math.h> <setjmp.h> <signal.h> <stdarg.h>
<stddef.h> <stdio.h> <stdlib.h> <string.h> <time.h>
Bagi C++, berikut adalah fail pengepala yang baru dan boleh digunakan.
<utility> <vector> <list> <deque> <queue> <stack>
<map> <set> <bitset> <functional> <memory> <iterator>
<algorithm> <exception> <stdexcept> <string> <sstream> <locale>
<limits> <typeinfo>
Sila rujuk sumber dan buku-buku untuk mengetahui lebih lanjut mengenai fungsi-fungsi yang terdapat di dalam fail pengepala yang telah disenaraikan di sini. Cari fungsi-fungsi lazim dari fail pengepala <math.h> , <ctype.h> dan <iomanip.h>. Ianya amat berguna dalam pengaturcaraan dan anda dianggap tahu untuk menggunakan fungsi-fungsi tersebut.

0 komentar:
Posting Komentar