No code no life
2020 暑假資訊讀書會
暑假資讀簡介
- 對象:027
- 時間:8/10-8/12 上午9:00-12:30
- 地點:資源大樓三樓 電腦教室一
- 講師名單:123賴昭勳 127黃思維 127張均豪
- 授課內容:C++基礎語法、資訊競賽簡介
Codeblocks 下載
第一支程式
#include <iostream>
using namespace std;
int main() {
cout << "Hello World!" << endl;
}
C++ 程式的組成
- 用來使用某些特定的內建功能,引入內建的函式庫。
- 基本上寫在最前面
- 處理C++式輸入輸出:#include <iostream>
1. 標頭檔
- 程式裡面的一組物件、類別、函式加上的標籤(為了避免名稱相撞)
- 標準函式庫:using namespace std
許多功能原本需要加上 std::function_name
using 就是直接告訴編譯器:「跟std名字一樣的東西就是std的」
2. 命名空間
- C++ 程式執行時會自動跑的函式
- int main() {}
回傳值:給編譯器看
名字跟參數
程式碼放這
3. 主函式
\注意/
#include <iostream>
using namespace std;
int main() {
}
#include <iostream>
using namespace std;
int main()
{
}
唯一真理
邪教
自己試試看吧!
變數、型別、運算子
C++ 如何儲存資料
不是01010111嗎?
雖然電腦裡所有資料都是二進位,程式語言會為使用者做好資料型別(data types),以方便處理不同種類的資料.
名稱 | 大小(位元組) | 數值範圍 |
---|---|---|
int | 4 | -2147483648~2147483647 |
unsigned int | 4 | 0~4294967295 |
long long | 8 | -2^63~2^63 - 1 |
char | 1 | -128~127 (或0~255) |
float | 4 | 3.4E +/- 38 (7 位數) |
double | 8 | 1.7E +/- 308 (15 位數) |
long double | 8 (?) | 1.7E +/- 308 (15 位數) |
bool | 1 | true 或 false |
變數
儲存資料的地方
int a;
型別
名稱
可以想成「記憶體中的某個放東西的位置」
有了變數可以做什麼?
運算子(operator)
- 對資料進行某種操作和改變
- 每個型別能用的運算子和功能不太一樣
int 的運算子
名稱 | 功能 |
---|---|
賦值(=) | 將左邊的變數數值改成右邊的 |
加(+) | 略 |
減(-) | 略 |
乘(*) | 略 |
除(/) | 會自動取下高斯喔 |
模運算(%) | a % b 為 a 除 b 的餘數 |
扣的
int a = 2, b = 0;
a = a + 5 * 6 / 7 % 3;
b += a;
a += b;
cout << a << " " << b << endl;
現在 a, b 是多少呢?
char 的運算
其實跟int 差不多?
C++ 的字元是從ASCII 編碼實作,因此每個字元對應到一個數字(中文沒有喔)。
char c = 'a';
cout << c + 1 << endl; //b
bool 的概念
bool 是布林值(boolean)的縮寫,其實就只是true 跟 false 的狀態,常用來判斷條件等。
bool 運算子
名稱 | 簡介 | 舉例 |
---|---|---|
and (&&) | 左右都是true | true && true == true, false && true == false |
or (||) | 其中一個true | true || false = true, false || false = false |
not (!) | 反過來 | !true = false, !false = true |
xor (^) | 左右不相同 | true ^ false = true, true ^ true = false |
基本輸入輸出
選擇結構(if/else)
要怎麼做判斷?
if (條件成立) {
//執行程式
} else if (上面不成立時下面成立) {
//...
} else {
//前面都不符合時
}
這三個都可以自由拼湊喔(除了if 一定要寫XD)
條件式
裡面其實是一個布林值!C++會判斷裡面的東西是不是 true。
==
(不是表情符號)
判斷左右兩個東西是否相同。是的話回傳true, 否則回傳false.
int a = 5, b = 5;
if (a == b) {
cout << "7122" << endl;
}
其他關係運算子
名稱 | 功能 | 舉例 |
---|---|---|
!= | 判斷兩者是否不同 | 5 != 8 |
< | 左<右 | 7 < 9 |
<= | 左<=右 | -5 <= -5 |
> | 略 | 6 > 4 |
>= | 略 | 8 >= 8 |
實作time!
Q1: 輸入兩個數字a, b,判斷a是不是b的整數倍。
Q2: 輸入兩個年齡a, b,如果有一者大於等於18而另一個小於18、或兩者小於16,輸出"FBI OPEN UP"。否則輸出"LEGAL"
(這題敘...)
迴圈
有一些東西要重複很多次,甚至不知道要做幾次,怎麼辦?
用迴圈!!!
while 迴圈
while (條件成立) {
//做事
}
飯粒
int a = 5;
while (a > 0) {
cout << a << endl;
a = a - 1;
}
for 迴圈
有點像是while 的進階版!
不覺得剛剛的code 可以再簡單點嗎?
與髮
for (起始條件; 判斷條件; 更新動作) {
//做事
}
舉個例子吧!
for (int i = 0;i < 10;i++) {
cout << i * i << endl;
}
for 迴圈疊for 迴圈...
大家要記得,上面寫的這些東西都可以重複堆疊喔!
for (int i = 0;i < 10;i++) {
for (int j = 0;j < 10;j++) {
cout << i * 10 + j << endl;
}
}
如果要讓東西重複n次呢?
int n;
cin >>n;
for (int i = 0;i < n;i++) {
}
現在,你已經會寫基本的程式了!
來練習吧!
Q1: 讓使用者輸入一個數字,程式輸出該數字四捨五入至十位數的結果。
ex. 輸入 7122, 輸出 7120
輸入 8, 輸出 10
Q2: 輸入一個整數,判斷該數字是不是質數。如果是的輸出 YES, 否則輸出 NO
Q3: 輸入一個整數 n,輸出1~n 的所有質數,並在最後輸出總共有幾個。
P.S. 這題注意一下執行效率喔!(n <= 100000)
Q4: 輸入兩個整數,輸出他們的最大公因數和最小公倍數。
一些第二位學長喜歡
但是不在他範圍講不到的東西
還很毒
Visual Studio Code
毒瘤
#include <bits/stdc++.h>
這個蠻好用的w
#if 0
#endif
這什麼鬼==
//*
//*/
蛤
int foo{} ;
殺蛇
#define
scope
Switch
不是遊戲機
陣列
以下講者腦補
某學弟:
我想要統計誰會來陽光宅男杯。
#include <bits/stdc++.h>
int main(){
bool num1 ;
bool num2 ;
bool num3 ;
bool num4 ;
bool num5 ;
}
好累喔
程式真爛,這麼麻煩
C++之神:
我聽到你的心聲了
#include <bits/stdc++.h>
int main(){
bool num[31] ;
}
學弟:好,我知道你很神了
但是怎麼用
像這樣,一個變數當火車頭,後面跟著車廂
好,那怎麼去到車廂?
#include <bits/stdc++.h>
int main(){
bool num[31] ;
num[3] = true ;
}
注意!火車頭自己也是一節車廂
#include <bits/stdc++.h>
int main(){
bool num[31] ;
num[0] = true ;
}
數字代表你要去火車頭"後"第幾節車廂
注意!!!
C++規定每一節車廂類型都要一樣(方便管理)
Python的車廂可以不一樣,所以管理不易
後來,學弟有了新夢想:
我要幫全校統計新生訓練有誰會來!!
但是學弟不知道每一班分別有幾人,於是
#include <bits/stdc++.h>
int main(){
int amount ;
std::cin >> amount ;
bool num[amount] ;
}
萬萬不可!!!
回到火車的例子
火車只能在發車時改變車廂數目
如果中途改變會怎樣? 很亂!!
看看隔壁的C
學弟:但是我真的很想
其實你直接照上面那樣寫不會出錯,因為編譯器知道這世界上就是有這種懶人,所以偷偷讓你用
但是我覺得不好,因為有些編譯器沒那麼貼心。
解方:Vector!!
#include <bits/stdc++.h>
int main(){
int amount ;
std::cin >> amount ;
std::vector<bool> num ;
num.reserve(amount) ;
}
Vector是什麼?
vector是一位工人,告訴你貨物在哪個火車上,
順便幫你搬貨物
火車滿了裝不下,怎麼辦?
再找一輛更長的火車,把貨物搬到新的火車上,完成!
而且這個工人很聰明,會幫你自動判斷。
那上面的num.reserve()在幹嘛
我們先告訴工人我們要的火車有多長
這樣他就不用把貨搬來搬去
比較省時間
實作
Q1 https://zerojudge.tw/ShowProblem?problemid=a104
hint : std::sort
我戳題技巧很爛
Q2 http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b005
green judge 超優
陣列
陣列
陣列
陣列
陣列
陣列
學弟:C++好爛,Excel比它好用多了
Excel兩個方向都有格子,C++的陣列只有1個方向,爛死了
陣列的真諦
你知道陣列的每一格也可以是陣列嗎
要包幾層就包幾層!!!
還敢說Excel好呀?
那要怎麼包?
#include <bits/stdc++.h>
int main(){
int a_list[5][7] ; //我包2層
int b_list[7][12][2] ; //我包3層
}
// 記得,陣列的每一格都要長一樣!
到底是誰包誰?
int b_list[7][12][2] ;
b_list有7格,每一格又有12小格,一小格又有2區
實作
Q2 寫一個2層vector的結構
函數
殘酷的事實
所有能用函數完成的東西,用迴圈也可以
那我學函數幹嘛
方便,簡潔,你以後會明白
學弟:我想知道任意數字的倒數是多少
#include <bits/stdc++.h>
int main(){
float a ;
std::cin >> a ;
std::cout << 1.0/a ;
}
另一位學弟:哇! 這程式好棒,我要放在我的程式裡! 但是我應該要複製哪一塊?
聰明的學弟把他的程式變成了函式
float rev(float x){
return 1.0/x ;
}
於是另一位學弟完成了\( \frac 1 {\frac 1 a + \frac 1 b} \) 的程式
#include<bits/stdc++.h>
float rev(float x){
return 1.0/x ;
}
int main(){
float a,b ;
std::cin >> a >> b ;
std::cout << rev(rev(a)+rev(b)) ;
}
那不用函式會怎樣?
#include<bits/stdc++.h>
int main(){
float a,b
std::cin >> a >> b ;
cout << 1.0/(1.0/a+1.0/b) ;
}
好像反而更簡潔?
先別管那個了,讓我教你怎麼寫函式
//↓ 每個函式都要告訴電腦,他會傳哪種資料回來
int main(/* 函式應該知道的東西,叫參數 */){
//函式的內容
return 0 ;
//每個函式最後都要return
}
//example
bool big(int a, int b){
if (a > b) return true ;
else return false ;
}
大發現! int main(){}竟然也是函式
所以其實你早就會函式了喔!
怎麼用?
#include <bits/stdc++.h>
bool big(int a, int b){
if (a > b) return true ;
else return false ;
}
int main(){
int x = 5, y = 7 ;
cout << big(x,y) ; //false
//就這麼簡單!
}
實作
老實說 我覺得沒有什麼好做的
Q1 寫一個"上高斯" 函數
Q2 寫一個可以在指定陣列的最尾端加值的函數
多型與重載
毒瘤,有時間再講
遞迴
學弟:我要計算費氏數列!
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155
(oeis A000045)
好難算喔,請電腦幫幫幫我!!
只要寫一個函式,可以執行
\( F_n = F_{n-1} + F_{n-2} \) 就好了
int f(int index){
if (index == 0 || index == 1) return 1 ;
return f(index-1)+f(index-2) ;
}
這就是遞迴
當然,迴圈也做得到
而且這方法更快
int f[100]{1,1} ;
for(int i = 2 ; i <= n ; i++){
f[i] = f[i-1] + f[i-2] ;
}
Why?
方法1
方法2
via http://mshang.ca/syntree/
同樣的東西 盡量避免重複算
實作
Q1 費氏數列 n<=50
hint: 拿前一項x0.618
Q2 n層河內塔 PTJ 我就爛
Q3 費氏數列 n < 1e6 模998244353
我不會用ojdl 我就爛
字串
字元
就是一個字元
char c='a'
//字元以單引號' '夾住
ASCII Code
每個字元都有一個數字編碼
其他語言也有自己的編碼如:中文的big-5,unicode
字串
C字串(字元陣列)
很多個字元組成的陣列
對陣列的操作都可以適用
但我沒有要講這個
char str[20]="Hello, world!";
//字串用雙引號" "夾住
cout<<str[4];
// o
string
需引入標頭檔<cstring> (萬用標頭檔也有)
算是vector的特化,功能跟vector有點像
也跟vector一樣可變長度
#include<cstring>
string s="Hello, world!";
cout<<s[4];
// o
字串的讀入
看到換行或空白就會停止
若想要一次讀一行,可使用getline
string s;
cin>>s;
cout<<s<<endl;
// input: Hello, world!
// output: Hello,
getline(cin,s);
cout<<s<<endl;
// input: Hello, world!
// output: Hello, world!
字串的操作
賦值: =
合併: +
比較: == 、 > 、 <
比較的東西: 字典序
只有string可以用這些運算子,字元陣列不行
有趣的東西
stringstream
功能類似將一整行讀進來後,再以空白分開(?
在某些輸入格式很毒瘤的題目或許會有奇效
int main(){
string s,tmp;
getline(cin,s);
stringstream ss(s);
while(ss>>tmp){
cout<<tmp<<endl;
}
return 0;
}
練習:字串反轉
練習:凱薩加密
指標
當我們需要交換兩個變數...
void swap(int x,int y){
int tmp=x;
x=y;
y=tmp;
}
int main(){
int x,y;
cin>>x>>y;
swap(x,y);
cout<<x<<" "<<y<<endl;
}
有什麼問題?
當我們需要交換兩個變數...
呼叫函數時,程式實際做的事是把x和y複製一份,然後交換
主程式中的x和y,其實沒有真正交換到
指標:儲存記憶體位址
int x = 3; //一個整數變數
int *p = &x;
// int *p: 整數型別的指標
// &x: 取x變數的記憶體位址
int* p; //也可以這樣
int *a, *b; //a,b都是指標
int* a, b; //只有a是指標
取址與取值
int x = 3; //一個整數變數
int *p = &x;
// int *p: 整數型別的指標
// &x: 取x變數的記憶體位址
cout<<(*p)<<endl;
// *p: 該記憶體位址儲存的值
// (其實就是x)
回到剛剛的問題
void swap(int *x,int *y){
int tmp=*x;
*x=*y;
*y=tmp;
}
int main(){
int x,y;
cin>>x>>y;
swap(&x,&y);
cout<<x<<" "<<y<<endl;
}
要這樣寫
或是這樣
void swap(int &x,int &y){
int tmp=x;
x=y;
y=tmp;
}
int main(){
int x,y;
cin>>x>>y;
swap(x,y);
cout<<x<<" "<<y<<endl;
}
int &x: 參照
可以想像成他就是把東西丟進去了
好麻煩?
使用全域變數
不要自己寫swap
指標的一些用途
當函數傳入引數
當陣列索引值
void print_arr(int* x,int cnt){
for(int i=0;i<cnt;i++){
cout<<*(x+i)<<endl;
}
}
指標的一些用途
動態宣告記憶體(new)
把一串東西用指標串起來
之後可能會講到
struct node{
int val;
node* next;
node(int v){
val=v;
}
};
node *root, *nd = new node(7122);
root->next = nd;
自定義資料型別
就是struct啦
然後struct和class有哪些不同
當一個東西有不同屬性
而你想把他們綁在一起時:
struct score{
int math;
int eng;
bool pretend_weak;
};
當一個東西有不同屬性
存取屬性就這樣寫
struct score{
int math;
int eng;
bool pretend_weak;
};
int main(){
score myscore;
myscore.math=71;
myscore.eng=22;
}
關於他的一些操作
可以包函式
struct score{
int math;
int eng;
bool pretend_weak;
score(int m,int e){
math=m;
eng=e;
if(math<60||eng<60){
pretend_weak=true;
}
else{
pretend_weak=false;
}
}
};
int main(){
score myscore=score(87,78);
score yourscore=score(71,22);
cout<<myscore.pretend_weak<<endl; //false
cout<<yourscore.pretend_weak<<endl; //true
}
一些應用
指標線段樹!
當你宣告一個變數時,你不想直接存取他,而是透過指標指向他的方式存取的話,就可以用new動態宣告變數
注意:如果本身是指標的話,存取屬性要用 ->
struct node{
int val;
node* next;
node(int v){
val=v;
}
};
node *root, *nd = new node(7122);
root->next = nd;
cout<<root->next->val<<endl; //7122
資訊競賽簡介
先來玩玩吧
重要比賽們
校隊初選
北市賽
全國賽(前十進選訓)
TOI初選
選訓
IOI
次要比賽們
HP codewars
NPSC
YTP
ISSC(?
Google code jam
......
Online Judge 們
是什麼應該不用多講(?
zerojudge
greenjudge
UVa
codeforces
TIOJ
ojdl
.......
正式資訊讀書會
- 對象:全體高一生(有人要幫忙宣傳嗎@@
- 時間:每周二下午6:00-9:00
- 地點:資源大樓三樓 電腦教室三
- 授課內容:演算法競賽相關
2020暑假資讀
By jass921026
2020暑假資讀
- 716