2. Recursion is everywhere
• In general, to solve a problem using recursion, you break it into
subproblems. Each subproblem
• is the same as the original problem, but smaller in size. You can apply
the same approach to each subproblem to solve it recursively.
3. A recursive function
• A recursive function can be defined as a routine that calls itself directly or indirectly.
• Using the recursive algorithm, certain problems can be solved quite easily. This technique
provides a way to break complicated problems down into simple problems which are
easier to solve.
• base case : One critical requirement of recursive functions is the termination point or
base case. Every recursive program must have a base case to make sure that the function
will terminate (終止條件:termination condition). Missing base case results in
unexpected behavior.
• Implement:
• The method is implemented using an if−else or a switch statement that leads to different cases.
• One or more base cases (the simplest case) are used to stop recursion.
• Every recursive call reduces the original problem, bringing it increasingly closer to a base case
until it becomes that case.
• three types of recursion : Head Recursion, Tail Recursion, Body Recursion
• https://www.geeksforgeeks.org/recursive-functions/
• https://www.w3schools.com/java/java_recursion.asp
4. Head Recursion、 Tail Recursion
• Tail recursion is the act of calling a recursive function at the end of a
particular code module rather than in the middle.
• A call is head-recursive when the first statement of the function is
the recursive call.
5. Data structure when executing machine codes
• System stack、run time stack、execution stack
• Local variables
• Activation record、Activation frame
• Heap
• Dymanic data, such as linked list、arraylist
• Data segment
• Global variable
• Code segment
6. Recursive operation in
system stack: 1
static int s(int n){
if (n<=1) return (1);
else return (n+s(n-1));}
Caller: r=s(5);
1. 主程式R=s(5);主程式r=s(5);呼叫s(5),無法完
成,被push到system stack頂端
2. 呼叫s(5):進入s函式本體執行
return(5+s(4)) ,but 無法完成,被push到
system stack頂端,但需呼叫s(4);
3. 呼叫s(4):):進入s函式本體執行
return(4+s(3)) ,but 無法完成,被push到
system stack頂端,但需呼叫s(3);
4. 呼叫s(3):):進入s函式本體執行
return(3+s(2)) ,but 無法完成,被push到
system stack頂端,但需呼叫s(2);
5. 呼叫s(2):):進入s函式本體執行
return(2+s(1)) ,but 無法完成,被push到
system stack頂端,但需呼叫s(1);
6. 呼叫s(1):進入本體,執行base case之
return(1), 結束遞迴,將system頂端的
return(2+s(1)) , pop出來執行,即計算s(2)之
結果2+1,且return(2+1);
7. 將system頂端的return(3+s(2)) , pop出來執
行, 且接收return結果,即計算s(3)之結果
3+3,且return(6);
8. 將system頂端的return(4+s(3)) , pop出來執
行, 且接收return結果,即計算s(4)之結果
4+6,且return(10);
9. 將system頂端的return(5+s(4)) , pop出來執
行, 且接收return結果,即計算s(5)之結果
5+10,且return(15);
10. 將system頂端的r=s(5) ,pop出來執行, s(5)之
結果15 assign給r
execution stack
return(2+s(1))
return(3+s(2))
return(4+s(3))
return(5+s(4))
r=s(5);
top
pop
7. Recursive operation in
system stack: 2
static int s(int n){
System.out.print(n);
if (n<=1) return (1);
else return (n+s(n-1));}
Caller:
int r;
r=s(5);
System.out.print(n);
Its result?
1. 主程式R=s(5);主程式r=s(5);呼叫s(5),無法完
成,被push到system stack頂端
2. 呼叫s(5):進入s函式本體執行
return(5+s(4)) ,but 無法完成,被push到
system stack頂端,但需呼叫s(4);
3. 呼叫s(4):):進入s函式本體執行
return(4+s(3)) ,but 無法完成,被push到
system stack頂端,但需呼叫s(3);
4. 呼叫s(3):):進入s函式本體執行
return(3+s(2)) ,but 無法完成,被push到
system stack頂端,但需呼叫s(2);
5. 呼叫s(2):):進入s函式本體執行
return(2+s(1)) ,but 無法完成,被push到
system stack頂端,但需呼叫s(1);
6. 呼叫s(1):進入本體,執行base case之
return(1), 結束遞迴,將system頂端的
return(2+s(1)) , pop出來執行,即計算s(2)之
結果2+1,且return(2+1);
7. 將system頂端的return(3+s(2)) , pop出來執
行, 且接收return結果,即計算s(3)之結果
3+3,且return(6);
8. 將system頂端的return(4+s(3)) , pop出來執
行, 且接收return結果,即計算s(4)之結果
4+6,且return(10);
9. 將system頂端的return(5+s(4)) , pop出來執
行, 且接收return結果,即計算s(5)之結果
5+10,且return(15);
10. 將system頂端的r=s(5) ,pop出來執行, s(5)之
結果15 assign給r
System stack
return(2+s(1))
return(3+s(2))
return(4+s(3))
return(5+s(4))
r=s(5);
top
pop
8. Illustration of the stack allocation (a) before, (b) during, and (c) after the procedure call. Figure 2.16 shows the
state of the stack before, during, and after the procedure call.
$fp
$sp
High address
Low address a. b. c.
Saved argument
registers (if any)
Saved return
address
Saved saved
registers (if any)
Local arrays and
structures (if any)
$fp
$sp
$sp
$fp
Activation record
/frame
9. The MIPS memory allocation for program and data.
Stack
Dynamic data
SS
heap
DS (global variable)
CS (code segment)
Static data
Text
Reserved
$sp 7fff fffchex
1000 8000hex
1000 0000hex
$gp
0040 0000hex
pc
0
$gp: access
static data
(local variable)
10. import java.util.Scanner;
public class dec_bin2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int z, sign=1;
double rn=0, fract;
String bin1="", bin2="";
while (rn>=-99) {
bin1=""; bin2="";
System.out.print("輸入數值含小數:");
rn = input.nextDouble();
if (rn<-99) System.exit(-1);
if (rn<0) {
sign=-1;
rn=rn*(-1); }
z=(int) rn;
System.out.println(rn+" 經(int)之type casting變成"+z);
fract=rn-z;
bin1=toint(z);
bin2=tofloat(fract);
String res1;
res1=(sign==-1)? “-”+rn+“轉換為二進制得”+“-”+bin1+“.”+bin2 : rn+"轉換為二進制得"+bin1+"."+bin2;
System.out.println(res1);
//=================
bin1=Rtoint(z);
bin2=Rtofloat(fract);
res1=(sign==-1)?"-"+rn+"轉換為二進制得"+"-"+bin1+"."+bin2:rn+"轉換為二進制得"+bin1+"."+bin2;
System.out.println(res1);
}//while
}//main
static String toint(int z){
String bin1="";
while (z>0) {
bin1=z%2+bin1;
z=z/2; }
return bin1;
}
static String tofloat(double fract){
String bin2="";
int tmp;
while (fract>0) {
fract=fract*2;
tmp=(int)fract;
fract=fract-tmp;
bin2=bin2+tmp;
}
return bin2;
}
11. 同樣的名字與不同的參數
import java.util.Scanner;
public class dec_bin2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int z;
double rn=0, fract;
String bin1="", bin2="";
while (rn>=0) {
bin1=""; bin2="";
System.out.print("輸入數值含小數:");
rn = input.nextDouble();
z=(int) rn;
fract=rn-z;
bin1=convert(z);
System.out.println("整數:"+bin1);
bin2=convert(fract);
System.out.println("小數:"+bin2);
System.out.println(rn+"轉換為二進制得"+bin1+"."+bin2);
}//while
}//main
}//class
static String convert(int x) {
//整數
String bin="";
while (x>0) {
bin=x%2+bin;
x=x/2; }
return(bin);
}//convert(int x)
static String convert(double x){
//小數
String bin="";
int tmp;
while (x>0) {
x=x*2;
tmp=(int)x;
x=x-tmp;
bin=bin+tmp;
}
return(bin);
}//convert(double x)
12. import java.util.Scanner;
public class dec_bin2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int z, sign=1;
double rn=0, fract;
String bin1="", bin2="";
while (rn>=-99) {
bin1=""; bin2="";
System.out.print("輸入數值含小數:");
rn = input.nextDouble();
if (rn<-99) System.exit(-1);
if (rn<0) {
sign=-1;
rn=rn*(-1); }
z=(int) rn;
System.out.println(rn+" 經(int)之type casting變成"+z);
fract=rn-z;
bin1=toint(z);
bin2=tofloat(fract);
String res1;
res1=(sign==-1)?"-"+rn+"轉換為二進制得"+"-"+bin1+"."+bin2:rn+"轉換為二進制得"+bin1+"."+bin2;
System.out.println(res1);
//=================
bin1=Rtoint(z);
bin2=Rtofloat(fract);
res1=(sign==-1)?"-"+rn+"轉換為二進制得"+"-"+bin1+"."+bin2:rn+"轉換為二進制得"+bin1+"."+bin2;
System.out.println(res1);
}//while
}//main
static String Rtoint(int z){
if (z>0)
return (Rtoint(z/2)+""+z%2);
else
return "";
}
static String Rtofloat(double fract){
if (fract>0) {
fract=fract*2;
int tmp=(int)fract;
return (tmp+""+Rtofloat(fract-tmp));
}
else return "";
}
14. Judge prime number
System.out.print("輸入>=2整數:");
n = input.nextInt();
if (n<=0) break;
prime=true;
i=2;
while (i*i<=n) {
if (n%i==0) {prime=false; break;}
++i;
}
dif=(prime)?"是質數!":"不是質數!";
System.out.println(n+dif);
//====================
prime=isPrime(n);
dif=(prime)?"是質數!":"不是質數!";
System.out.println(n+dif);
//====================
prime=R_isPrime(n, 2);
dif=(prime)?"是質數!":"不是質數!";
System.out.println(n+dif);
static boolean isPrime(int n) {
int i=2;
while (i*i<=n) {
if (n%i==0) { return (false); }
++i;
}
return (true);
}
static boolean R_isPrime(int n, int i) {
//int i=2;
if (i*i<=n) {
if (n%i==0) { return (false); }
return (R_isPrime(n, i+1));
}
return (true);
}
prime_2.java
15. import java.util.Scanner;
public class linear_search_2 {
static int [] A={15, 28, 45, 51, 60, 68, 75, 81, 90, 99};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int score=99, idx=-1;
while (score>=0) {
System.out.print("請輸入欲尋找分數(>=0): ");
score = scanner.nextInt();
if (score<0) break;
idx=linearsearch(A, score);
if (idx>=0)
System.out.println("1.欲尋找分數"+score+" 在A["+idx+"]");
else
System.out.println("1.欲尋找分數"+score+" 不在A陣列中");
idx=Rlinearsearch(A, score, 0);
if (idx>=0)
System.out.println("2.欲尋找分數"+score+" 在A["+idx+"]");
else
System.out.println("2.欲尋找分數"+score+" 不在A陣列中");
}
}//main()
static int linearsearch(int refsc[],int num) {
int i=0;
int len=refsc.length;
while (i<=len-1)
{ System.out.println("尋找次數:第"+(i+1)+"次");
if (refsc[i]==num) //Ascending
return (i);
else i++;
}//while
return (-1); //not found!!
}//lsearch
static int Rlinearsearch(int refsc[],int num, int i) {
int len=refsc.length;
if (i<=len-1)
{ System.out.println("尋找次數:第"+(i+1)+"次");
if (refsc[i]==num) //Ascending
return (i);
else return Rlinearsearch(refsc, num, ++i);
}
return (-1); //not found!!
}
}//class
16. binary search二分搜尋法
public class bin_search_1 {
static int [] A={15, 28, 45, 51, 60, 68, 75, 81, 90, 99};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int score=99, idx=-1;
while (score>=0) {
System.out.print("請輸入欲尋找分數: ");
score = scanner.nextInt();
if (score<0) break;
idx=binarysearch(A, score);
if (idx>=0)
System.out.println("欲尋找分數"+score+" 在A["+idx+"]");
else
System.out.println("欲尋找分數"+score+" 不在A陣列中");
}
}//main()
static int binarysearch(int refsc[],int num) {
int low=0,mid=0,high=0, cnt=1;
high=refsc.length-1;
while (low<=high)
{ System.out.println("尋找次數"+cnt+"次");
mid=(int)((low+high)/2);
if (refsc[mid]<num) //Ascending
low=mid+1;
else if (refsc[mid]>num)
high=mid-1;
else
return (mid);
cnt++;
}//while
return (-1); //not found!!
}//binarysearch
}//class
17. static int Rbinarysearch(int refsc[],int num,int low, int high)
{
int mid=0;
mid=(int)((low+high)/2);
if (low>high)
return (-1); //not found!!
else if (refsc[mid]<num) //Asce
return (Rbinarysearch(refsc,num,mid+1,high));
else if (refsc[mid]>num) //Asce
return (Rbinarysearch(refsc,num,low,mid-1));
else //if (refsc[mid]==num)
return (mid));
}// Rbinarysearch
//static關鍵字讓程式被OS載入時函式被儲存於記憶體中,直
到Application結束為止。
RBinary search //用遞迴的二元搜索
21 33 44 66 76 89 99
0 6
low high
mid
3
18. GCD
import java.util.Scanner;
import java.io.*;
public class GCD_all{
static int fib[];
public static void main(String args[])
{
int n1=0,n2=0,result=0;
fib=new int[100];
System.out.println("----求二數之最大公因數GCD----");
try {
Scanner input = new Scanner(System.in);
System.out.print("正整數1:(>=2)");
n1=input.nextInt();
System.out.print("正整數2:(>=2)");
n2=input.nextInt();
}
catch (Exception e) {
System.exit(-1);}
if (n1<2 || n2<2) System.exit(-1);
result=gcd(n1,n2);
System.out.println("recursive:gcd("+n1+","+n2+")="+result);// using the loop approach 1--
substraction
result=gcd_loop1(n1,n2);
System.out.println("輾轉相減法:gcd("+n1+","+n2+")="+result);// using the loop approach 2--divide
result=gcd_loop2(n1,n2);
System.out.println("輾轉相除法:gcd("+n1+","+n2+")="+result);
}//main
static int gcd_loop1(int m, int n) {
while (m!=n) {
while (m>n) m=m-n;
while (m<n) n=n-m; }
return (m); }
static int gcd_loop2(int m, int n) {
int t;
if (m<n) { t=m;m=n;n=t; }
while (n!=0) {
t=m%n; m=n; n=t; }
return (m); }
static int gcd(int m, int n) {
int temp;
if (m<n) {temp=m; m=n; n=temp; }
if (m%n==0) return (n);
else return ( gcd(n, m%n) );
}//gcd
static int gcd_loop1b(int m, int n) {
if (m!=n) {
if (m>n) return gcd_loop1b(m-n, n);
if (m<n) return gcd_loop1b(m, n-m); }
return (m); }
}//class
19. selection_sort
public class Rselection_sort{
public static void main(String[] args){
int max=0,i=0, j=0, tmp=0;
int [] data2={78,66,50,90,45,88,89,40,30,40};
System.out.println("before descending sorting");
for(i=0;i<=data2.length-1; i++)
System.out.println("data2["+i+"]="+data2[i]);
rsort(data2, 0);
// ssort(data2);
System.out.println("after descending sorting");
for(i=0;i<=data2.length-1; i++)
System.out.println("data2["+i+"]="+data2[i]);
}//main
static void ssort(int [] data2){
int max,i, j, tmp;
for(i=0;i<=data2.length-2; i++){
max=i;
for (j=i+1;j<=data2.length-1;j++)
if (data2[max]<data2[j]) max=j;
tmp=data2[i];
data2[i]=data2[max];
data2[max]=tmp;
}
}//ssort
static void rsort(int [] data, int i){
int max=i, j, tmp;
if (i<=data.length-2) {
for (j=i+1;j<=data.length-1;j++)
if (data[max]<data[j]) max=j;
tmp=data[i];
data[i]=data[max];
data[max]=tmp;
rsort(data, i+1); }
}//rsort
24. String sta=xx(6);
System.out.println(sta);
String stb=yy(6);
System.out.println(stb);
static String xx(int n){
if (n<=1) return (""+n);
else return (n+xx(n-2));
}
static String yy(int n){
if (n<=1) return (""+n);
else return (yy(n-2)+n);
}
return (“0");
return (2+xx(2-2));
return (4+xx(4-2));
return (6+xx(6-2));
sta=xx(6);
After calling, OS will create
activation record in execution
stack
Activation record for xx()
xx()
xx()
xx()
Activation record for main()
Pop & return(“0”)
Pop & return(2+“0”)
Pop & return(4+“20”)
Pop & return(6+“420”)
25. String stb=yy(6);
System.out.println(stb);
static String yy(int n){
if (n<=1) return (""+n);
else return (yy(n-2)+n);
}
yy(6-2)+”6”
yy(4-2)+”4”+”6”
yy(2-2)+”2”+”4”+”6”
“0”+”2”+”4”+”6”
return (“0");
return (2+xx(2-2));
return (4+xx(4-2));
return (6+xx(6-2));
sta=xx(6);
After calling, OS will create
activation record in execution
stack
Activation record for xx()
xx()
xx()
xx()
Activation record for main()
Pop & return(“0”)
Pop & return(2+“0”)
Pop & return(4+“20”)
Pop & return(6+“420”)
27. time complexity of Fibonacci
• loop solution:
• The time complexity of the iterative code is linear, as the loop runs from 2 to
n, i.e. it runs in O(n) time
• Recursive solution:
• for n > 1:
T(n) = T(n-1) + T(n-2) + 4 (1 comparison, 2 subtractions, 1 addition)
• the time taken by recursive Fibonacci is O(2^n) or exponential.
• https://syedtousifahmed.medium.com/fibonacci-iterative-vs-
recursive-5182d7783055
28. T(n) = T(n-1) + T(n-2) + c
= 2T(n-1) + c //from the approximation T(n-1) ~ T(n-2)
= 2*(2T(n-2) + c) + c
= 4T(n-2) + 3c
= 8T(n-3) + 7c
= 2^k * T(n - k) + (2^k - 1)*c Let's find the value of k for which: n - k = 0
k = n
T(n) = 2^n * T(0) + (2^n - 1)*c
= 2^n * (1 + c) – c i.e. T(n) ~ O(2^n)