胡凡演算法筆記---第二章 C/C++快速入門
第二章 C/C++快速入門
下面介紹C語言相關內容,先來看一段C語言小程式:
#include <stdio.h>
int main() {
int a, b;
scanf("%d%d", &a, &b);
printf("%d", a+b);
return 0;
}
這個程式分為兩個部分:標頭檔案和主函式。
1.標頭檔案
在上面的程式碼中,#include<stdio.h>這一行就是標頭檔案。其中,stdio.h是標準輸入輸出庫,如果在程式中需要輸入輸出,就需要加上這個標頭檔案。 stdio的全稱是standard input output,h就是head的縮寫,.h是標頭檔案的檔案格式。 既然stdio.h是負責輸入輸出,那麼自然還會有負責其他功能的標頭檔案。例如,math.h負責一些數學函式,string.h 負責跟字串有關的函式,則只需要在需要使用對應的函式時,將它們的標頭檔案包含到這個程式中來即可。 此外,在C++的標準中,stdio.h更推薦使用等價寫法: cstdio,也就是在前面加一個c,然後去掉.h即可。所以#include<stdio.h>和#include<cstdio>的寫法是等價的,#include<math.h>和#include<cmath>等價,#include <string.h>和#include <cstring>也等價。
2.主函式
int main(){
...
return 0;
}
上面的程式碼就是主函式。主函式是一個程式的入口位置,整個程式從主函式開始執行。一個程式最多隻能有一個主函式。
int a, b;
這句話定義了兩個變數a和 b,型別是int 型(簡單來說就是整數)。
scanf("%d%d", &a, &b);
scanf用來讀入資料,這條語句以%d的格式輸入a和 b,其中%d就是 int型的輸入輸出標識。簡單來說,就是把a和 b作為整數輸入。
printf("號d",a+b);
printf用來輸出資料,這條語句計算a + b並以%d格式輸出。上面說過,%d就是int型的輸入輸出標識,所以就是把a+b作為整數輸出。因此這段程式碼的主函式實現了輸入兩個數a和 b然後輸出a+b的功能。
接下來進入正題,講解一下C語言中各個需要使用的語法。
宣告:下文使用的程式碼請儲存成.cpp檔案(即C++檔案),然後選擇C++語言(或C++)進行提交。由於C++向下相容C,因此採用這種方式可以儘可能防止一些因C與C++之間的區分而導致的編譯錯誤。
2.1 基本資料型別
2.1.1 變數的定義
變數是值可以改變的量,需要定義後才能使用,定義格式如下:
變數型別 變數名;
變數型別 變數名 = 初值;
定義要求:
- 不能是C語言識別符號
- 變數名的第一個字元必須是字母或下劃線,除第一個字元之外的其他字元必須是字母、數字或下劃線
- 區分大小寫
2.1.2 變數型別
1.整型
- int 32bit
int num;
- long long int 64bit
long long bigNum;
long long bigNum = 1234567890123456LL
%d是int型的輸出格式
2.浮點型
- 單精度float 32bit
float f1;
float f1 = 3.1415;
2.雙精度double 64bit
double db;
double db = 3.141592653589;
浮點型相關程式:
#include <stdio.h>
int main() {
double a = 3.14, b = 0.12;
double c = a + b;
printf("%f", c);
return 0;
}
%f是float和double型的輸出格式
對於浮點型來說,不要使用float,碰到浮點型的資料都應該使用double來儲存
3.字串常量
字串是由若干字元組成的串,在C語言中沒有單獨一種基本資料型別可以儲存(C++中有string型別),只能使用字元陣列的方式。
#include <stdio.h>
int main() {
char str1[25] = "Wo ai de ren bu ai wo";
char str2[25] = "So sad a story it is.";
printf("%s, %s", str1, str2);
return 0;
}
4.布林型
bool變數:true,false
#include <stdio.h>
int main() {
char str1[25] = "Wo ai de ren bu ai wo";
char str2[25] = "So sad a story it is.";
printf("%s, %s", str1, str2);
return 0;
}
2.1.3 強制型別轉換
格式如下:
(新型別名) 變數名
案例說明:
#include <stdio.h>
int main() {
double r = 12.56;
int a = 3, b = 5;
printf("%d\n", (int)r);
printf("%d\n", a / b);
printf("%.1f", (double)a / (double)b);
return 0;
}
2.1.4 符號常量和const常量
符號常量即用一個識別符號來替代常量,又稱為“巨集定義”或者“巨集替換”,其格式如下:
#define 識別符號 常量
#define pi 3.14
const 資料型別 變數名 = 常量;
const double pi = 3.14;
#define 識別符號 任何語句或片段
#define ADD(a, b) (a) + (b)
可以直接使用ADD(a, b)來替代a+b 的功能
2.1.5 運算子
運算子就是用來計算的符號。常用的運算子有算術運算子、關係運算符、邏輯運算子、條件運算子、位運算子等。
1.算術運算子
算術運算子有很多,比較常用的是下面幾個:
+加法運算子:將前後兩個數相加。
–減法運算子:將前後兩個數相減。
*乘法運算子:將前後兩個數相乘。
/除法運算子:取前面的數除以後面的數得到的商。
%取模運算子:取前面的數除以後面的數得到的餘數。
++自增運算子:令一個整型變數增加1.
--自減運算子:令一個整型變數減少1。
2.關係運算符
常用的關係運算符共有六種:<、>、<=、>=、--、!=
3.邏輯運算子
常用的邏輯運算子有三種:&&、l|、!,分別對應“與”“或”“非”
4.條件運算子
A ? B : C
2.2 順序結構
2.2.1 賦值表示式
int n = 5;
n = 6;
2.2.2 使用scanf和printf輸入/輸出
1.scanf函式的使用
scanf("格式控制", 變數地址);
scanf("%d", &n);
2.printf函式的使用
printf("格式控制", 變數名稱);
int n = 5;
printf("%d", n);
2.2.3 使用getchar和putchar輸入/輸出字元
getchar用來輸入單個字元,putchar用來輸出單個字元,在某些scanf函式使用不便的場合可以使用getchar來輸入字元。
#include <stdio.h>
int main() {
char c1, c2, c3;
c1 = getchar();
getchar();
c2 = getchar();
c3 = getchar();
putchar(c1);
putchar(c2);
putchar(c3);
return 0;
}
2.2.4 註釋
(1)多行註釋:"/**/"
(2) 單行註釋:”//“
2.2.5 typedef
typedef能給複雜的資料型別起別名,在使用中可以用別名來替代原來的寫法。
2.2.6 常用math函式
1.fabs(double x)
該函式用於對double型變數取絕對值
2.floor(double x)和cell(double x)
這兩個函式分別用於double型變數的向下取整和向上取整,返回型別為double型
3.pow(double r, double p)
該函式用於返回 r 的 p次方,要求 r 和 p都是double型
4.sqrt(double x)
該函式用於返回doublc型變數的算術平方根
5.log(double x)
該函式用於返回double型變數的以自然對數為底的對數
#include <stdio.h>
#include <math.h>
int main() {
double db = log(1.0);
printf("%f", db);
return 0;
}
6.sin(double x)、cos(double x)和tan(doubel x)
這三個函式分別返回double型變數的正弦值、餘弦值和正切值,引數要求是弧度制
7.asin(double x)、acos(double x)和atan(double x)
這三個函式分別返回double型變數的反正弦值、反餘弦值和反正切值
8.round(double x)
該函式用於將double型變數x四捨五入,返回型別也是double型,需進行取整
2.3 選擇結構
2.3.1 if語句
if(條件A){
....
}
2.3.2 if語句的巢狀
if(條件A){
...
if(條件B){
...
}else{
...
}
...
}
2.3.3 switch語句
switch(表示式){
case 常量表達式1:
...
break;
case 常量表達式2:
...
break;
default:
...
}
2.4 迴圈結構
2.4.1 while迴圈
while(條件A){
....
}
2.4.2 do···while語句
do{
...
}while(條件A);
2.4.3 for語句
for(表示式A; 表示式B; 表示式C){
.....
}
①在for迴圈開始前,首先執行表示式A。
②判斷表示式B是否成立:若成立,執行省略號內容;否則,退出迴圈。
③在省略號內容執行完畢後,執行表示式c,之後回到②。
為了理解上面的格式,下面舉一個較為常用的特例:
for(迴圈變數賦初值; 迴圈條件; 迴圈變數改變){
.......
}
2.4.4 break和continue語句
break:退出當前迴圈,執行剩下的語句
continue:退出本次迴圈,然後進去下一個輪迴
2.5 陣列
2.5.1 一維陣列
陣列就是把相同資料型別的變數組合在一起而產生的資料集合。
資料型別陣列名[陣列大小];注意:
陣列大小必須是整數常量,不可以是變數。
int a[10];
double str[233];
陣列訪問:
陣列名稱[下標]
2.5.2 氣泡排序
排序是指將一個無序序列按某個規則進行有序排列,而氣泡排序是排序演算法中最基礎的一種。現給出一個序列a,其中元素的個數為n,要求將它們按從小到大的順序排序。氣泡排序的本質在於交換,即每次通過交換的方式把當前剩餘元素的最大值移動到一端,而當剩餘元素減少為0時,排序結束。
#include <stdio.h>
int main() {
int a[10] = {3, 1, 4, 5, 2};
for(int i = 1; i <= 4; i++) { //進行 n - 1次
//第i趟時從a[0]到a[n - i -1]都與它們下一個數比較
for(int j = 0; j < 5 - i; j++) {
if(a[j] > a[j + 1]) {
//如果左邊的數更大,則交換a[j]和a[j + 1]
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
for(int i = 0; i < 5; i++) {
printf("%d", a[i]);
}
return 0;
}
2.5.3 二位陣列
資料型別陣列名[第一維大小] [第二維大小];
int a[5][6];
double db[10][10];
訪問:陣列名[下標1] [下標2]
2.5.4 memset----對陣列中每一個元素賦相同的值
memset 函式的格式為:
memset(陣列名,值,sizeof(陣列名));
2.5.5 字元陣列
1.字元陣列的初始化
char str[15] ={'G','o','o','t','o', 'r','y','!'};
2.字元陣列的輸入輸出
(1)scanf輸入,printf輸出
(2)getchar輸入,putchar輸出
(3)gets輸入,puts輸出
3.字元陣列的存放方式
由於字元陣列是由若干個 char 型別的元素組成,因此字元陣列的每一位都是一個char字元。除此之外,在一維字元陣列(或是二維字元陣列的第二維)的末尾都有一個空字元\0。
2.5.6 string.h標頭檔案
1.strlen()
strlen 函式可以得到字元陣列中第一個\0前的字元的個數,其格式如下:
strlen(字元陣列):
2.strcmp()
strcmp函式返回兩個字串大小的比較結果,比較原則是按字典序,其格式如下:
strcmp(字元陣列1,字元陣列2)
3.strcpy()
strcpy函式可以把一個字串複製給另一個字串,其格式如下:
strcpy(字元陣列1,字元陣列2)
注意:是把字元陣列⒉複製給字元陣列1,這裡的“複製”包括了結束符\0。
4.strcat()
strcat()可以把一個字串接到另一個字串後面,其格式如下:
strcat(字元陣列1,字元陣列2)
注意:是把字元陣列2接到字元陣列1後面,示例如下:
2.5.7 sscanf與sprintf
sscanf與 sprintf是處理字串問題的利器,讀者很有必要學會它們( sscanf從單詞上可以理解為string + scanf,sprintf則可以理解為string + printf,均在stdio.h標頭檔案下)。
2.6 函式
2.6.1 函式的定義
基本語法格式:
返回型別 函式名稱(引數型別 引數){
函式主體
}
2.6.2 再談main函式
主函式對一個程式來說只能有一個,並且無論主函式寫在哪個位置,整個程式一定是從主函式的第一個語句開始執行,然後在需要呼叫其他函式時才去呼叫。
int main(){
...
return 0;
}
2.6.3 以陣列作為函式引數
函式的引數也可以是陣列,且陣列作為引數時,引數中陣列的第一維不需要填寫長度(如果是二維陣列,那麼第二維需要填寫長度),實際呼叫時也只需要填寫陣列名。最重要的是,陣列作為引數時,在函式中對陣列元素的修改就等同於是對原陣列元素的修改(這與普通的區域性變數不同)
2.6.4 函式的巢狀呼叫
函式的巢狀呼叫是指在一個函式中呼叫另一個函式,呼叫方式和之前main函式呼叫其他函式是一樣的。
2.6.5 函式的遞迴呼叫
函式的遞迴呼叫是指一個函式呼叫該函式自身。
2.7 指標
2.8 結構體(struct)的使用
2.8.1 結構體的定義
定義一個結構體的基本格式如下:
struct Name{
//一些基本的資料結構或者自定義的資料型別
};
# 初始化
struct Name{
//一些基本的資料結構或者自定義的資料型別
}Name1, Name2;
需要注意的是,結構體裡面能定義除了自己本身(這樣會引起迴圈定義的問題)之外的任何資料型別。不過雖然不能定義自已本身,但可以定義自身型別的指標變數。例如:
struct node {
node n; //不能定義node型變數
node next;//可以定義node*型指標變數
};
2.8.2 訪問結構體內的元素
訪問結構體內的元素有兩種方法:“.”操作和“->”操作。
2.8.3 結構體的初始化
1.定義時初始化
定義一個studentInfostu的結構體變數,然後對其中的元素逐一賦值,以達到初始化的目的,示例如下:
stu.id =1;
stu.gender ='M”;
或者在讀入時進行賦值;
scanf("%d 號c",&stu .id, &stu.gender);
2.建構函式
所謂建構函式就是用來初始化結構體的一種函式,它直接定義在結構體中。建構函式的一個特點是它不需要寫返回型別,且函式名與結構體名相同。
struct studentInfo{
int id;
char gender;
//預設生成的建構函式
studentInfo(){};
};
建構函式簡化成一行:
studentInfo(int _id, char _gender): id(_id), gender(_gender){}
# 賦值
studentInfostu = studentInfo(10086,"M');
注意:如果自己重新定義了建構函式,則不能不經初始化就定義結構體變數,也就是說,預設生成的建構函式“studentInfo(){}”此時被覆蓋了。為了既能不初始化就定義結構體變數,又能享受初始化帶來的便捷,可以把“studentInfo{}”手動加上。
2.9 補充
2.9.1 cin與cout
1.cin
cin是c和 in的合成詞,採用輸入運算子“>>”來進行輸入。可以發現,cin的輸入不指定格式,也不需要加取地址運算子&,直接寫變數名就可以了。如果同時讀入多個變數也是一樣的寫法,只需要往後面使用>>進行擴充套件即可。
int n;
cin >> n;
2.cout
cout是c和 out的合成詞,其使用方法和 cin幾乎是一致的,只不過使用的是輸出運算子<<。
對cout來說,換行有兩種方式:第一種和C中相同,也就是使用n來進行換行;第二種方法則是使用endl 來表示換行(endl是 end line的縮寫):
2.9.2 浮點數的比較
1.等於運算子(==)
2.大於運算子(>)
3.小於運算子(<)
4.大於等於運算子(>=)
5.小於等於運算子(<=)
6.圓周率Π
2.9.3 複雜度
1.時間複雜度
簡單地說,時間複雜度是演算法需要執行基本運算的次數所處的等級,其中基本運算就是類似加減乘除這種計算機可以直接實現的運算。時間複雜度是評判演算法時間效率的有效標準。在時間複雜度中,高等級的冪次會覆蓋低等級的冪次。
2.空間複雜度
和時間複雜度類似,空間複雜度採用相同的寫法,表示演算法需要消耗的最大資料空間。
3.編碼複雜度
編碼複雜度是一個定性的概念,並沒有什麼量化的標準。對一個問題來說,如果使用了冗長的演算法思想,那麼程式碼量將會非常巨大,其編碼複雜度就會非常大。
2.10 黑盒測試
2.10.1 單點測試
對單點測試來說,系統會判斷每組資料的輸出結果是否正確。如果輸出正確,那麼對該組資料來說就通過了測試,並獲得了這組資料的分值。在這種情況下,題目的總得分等於通過的資料的分值之和。PAT 就是採用了單點測試,並且對每組資料都會給出相應的測評結果。
2.10.2 多點測試
與單點測試相對,多點測試要求程式能一次執行所有資料,並要求所有輸出結果都必須完全正確,才能算作這題通過;而只要有其中一組資料的輸出錯誤,本題就只能得0分。
(1)while...EOF型
C語言中使用EOF(即End Of File)來代表-1
while(scanf("%d", &n) != EOF){
.....
}
(2)while....break型
這種型別是while.… EOF 型的延伸,題目要求當輸入的資料滿足某個條件時停止輸入。這種型別是while.… EOF 型的延伸,題目要求當輸入的資料滿足某個條件時停止輸入。
(3)while(T--)型
在這種型別中,題目會給出測試資料的組數,然後才給出相應數量組數的輸入資料。
#include <stdio.h>
int main(){
int T, a, b;
scanf("%d", &T);
while(T--){
scanf("%d%d", &a, &b);
printf("%d\n", a + b);
}
return 0;
}
以上就是多點測試的三種輸入型別。下面講解三種常見的輸出型別。
(1)正常輸出
這種輸出型別要求需要每兩組輸出資料中間沒有額外的空行,即輸出資料是連續的多行。
(2)每組資料輸出之後都額外加一個空行
這個要求非常容易實現,只需要在每組輸出結束之後額外輸出一個換行符n即可。
(3)兩組輸出資料之間有一個空行,最後一組資料後面沒有空行
這一般是在第三種輸入型別 while(T--)的情況下,只需要通過判斷T是否已經減小到0來判斷是否應當輸出額外的換行。
最後需要指出,在多點測試中,每一次迴圈都要重置一下變數和陣列,否則在下一組資料來臨的時候變數和陣列的狀態就不是初始狀態了,而重置陣列一般使用memset函式或f函式。
最後分享一首自己很喜歡的詩(姑且算是吧)。我欲乘風向北行,雪落軒轅大如席,我欲借船向東遊,綽約仙子迎風立,我欲踏雲千萬裡,廟堂龍吟耐我何,崑崙之巔沐日光,滄海絕境見青山,長風萬里燕歸來,不見天涯人不回。本文來自部落格園,作者:NotYourferry,轉載請註明原文連結:https://www.cnblogs.com/pinghuimolu/p/15163978.html