1. 程式人生 > >2018年物聯網學生科協軟體第二次培訓總結

2018年物聯網學生科協軟體第二次培訓總結

2018年物聯網學生科協軟體第二次培訓總結

文章目錄

一、陣列----多資料儲存

1. 陣列的定義

陣列是c語言中的一種複合資料型別,是相同資料型別的有序集合。

2. 陣列的宣告

資料型別 陣列名[下標個數];

int array[100];
double d_array[30];

3. 陣列的初始化

(1).

    int arr1[3] = {1, 2, 3};
    int arr2[] = {1, 2, 3};   //在這裡,我們arr[3]裡邊的數字可以不用寫

(2).

	int arr2[3] = {1, 2};       //也是可以的,注意最後一個數初始化為0

(3).

	int arr3[3] = {1, 2, 3, 4}; //錯誤,不能超過陣列長度

4. 陣列中元素的訪問

通過陣列下標來訪問每個元素

int a[5]={1,2,3,4,5};
a[0]=1;    //a[0]為陣列中的首個元素
a[1]=2;
a[2]=3;
a[3]=4;
a[4]=5;

小程式碼示例:

int score[10];  //儲存10個整型值的陣列
int count = 10;  //學生人數
printf("Enter the 10 scores: \n");
for(int i=0; i< count; i++) 
{       
    scanf(“%d”, &score[i]);  //從鍵盤讀入一個分數並存到數組裡 
}

5.陣列的記憶體分配

    int a[100];
    double b[30];
    printf("%d\n",sizeof(a));    //400
    printf("%d",sizeof(b));      //240

當編譯器對以上程式碼進行編譯時,就會為陣列分配記憶體單元。 假設計算機指定陣列score中的元素從地址為1000的地方開始存放。
具體分配原理如下圖所示:在這裡插入圖片描述

二、數值交換問題

1. 最常用的方法----建立臨時變數

小程式碼示例:

int a=10,b=20,temp;
temp = a;
a = b;
b = temp;
printf("%d%d", a,b);

2. 數學計算的方法

小程式碼示例:

int a =10, b = 20;
a = a - b;
b = a + b;
a = b - a;
printf("%d%d", a, b);

缺點:兩個數的和可能會越界,適用於兩個比較小的數

3. 異或運算的方法

小程式碼示例:

int a =10, b = 20;
a = a^b;
b = a^b;
a = a^b;
printf("%d%d", a, b);

思路:將a,b轉換為二進位制數(10 = 01010,20 = 10010)
按位異或(兩個值相同為0,不同為1)

4. 陣列換標不換值的方法

小程式碼示例:

int a=10,b=20;
int array1[2] = {10,20};  //存a、b
int array2[2] = {0,1};    //存下標
b = array1[array2[0]];
a = array1[array2[1]];
printf("%d%d",a,b);

思路:用陣列元素作為陣列的下標,這種方法換邏輯不換儲存

三、 基本的排序演算法

1. 氣泡排序(升序)

基本操作:比較陣列中相鄰的元素。如果這個數比它後一個大,就交換它們兩個。
第一步:從陣列第一和第二個元素(第一對)開始,執行基本操作,直到陣列末尾的兩個元素(最後一對)。這樣執行一遍後,最後的元素會是陣列中最大的數。
第二步:重複基本操作,但每次操作的元素會少一個(因為執行完n次操作後,前n個最大的元素會被排好序),直到沒有任何一對數字需要比較。氣泡排序完成。

小程式碼示例:

#include<stdio.h>
int main(){
    int a[5] = {2,3,4,1,6};
    int i, j, temp;
    for (j = 0; j < 4; j++)
        for (i = 0; i < 4 - j; i++){
            if(a[i] > a[i + 1]){
                temp = a[i];
                a[i] = a[i + 1];
                a[i + 1] = temp;
            }
        }
    for(j = 0; j < 5; j++){
        printf("%d ",a[j]);
    }
    return 0;
}

2. 選擇排序(升序)

基本操作:每次找出操作序列中最小的數放到最前面。
第一步:第一次操作遍歷整個序列,將最小的元素放到首位。
第二步:重複基本操作,第n次操作從序列第n個元素開始遍歷序列,將最小的元素放到序列第n個位置。直到某次操作序列中沒有元素可以遍歷。選擇排序完成。

圖解如下:
在這裡插入圖片描述
小程式碼示例:

#include<stdio.h>
int main(){
    int a[5] = {2,3,4,1,6};
    int i, j, temp;
    //每一次都找出最小的放到前面
    for(i = 0; i < 4; i++)
    {
        min = i;     //查詢最小值的下標
        for(j = i+1; j < 5; j++)
            if(a[min] > a[j])
                min = j;   //交換最小值的下標

        //判斷一下最小的是不是自身,如果不是則交換位置
        if(min != i)  
        {
            temp = a[min]; 
            a[min] = a[i];
            a[i] = temp;
        }
    }
    for(i=0;i<5;i++){
        printf("%d",a[i]);
    }
}

3. 插入排序(升序)

基本操作:將有序序列的後一個元素插入到序列當中,使其依然有序。
第一步:假設初始時有序序列中只有第一個元素,此時執行基本操作,會將第二個元素排好序。此時有序序列中有兩個元素。
第二步:重複基本操作,有序序列的長度不斷增加。當有序序列中的元素個數和原序列相等時,即所有元素均有序排列時,插入排序完成。

圖解如下:
在這裡插入圖片描述
小程式碼示例:

#include<stdio.h>
int main(){
    int i, j, temp;
    int a[5] = {2,3,4,1,6};
    for(i = 1 ;i < 5 ; i++){
        temp = a[i];
        for(j = i ; j>0 && a[j-1]>temp ; j--)
            a[j] = a[j-1];
        a[j]=temp;
    }
    for(i=0;i<5;i++){
        printf("%d",a[i]);
    }
    return 0;
}

四、 字元與字串

1. 字元的概念

字元型資料包括 字元常量字元變數

(1). 字元常量:

  • 概念
    是單引號括起來的一個字元。例如:‘a’、‘b’、‘=’、‘?’都是合法的字元常量。
  • 特點
    ①字元常量只能用單引號括起來,不能用雙引號或者其他字元;
    ②字元常量只能是單個字元,不能是字串;
    ③字元可以是字符集中的任意字元,但數字被定義為字元型之後不能參與數值的運算。(比如:‘3’和3)
  • 特殊的字元常量
    在上次培訓我們提到的轉義字元是一種特殊的字元常量,其具有特定的含義不同於字元原有的意義即為”轉義”。
    圖!

(2). 字元變數:

  • 字元型變數用來儲存字元資料,即單個字元。
  • 字元變數的型別說明符是char。
    注意: ①每個字元變數被分配一個位元組的記憶體空間,因此只能存放一個字元;
    程式碼小示例:
	char a='h';
    printf("%d",sizeof(a));     //1

字元值是以ASCII碼的形式存放在變數的記憶體單元之中的。
在這裡插入圖片描述

2. 字元的輸入與輸出

char ch;
scanf(“%c”,&ch);
printf(“%c”,ch);

小練習: 輸入一個字母,將其大寫轉小寫,小寫轉大寫。

小程式碼示例:

#include<stdio.h>
int main(){
    char a;
    scanf("%c",&a);
    if(a>=65&&a<=90)
        a += 32;
    else if(a>=97&&a<=122)
        a -= 32;
    printf("%c",a);
    return 0;
}

3. 字串的概念

從形式上看,一個字串就是用一對雙引號括起來的一串字元,其雙引號是該字串的起,止標誌符,它不屬於字串本身的字元。
例:
“string”
“物聯網院學生科協”

4. 字串的初始化

字元型陣列表示字串

char[]=“iotesta”
char b[20]=“I love esta”
Char str[6]={‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’}

注意: 在進行逐個元素初始化時,必須明確寫出字串結束符’\0’

5. 字串的輸入與輸出

scanf(“%s”,str);   //(注意!不用寫&)
printf(“%s”,str);

小練習:輸入一個字串,將其大寫轉小寫,小寫轉大寫。

小程式碼示例:

#include<stdio.h>
int main(){
    int i;
    char a[12]="iLoVEesTA";
    for(i=0;i<12;i++){
        if(a[i]>=65&&a[i]<=90)
            a[i] += 32;
        else if(a[i]>=97&&a[i]<=122)
            a[i] -= 32;
    }
    printf("%s",a);
    return 0;
}

6. 關於字串的常用函式

函式:函式是一個封裝一個功能的程式碼塊,便於重複使用。主要是傳入引數,獲得返回值,或者在函式內對引數進行操作。其中關於字串的常用函式都在<string.h>標頭檔案裡,即在使用時要在最上面加上 #include<string.h>

(1). 求字串長度----strlen函式

int strlen (const char s[ ]); 

①功能:計算字串的長度

②返回值:返回字串的實際長度,不包括‘\0’在內

③注意:在求字串長度的過程中,遇到字串‘\0’就結束,只計算起始位置到‘\0’前面的字元個數,例如:strlen(“AB\0CD\0EF”)的結果是2

sizeof()與strlen()函式的區別:
sizeof()計算的是系統為變數分配的記憶體空間的大小,會加上隱藏結束符的長度。

(2). 字串拷貝

  • strcpy函式
char* strcpy (char *s1, const char *s2);

①功能:將字串s2複製到s1指定的地址(即將字串s2拷貝到s1中去)

②返回值:字串s1的首地址。

③注意:字串s1必須是陣列或者已經分配空間的字元型指標,並且空間足夠大,該函式不分配空間;拷貝時‘\0’一同被拷貝;不能使用賦值語句給一個字元陣列賦值;

  • strncpy函式
char* strncpy (char *s1, const char *s2, int n);

功能:將s2的前n個字元複製到s1中對應的地址, 並在末尾加‘\0’ ;

(3). 字串連線----strcat函式

char* strcat (char *s1, const char *s2);

①功能:將字元陣列s2連線到字元陣列s1尾部
②說明:字元陣列s1必須空間足夠大(s1的儲存空間≥strlen(s1)+strlen(s2)+1),連線前,兩串均以‘\0’結束,連線後,串s1原來的‘\0’被覆蓋,新得到的字串最後加‘\0’;呼叫此函式後,s1的長度等於s1、s2兩個字串長度之和。

小程式碼示例:

	char a[20]="Hello";            //字串長度為5
    char b[ ]="World";             //字串長度為5
    strcat(a," ");                //連線一個空格到a串之後
    strcat(a,b);                  //把b串連線到a串之後
    printf("%s %d",a,strlen(a));

//執行該程式的輸出結果是: Hello World 11

(4). 字串比較----strcmp函式

int strcmp (const char *s1, const char *s2);

①功能:比較字串s1和s2。
②比較規則:對兩個串從左向右逐個字元比較(ASCII碼),直到遇到不同的字元或者‘\0’為止;
③返回值:返回int型整數。
(1)若s1 < s2,返回負整數;
(2)若s1 > s2,返回正整數;
(3)若s1 = s2,返回零;
注意: 字串比較不能用“==”,必須用strcmp;


以上函式的綜合使用
小程式碼示例:

    char str1[10];
    char str2[10];
    scanf("%s%s",str1,str2);
    
    //求字串的長度
    printf("%d %d\n",strlen(str1),strlen(str2));
    
    //字串連線
    strcat(str1,str2);
    printf("%s\n",str1);
    
    //字串拷貝
    strcpy(str1,str2);
    printf("%s\n",str1);
    
    //字串比較
    printf("%d\n",strcmp(str1,str2));

五、有趣的小演算法

貪心演算法

貪心演算法(又稱貪婪演算法)是指,在對問題求解時,總是做出在當前看來最好的選擇。也就是說,將整體最優問題分解為區域性來考慮,做出的是在某種意義上的區域性最優解。

貪心選擇 — 第一個基本要素

貪心選擇是指,所求問題的整體最優解可以通過一系列區域性最優的選擇來達到。
對於一個具體問題,要確定它是否具有貪心選擇的性質,我們必須證明每一步所作的貪心選擇最終能得到問題的最優解。通常可以首先證明問題的一個整體最優解,是從貪心選擇開始的,而且作了貪心選擇後,原問題簡化為一個規模更小的類似子問題。

  • 貪心演算法相關經典問題:
    貨幣選擇問題、揹包問題、區間排程問題、字典序最小問題

小練習: 雙11已經不遠了,但一橙小萌新很苦惱,因為他每個月的15號才能收到生活費。為了解決這個問題,他決定提前向媽媽索要11月份的生活費,但他的媽媽卻沒有那麼容易將錢給他。媽媽說:你不是在學程式設計嗎?那你告訴我,如果接下來幾個月的生活費我都不用移動支付的方式,而是以紙幣的形式給你,我最少要準備多少張人民幣呢?你回答出來就提前給你11月份的生活費,否則你雙11就別買東西了!
一橙小萌新想買的羅技滑鼠在購物車裡很久了,要是錯過雙11就太悲傷了,你們快幫幫他吧!(假設每個月的生活費是整數。人民幣一共有100元、50元、10元、5元、2元和1元六種)。

Input
輸入資料第1行是一個整數n(n<100),表示接下來的n個月,第2到第n+1行每行一個數,表示每個月一橙小萌新的生活費。
Output
輸出一個整數x,表示至少需要準備的人民幣張數。每個輸出佔一行。
Sample Input
3 1 2 3
Sample Output
4

小程式碼示例:

while(scanf("%d",&n)!=EOF&&n!=0)
    {
        sum=0;
        for(i=0; i<n; i++)
        {
            scanf("%d",&m);
            sum+=m/100;
            m%=100;
            sum+=m/50;
            m%=50;
            sum+=m/10;
            m%=10;
            sum+=m/5;
            m%=5;
            sum+=m/2;
            m%=2;
            sum+=m;
        }
        printf("%d\n",sum);
    }

思路:從大面值鈔票往下選,便是最少的張數。

貪心演算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無後效性,即某個狀態以前的過程不會影響以後的狀態,只與當前狀態有關。