1. 程式人生 > 其它 >胡凡演算法筆記---第二章 C/C++快速入門

胡凡演算法筆記---第二章 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 變數的定義

變數是值可以改變的量,需要定義後才能使用,定義格式如下:

變數型別 變數名;
變數型別 變數名 = 初值;

定義要求:

  1. 不能是C語言識別符號
  2. 變數名的第一個字元必須是字母或下劃線,除第一個字元之外的其他字元必須是字母、數字或下劃線
  3. 區分大小寫

2.1.2 變數型別

1.整型

  1. int 32bit
int num;
  1. long long int 64bit
long long bigNum;
long long bigNum = 1234567890123456LL

%d是int型的輸出格式

2.浮點型

  1. 單精度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