C++語法衝刺(3)

最後一堂語法衝刺ㄌ

目錄

  • function & recursion
  • struct
  • 亂七八糟的東西

函式

function

#include <iostream>
using namespace std;
int main() {
	int x1, y1, x2, y2;
	int a, b, c, d;
	cin >> x1 >> y1 >> x2 >> y2;
	cin >> a >> b >> c >> d;
	int cnt = 0;
	if(a<=x1 && x1<=c && b<=y1 && y1<=d) cnt++;
	if(a<=x1 && x1<=c && b<=y2 && y2<=d) cnt++;
	if(a<=x2 && x2<=c && b<=y1 && y1<=d) cnt++;
	if(a<=x2 && x2<=c && b<=y2 && y2<=d) cnt++;
	if(cnt<2) cout << (x2-x1)*(y2-y1);
	else if(cnt == 4) cout << 0;
	else{
		int xl, xr, yl, yr;
		if(x1 > a) xl = x1;
		else xl = a;
		if(x2 < c) xr = x2;
		else xr = c;
		if(y1 > b) yl = y1;
		else yl = b;
		if(y2 < d) yr = y2;
		else yr = d;
		cout << (x2-x1)*(y2-y1) - (xr-xl)*(yr-yl);
	}
	return 0;
}

我到底在寫什麼啊好醜

怎麼連我自己都看不懂RRRRRR

我怎麼一直打重複ㄉ東西

一直複製貼上再改煩死了啊啊啊

而且code這麼亂的話debug好難QAQ

好想像python一樣好多方便的函式……

Function saves the day!

#include <iostream>
using namespace std;
bool cover_corner(int x, int y, int x1, int y1, int x2, int y2){
	return x1<=x && x<=x2 && y1<=y && y<=y2;
}
int main() {
	int x1, y1, x2, y2;
	int a, b, c, d;
	cin >> x1 >> y1 >> x2 >> y2;
	cin >> a >> b >> c >> d;
	int cnt = 0;
	if(cover_corner(x1, y1, a, b, c, d)) cnt++;
	if(cover_corner(x1, y2, a, b, c, d)) cnt++;
	if(cover_corner(x2, y1, a, b, c, d)) cnt++;
	if(cover_corner(x2, y2, a, b, c, d)) cnt++;
	if(cnt<2) cout << (x2-x1)*(y2-y1);
	else if(cnt == 4) cout << 0;
	else{
		int xl = max(x1, a);
		int xr = min(x2, c);
		int yl = max(y1, b);
		int yr = min(y2, d);
		cout << (x2-x1)*(y2-y1) - (xr-xl)*(yr-yl);
	}
	return 0;
}

整齊、美觀、可讀性++、易於debug

減少複製貼上改到頭很痛編寫重複ㄉcode

btw C++也有有很多內建函式可以用喔喔喔

(希望你們還記得++是什麼意思

C++內建函式庫

__gcd(a,b) 回傳a和b的最大公因數

lcm(a,b) 回傳a和b的最小公倍數
swap(a,b) 交換a和b
max(a,b) 回傳a或b較大的那個
min(a,b) 回傳a或b較小的那個
abs(n) 回傳絕對值n
sqrt(n) 回傳根號n

這些都是比較常用的 可以先記一下

除此之外還有很多內建函式可以用,遇到再去查就可以ㄌ

btw後面這兩個要先include <cmath>

自訂義函式怎麼寫

/*回傳型別*/ /*函式名稱*/ (/*傳入參數*/){
    /*做事情*/
    return /*變數*/;
}
int plus_one(int n){
    return n + 1;
}

傳入參數的地方記得打上參數的型別

return代表回傳東西並且碰到return後函式會停止執行

例子

#include <iostream>
using namespace std;

bool passed(int n){ //傳入參數的名字可以跟傳進來的時候不一樣
    if(n < 60) return false; 
    //如果小於60就回傳false並結束 不會跑到後面的東西
    return true;
}

int main(){
    int score;
    cin >> score;
    if(!passed(score)) cout << "FAILURE\n";
    else cout << "I'm so dian\n";
}

如果我沒有要回傳東西ㄋ

如果我沒有要回傳東西ㄋ

在回傳型別寫void!!!

void greeting(){
    cout << "hello\n";
    return;
}

例子:

也可以省略return

那就是會跑到函式的最後一行才會結束

傳入一維陣列!

#include <iostream>
using namespace std;
int max_of_array(int arr[], int n) {
  int maxx = 0;
  for (int i = 0; i < n; i++){
      if(arr[i] > maxx) maxx = arr[i];
  }
  return maxx;
}
int main(){
    int arr[100] = {1, 2, 3};
    int maxx = max_of_array(arr, 100);
    cout << maxx;
}

// output : 3

傳入二維陣列!

#include <iostream>
using namespace std;
int max_of_array(int arr[][100], int n, int m) {
  int maxx = 0;
  for (int i = 0; i < n; ++i){
      for(int j=0; j < m; ++j)
          if(arr[i][j] > maxx) maxx = arr[i][j];
  }
  return maxx;
}
int main(){
    int arr[100][100] = {{1, 2, 3}, {4, 5, 6}};
    int maxx = max_of_array(arr, 100, 100);
    cout << maxx;
}

// output : 6

除了第一維以外要記得寫大小喔喔喔

pass by value

#include <iostream>
using namespace std;
void swap_num(int m, int n){
     int tmp;
     tmp = m;
     m = n;
     n = tmp;
}
int main(){
    int a = 1, b = 2;
    swap_num(a, b);
    cout << a << ' ' << b << '\n';
}

// output : 1 2

whyyyyyyyyyyyyyyyyyyyyyyyyyyy

pass by value

一般傳入參數的時候,參數是被複製進去的

所以m跟a是不一樣的東西,n跟b也是不一樣的東西

#include <iostream>
using namespace std;
void swap_num(int m, int n){
     int tmp;
     tmp = m;
     m = n;
     n = tmp;
}
int main(){
    int a = 1, b = 2;
    swap_num(a, b);
    cout << a << ' ' << b << '\n';
}

// output : 1 2

怎麼解決這個問題ㄋ

指標或pass by reference !

但我們之後才會教指標la

pass by reference

#include <iostream>
using namespace std;
void swap_num(int &m, int &n){
     int tmp;
     tmp = m;
     m = n;
     n = tmp;
}
int main(){
    int a = 1, b = 2;
    swap_num(a, b);
    cout << a << ' ' << b << '\n';
}

// output : 2 1

aka. 傳參考 一個給變數取暱稱的概念

用法基本上就是在變數前面加 '&'

總結一下

在函式裡面改變變數的值不會影響到這個函式以外的地方

但陣列是例外,在函式裡面改變陣列的值整個程式都會被影響到,原因教指標的時候應該會講......吧

遞迴

Recursion

遞迴是什麼

遞迴的定義:參見遞迴

蛤?

遞迴是什麼

遞迴函式就是指在函式中再呼叫一次函式本身,而用這種做法可以省下許多麻煩的coding,譬如若要算出\(x\)的階乘,其實\(x! = x \times (x-1)!\),再以此往下類推到\(1!\)為止,此時用遞迴去寫就很方便。

階乘

#include <iostream>
using namespace std;
int rec(int n){
    if(n == 1) return 1;
    return n * rec(n-1);
}
int main(){
    int n; 
    n = 5;
    cout << rec(n);
}

// output : 120

費式數列

在數學上,費波那契數是以遞迴的方法來定義:

\(F_{0}=0\)
\(F_{1}=1\)
\(F_{n}=F_{n-1}+F_{n-2}\) \((n \geq 2)\)

輸入一個數字\(n (n\leq 40)\) 請輸出費式數列第\(n\)項

費式數列

#include <iostream>
using namespace std;
int f(int n){
	if(n <= 1) return n;
	return f(n-1) + f(n-2);
}
int main(){
	int n;
	cin >> n;
	cout << f(n) << '\n';
}

河內塔

河內塔是根據一個傳說形成的一個問題:有三根桿子A, B, C。A桿上有\(n\)個\((n \geq 1)\)穿孔圓盤,盤子的尺寸由下到上依次變小。
現在,想要把桿子A上的盤子移動到桿子C,而且盤子的移動規則是:每次只能移動一個圓盤; 大盤子不能疊在小盤子上面。當然,任何盤子皆可以臨時置於B桿,也可將從A桿移出的圓盤重新移回A桿,但都必須遵循上述兩條規則。
現在,請你寫一個能夠描述盤子搬動過程的程式。

河內塔

把整個問題拆解成每次把最底下的盤子搬到目的地

所以會是先把第\(n\)個盤子以外的所有盤子搬到工具桿(?),再把第\(n\)個盤子搬到目的地,再把第\(n\)個盤子以外的所有盤子從工具桿(?)搬到目的地

#include <iostream>
using namespace std;
int cnt = 0;
void rec(int n, char from, char to, char buffer){
	if(n == 0) return;
	rec(n-1, from, buffer, to);
	printf("Move disk %d from %c to %c\n", n, from, to);
	cnt++;
	rec(n-1, buffer, to, from);
}
int main(){
	int n;
	cin >> n;
	rec(n, 'a', 'c', 'b');
	cout << cnt;
}

河內塔

快速冪

求\(n^{m}\)

for迴圈?

如果\(m=0\) \(n^{m}=1\)

如果\(m\)是奇數 \(n^{m}=n \times n^{m-1}\)

如果\(m\)是偶數

n^{m}=n^{\frac{m}{2}}\times n^{\frac{m}{2}}

快速冪

求\(n^{m}\)

#include <bits/stdc++.h>
using namespace std;
int rec(int n, int m){
	if(m == 0) return 1;
	if(m % 2 == 1) return n * rec(n, m-1);
	int a = rec(n, m/2);
	return a * a;
}
int main(){
	int n, m;
	cin >> n >> m;
	cout << rec(n, m) << endl;
}

寫寫題目

學長學長~

那我殼以在一個函式一次回傳兩個值ㄇ

打咩。

在一個函式回傳多個值 ?

struct !

struct

struct structName{
    /*這個struct裡面有的變數*/
}; // 注意這裡要分號

把很多變數綁在一起的東西(變數型態可以不一樣)

創造一個把很多變數綁在一起的變數型態

當要存取那些子資料時,便是使用 變數.子結構名稱 來像一個普通變數一樣存取。

栗子

#include <iostream>
using namespace std;
struct score{
    string name;
    int math;
};
int main(){
    score luo;
    luo.name = "luo";
    luo.math = 0;
}

搭配陣列使用

#include <iostream>
using namespace std;
struct score{
    string name;
    int math;
};
int main(){
    score students[100];
    int n;
    cin >> n;
    for(int i=0; i<n; ++i)
        cin >> students[i].name >> students[i].math;
    //輸入n個學生ㄉ名字和數學成績
}

好耶語法衝刺結束ㄌ

Made with Slides.com