Dev-C++
codeblocks
#include <iostream>
using namespace std;
int main(){
cout << "Hello, world!\n";
}
建議全部自己打一次
引入已經寫好的程式 像cout
把std::cout變成cout
程式一開始進入的地方
儲存資料的東西
整數
範圍:
~
佔用空間: 4 Bytes
浮點數
精準至小數點後七位
佔用空間: 4 Bytes
字元
佔用空間: 1 Bytes
用ASCII碼儲存
' '表示一個字元
整數
範圍:
~
佔用空間: 4 Bytes
浮點數
精準至小數點後七位
佔用空間: 4 Bytes
字元
佔用空間: 1 Bytes
用ASCII碼儲存
' '表示一個字元
字串
可以儲存多個字元
" "表示一個字串
布林(真假)值
儲存true(1)和false(0)
佔用空間: 1 Bytes
//變數型別 變數名稱;
int x = 0;
float y = 1.5;
char c = 'c';
bool b = 1;
string s = "Hello, world!";
#inculde<iostream>
using namespace std;
int main(){
int a, b;
cin>>a>>b;
cout<<"a:"<<a<<" b:"<<b<<'\n';
}
int x;
x = 3;
x = 2 + 5;//x = 7
x = x - 1;//x = 6
x = 3 * x;//x = 18
x = x / 5;//x = 3
x = x % 3;//x = 0
+ 加
- 減
* 乘
% 取餘
/ 除
整數/整數是取商
= 指定
()括號
int x;
x = 3;
cout<<x++<<'\n';//cout 3, x = 4
cout<<++x<<'\n';//cout 5, x = 5
x -= 1;
x *= 3;
x %= 2;
++ 遞增
-- 遞減
運算後指定
< 小於
> 大於
<= 小於等於
>= 大於等於
==相等
(注意不是=)
!=不相等
if(條件){
你要執行的東西
}
例如:
int a = 5, b = 4;
if(a > b){
cout<<"a > b\n";
}
&& 邏輯AND
|| 邏輯OR
! 邏輯NOT
AND和OR可以用來連接兩個條件
A&&B | B = TRUE | B = FALSE |
---|---|---|
A = TRUE | TRUE | FALSE |
A = FALSE | FALSE | FALSE |
A||B | B = TRUE | B = FALSE |
---|---|---|
A = TRUE | TRUE | TRUE |
A = FALSE | TRUE | FALSE |
- | A = TRUE | A = FALSE |
!A | false | true |
int a;
cin>>a;
if(4 <= a && a < 7){
cout<<"4 <= a < 7\n";
}
if(4 <= a < 7){
cout<<"4 <= a < 7\n";
}
/*當上方的if(else if)的條件判斷是false時
才會判斷(執行)下面的else if(else)*/
int a, b;
cin>>a>>b;
if(a>b){
cout<<"a>b\n";
}
else if(a<b){
cout<<"a<b\n";
}
else{
cout<<"a==b\n";
}
INPUT
OUTPUT
75 90 80 70 60
66 80 68 67 66
99 100 98 50 40
乙
丙
甲
讓程式重複執行
while
int i,n;
cin>>n;
i=0;
while(i<n){
cout<<i<<' ';
i++;
}
while(條件){
要執行的東西;
}
int n;
cin>>n;
for(int i=0;i<n;i++){
cout<<i<<' ';
}
for(第一次進入;條件;每次結束){
}
1
3
2
4
5
int n;
cin>>n;
while(1){
cout<<i++<<' ';
if(i>=n) break;
}
跳出迴圈
輸入
如果 是奇數
如果 是偶數
輸出過程中 的數值直到
INPUT
3
4
OUTPUT
3 10 5 16 8 4 2 1
4 2 1
一連串的變數
宣告方式:
陣列變數型別 陣列名稱[陣列大小];
範例:
int array[100];
陣列是從零開始
使用方式:
陣列名稱[編號]
範例:
int array[100];
array[0] = 5;
0 1 2
利用迴圈的計數器當作索引
範例:
輸入n個數,並存在陣列中
#include<iostream>
using namespace std;
int main() {
int n, a[100];
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
}
INPUT
第一行有兩個正整數n q
第二行有n個整數代表數列A的值
接下來有q行,每一行有兩個正整數i j
代表要交換的數的編號
編號從1開始
OUTPUT
輸出操作後的數列
給一個數列A,接著有q個操作每次操作會交換數列裡的兩個編號的數,在最後輸出操作後的數列
5 4
5 4 2 3 1
1 3
1 2
3 4
1 5
1 2 3 5 4
眾數的定義是在一個數列A出現次數最多的數
給定一個數列並找出它的眾數
INPUT
第一行一個正整數n代表數列A長度
第二行有n個數,代表數列A的值
OUTPUT
輸出眾數
5
3 2 2 2 1
10
9 9 8 3 4 7 1 3 4 9
2
9
回傳資料型別 函數名稱(參數資料型別 參數名稱, ...){
執行的程式碼
可用return回傳並結束函數
}
#include<iostream>
using namespace std;
int f(int a, int b){
return a + b;
}
int main(){
int x, y;
cin >> x >> y;
cout << f(x, y) << '\n';
}
透過函數可以把整個程式分成多個函數
讓程式比較好閱讀
也比較好debug
可以把多個變數和函式包在裡面
class 物件名稱{
public:
包含變數
...
};
#include<iostream>
using namespace std;
class Student{
public:
string name;
int mandarin_score, math_score, english_score;
};
#include<iostream>
using namespace std;
class Student{
public:
string name;
int mandarin_score, math_score, english_score;
};
int main(){
Student student1;
}
#include<iostream>
using namespace std;
class Student{
public:
string name;
int mandarin_score, math_score, english_score;
};
int main(){
Student student1;
student1.name = "Scott";
}
#include<iostream>
using namespace std;
class Student {
public:
string name;
int mandarin_score, math_score, english_score;
int sum() {
return mandarin_score + math_score + english_score;
}
double avg() {
return (double)sum() / 3;
}
};
int main() {
Student student1;
student1.name = "Scott";
student1.mandarin_score = 80;
student1.english_score = 75;
student1.math_score = 90;
cout << student1.sum() << ' ' << student1.avg() << '\n';
}
階乘
\(n! = 1 * 2 * 3 ... * (n - 1) * n\)
定義函式\(f(n)\)為n!的值
\(n! = n * (n - 1)!\)
用遞迴表示\(f(n)\)
\(f(n) = f(n - 1) * n\)
\(f(3) = f(2) * 3\)
\(f(2) = f(1) * 2\)
\(f(1) = f(0) * 1\)
\(f(0) = f(-1) * 0\)
......\(\infty\)
寫出來看看
設結束條件
定f(1) = 1
\(f(3) = f(2) * 3\) = 6
\(f(2) = f(1) * 2\) = 2
\(f(1) = 1\)
範例測資
輸入:5 輸出:120
輸入:8 輸出:40320
#include<iostream>
using namespace std;
int f(int n) {
if (n == 1)
return 1;
return n * f(n - 1);
}
int main() {
int x;
cin >> x;
cout << f(x) << '\n';
}
範例測資
輸入:5 輸出:5
輸入:9 輸出:34
#include<iostream>
using namespace std;
int f(int n) {
if (n == 1)
return 1;
if (n == 2)
return 1;
return f(n - 1) + f(n - 2);
}
int main() {
int x;
cin >> x;
cout << f(x) << '\n';
}
有a, b, c三根桿子,一開始有N個盤子由大到小往上疊,問最少要花多少步才能把所有盤子從a桿子移到c桿子。
#include<iostream>
using namespace std;
int f(int n) {
if (n == 1)
return 1;
return f(n - 1) * 2 + 1;
}
int main() {
int x;
cin >> x;
cout << f(x) << '\n';
}
可以把每一個數字分為拿和不拿,透過遞迴跑過每個可能的狀況。
遞迴枚舉
給一個有長度為n的整數陣列a,計算其中有多少種組合的和等於k。
#include<iostream>
using namespace std;
int n, k, ans = 0, a[30];
void f(int i, int sum = 0) {
if (i == n) {
if (sum == k)
ans++;
return;
}
f(i + 1, sum + a[i]);
f(i + 1, sum);
}
int main() {
cin >> n >> k;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
f(0);
cout << ans << '\n';
}
a524
6 3 8 0 9 => 0 3 6 8 9
6 3 8 0 9 => 0 3 6 8 9
找到最大的數,放到最後面
找到最大的數,放到最後面
看相鄰兩個,如果順序相反就交換
找到最大的數,放到最後面
看相鄰兩個,如果順序相反就交換
一個一個把數字插入到正確的位置
#include<algorithm>
預設從小到大
不包含
起始指標
結尾指標
排序範圍
有一個陣列a, 要排序a[0]~a[n - 1]
#include<iostream>
#include<algorithm>
using namespace std;
int a[200005];
bool cmp(int a, int b) {
return a > b;
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n, cmp);
for (int i = 0; i < n; i++) {
cout << a[i] << ' ';
}
cout << '\n';
}
有沒有一個策略可以讓你有在最差情況下,猜的次數最少?
假設要猜的範圍是\(0\)~\(2^{31} - 1\)
最多只需要猜31次!
用數學算算看
每次找搜尋陣列範圍的中間位置
如果他比你的目標大,就往左找
如果他比你的目標小,就往右找
遞迴想法
設函式\(f(l, r, val)\)為整數\(val\)在陣列a[\(l\)~ \(r\)]區間中的位置
#include<iostream>
#include<algorithm>
using namespace std;
int a[200005];
int f(int l, int r, int val) {
if (l == r) {
if (a[l] == val)
return l;
else
return -1;
}
int mid = (l + r) / 2;
if (a[mid] == val)
return mid;
else if (a[mid] > val)
return f(l, mid - 1, val);
else
return f(mid + 1, r, val);
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n);
int q;
cin >> q;
cout << f(0, n - 1, q) << '\n';
}
#include<iostream>
#include<algorithm>
using namespace std;
int a[200005];
int f(int l, int r, int val) {
while (l < r) {
int mid = (l + r) >> 1;
if (a[mid] == val)
return mid;
else if (a[mid] < val)
l = mid + 1;
else
r = mid - 1;
}
if (a[l] == val)
return l;
return -1;
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n);
int q;
cin >> q;
cout << f(0, n - 1, q) << '\n';
}
#include<algorithm>
lower_bound(開始位置, 結束位置, 要找的值):
找第一個大於等於的
upper_bound(開始位置, 結束位置, 要找的值):
找第一個大於的
在變數前加上&符號就是他的指標
int a = 5;
cout << &a << '\n';
008FFCFC
用於儲存變數的記憶體位置的變數
變數型別 *變數名稱;
int a = 5;
int *p = &a;
取得儲存的記憶體位置上的變數
int a = 5;
int *p = &a;
cout << *p << '\n';
*p = 4;
cout << *p << '\n';
幫變數取一個新名字
int a = 5;
int& b = a;
cout << b << '\n';
b = 3;
cout << a << '\n';
new 變數型別
int *p;
p = new int;
設初始值
int *p;
p = new int(100);
int *p = new int(100);
delete p;
可以快速插入或刪除一個數
#include<iostream>
using namespace std;
class list{
public:
list* next;
int val;
};
list* root=new list;
int main(){
int n,i;
list* now=root;
cin>>n;
for(i=0;i<n;i++){
cin>>now->val;
now->next=new list;
now=now->next;
}
now=root;
for(i=0;i<n;i++){
cout<<now->val<<' ';
now=now->next;
}
}
#include<iostream>
using namespace std;
class list{
public:
list* next;
int val;
};
list* root=new list;
void list_insert(list* now){
list* t=now->next;
now->next=new list;
now=now->next;
now->next=t;
}
void list_erase(list* now){
now->next=now->next->next;
}
#include<iostream>
using namespace std;
int main()
{
int n;
cin >> n;
cout << n << '\n';
return 0;
}
執行次數: 3
#include<iostream>
using namespace std;
int main()
{
for(int i = 0; i < 10; i++){
cout << i << '\n';
}
}
執行次數: 31
#include<iostream>
using namespace std;
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++){
cout << i << '\n';
}
}
執行次數: \(3n+2\)
#include<iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int a = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
a++;
}
}
cout << a << '\n';
return 0;
}
執行次數: \(9n^2 + 3n + 4\)
\(3\)
\(31\)
\(3n + 2\)
\(9n^2 + 3n + 4\)
\(O(1)\)
\(O(1)\)
\(O(n)\)
\(O(n^2)\)
#include<iostream>
using namespace std;
int a[10005];
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
}
int search;
while(cin >> search){
bool found = 0;
for(int i = 0; i < n; i++){
if(search == a[i]){
cout << i << '\n';
found = 1;
break;
}
}
if(!found){
cout << -1 << '\n';
}
}
}
如果他第一個就找到
那他是不是\(O(1)\)?
#include<iostream>
using namespace std;
int a[10005];
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
}
int search;
while(cin >> search){
bool found = 0;
for(int i = 0; i < n; i++){
if(search == a[i]){
cout << i << '\n';
found = 1;
break;
}
}
if(!found){
cout << -1 << '\n';
}
}
}
如果他第一個就找到
那他是不是\(O(1)\)?
估算時間複雜度時
要用最差狀況評估
\(O(1)\)
\(O(logn)\)
\(O(\sqrt{n})\)
\(O(n)\)
\(O(nlogn)\)
\(O(n\sqrt{n})\)
\(O(n^2)\)
\(O(n^3)\)
\(O(2^n)\)
快
慢
\(O(n\log^2n)\)
\(O(n \log n + q \log n)\)
#include <iostream>
using namespace std;
int main()
{
char a[20];
cin >> a;
for (int i = 0; i < strlen(a); i++) {
cout << (char)(a[i] + 1);
}
return 0;
}
引入函式庫:vector
宣告方式:vector<陣列變數型別> 陣列名稱
取值方式:跟陣列一樣
\(O(1)\)
\(O(1)\)
\(O(1)\)
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> a;
a.push_back(5);
a.push_back(3);
a.push_back(4);
cout << a.size() << '\n'; //輸出3
cout << a[1] << '\n'; //輸出3
a.pop_back();
cout << a.size() << '\n'; //輸出2
}
引入函式庫:stack
宣告方式:stack<變數型別> 名稱
\(O(1)\)
\(O(1)\)
\(O(1)\)
\(O(1)\)
#include <iostream>
#include <stack>
using namespace std;
int main()
{
stack<int> s;
s.push(0);
s.push(1);
cout << s.size() << '\n'; //輸出2
cout << s.top() << '\n'; //輸出1
s.pop();
cout << s.top() << '\n'; //輸出0
}
引入函式庫:queue
宣告方式:queue<變數型別> 名稱
\(O(1)\)
\(O(1)\)
\(O(1)\)
\(O(1)\)
\(O(1)\)
引入函式庫:deque, stack, queue都可以
宣告方式:deque<變數型別> 名稱
\(O(1)\)
\(O(1)\)
\(O(1)\)
\(O(1)\)
\(O(1)\)
\(O(1)\)
\(O(1)\)
stack:
zj b923
zj c123
zj a565
zj e924
queue:
zj e447
進階題:
tcirc judge d028
tcirc judge d029
反覆運算器
用法跟指標差不多
宣告方式
STL的模板名稱::iterator 變數名稱;
vector<int>::iterator p;
可使用++移動到下一位,--移動到上一位
也可以使用prev()和next()
因為變數名稱太長,可以在有初始值時使用auto
vector<int> v;
auto p = v.begin();
引入函式庫:set
宣告方式:set<int> 名稱
\(O(1)\)
\(O(logn)\)
\(O(logn)\)
\(O(logn)\)
\(O(logn)\)
練習題:
zerojudge f607
引入函式庫:map
宣告方式:map<鍵的型別, 值的型別> 名稱
可以把它當陣列用
map<string, int> m;
m["ten"] = 10;
m["five"] = 5;
cout << m["ten"] + m["five"] << '\n';
\(O(1)\)
\(O(logn)\)
\(O(logn)\)
\(O(logn)\)
\(O(logn)\)
引入函式庫:queue
宣告方式:priority_queue<int> 名稱(最大)
priority_queue<int, vector<int>, greater<int> > 名稱(最小)
\(O(1)\)
\(O(1)\)
\(O(logn)\)
\(O(logn)\)
練習題:
zerojudge b606
operator
回傳型別 operator要重載的運算子(運算子需要的參數){
}
struct A{
int x, y;
};
bool operator<(A a, A b) {
if (a.x != b.x)
return a.x < b.x;
return a.y < b.y;
}