物聯網技術部&祕書部第一次軟體培訓總結
物聯網技術部&祕書部第一次軟體培訓總結
文章目錄
一、二維陣列
1.定義
型別說明符 陣列名 [常量表達式1] [常量表達式2]
float a[3][4];
陣列中的元素為:
a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]
2.初始化
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int a[3][4]={{1},{0,6},{0,0,11}}; int a[3][4]={1,2,3}; int a[ ][3]={{1},{2},{3,4,5}}; //即 a[3][3] int a[ ][3]={1,2,3,4,5}; //即 a[2][3]
注意: 下標不能越界!
3.引用
陣列名[常量表達式1][常量表達式2]
//示例:
b[1][2] = a[2][3]/2
4.應用
請設計一個程式,將一個4行4列的二維陣列中行和列元素互換,並存放到另一個數組中。
小程式碼示例
//C語言
#include<stdio.h>
int main(){
int a[4][4] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14};
int t;
for (int i=0; i < 4; i++) {
for (int j = 0; j < 4; j++)
printf("%3d", a[i][j]);
printf("\n");
}
for (int i = 0; i < 4; i++)
for (int j = i + 1; j < 4; j++) {
t = a[i][j];
a[i][j]=a[j][i] ;
a[j][i] = t;
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++)
printf("%3d", a[i][j]);
printf("\n");
}
return 0;
}
// C++
#include<iostream>
#include<iomanip>
using namespace std;
int main(){
int a[4][4] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14};
int t;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++)
cout << setw(3) << setfill(' ') << a[i][j];
cout << endl;
}
for (int i = 0; i < 4; i++)
for (int j = i + 1; j < 4; j++) {
t = a[i][j];
a[i][j]=a[j][i] ;
a[j][i] = t;
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++)
cout << setw(3) << setfill(' ') << a[i][j];
cout << endl;
}
return 0;
}
二、指標
1.概念
變數的值: 變數所代表的記憶體單元中的內容
變數的地址: 該變數所佔儲存單元的首地址
指標: 一個變數的地址,一個記憶體單元的地址,通常是一個無符號整數
指標變數: 存放變數地址的變數
2.定義與使用
型別說明符 *變數名
int *i_pointer , i=10;
i_pointer=&i;
printf(“%d”,*i_pointer);
說明: * 解引用 & 取地址符
小程式碼示例:
int main(){
int i = 10;
int *p;
*p = i; //危險!
printf("%d", *p);
return 0;
}
注意: 指標變數必須先賦值,再使用!
3.指標與一維陣列
1)一維陣列的地址
2)關係
int a[10], *pa;
pa=a; pa =&a[0]; //等價
引用一個數組元素,有3種方法:
1)下標法: a[ i ]
2)陣列名地址法: * (a+i )
3)指標法:
①指標地址法: * (pa+i )
②指標下標法: pa[ i ]
4.指標與多維陣列
1)多維陣列的地址
int a[3][4]={0};
a代表二維陣列首行的首地址,記作a[0]或&a[0][0](現在的首元素不是一個簡單的整型元素,而是由4個整型元素所組成的一維陣列)
同理a+1為序號為1的行的首地址,記作a[1]==&a[1][0]
那1行1列的元素的地址? a[1]+1
2)關係
指向陣列元素的指標變數
int a[3][4]={0};
int *p;
p = a[0];
p++; //p可以向下移動,依次指向下一個元素
指向陣列的行指標變數
int a[3][4]={0};
int (*p)[4];
p = a;
a[i][j] == *(*(p+i)+j)
5.多級指標
如果指標變數中存放的是另一個指標變數的地址,就稱該指標變數為指向指標的指標變數,也稱為二級指標。
資料型別 **變數名
int i=10,*ptrch=&i;
int **pp=&ptrch;
6.malloc動態分配
void *malloc(unsigned int size);
int a[n]; !錯誤
int *a=(int *)malloc(n*sizeof(int));
//或
#define N 100
int a[N]
7.指標小應用
用指標改寫二維陣列中的矩陣轉置
int *p=a;
int (*q)[4]=a;
a[i][j] = p[i*n+j] = *(p+(i*n+j));
a[i][j] = q[i][j] = *(*(q+i)+j);
三、函式
1.定義與宣告
定義
型別名 函式名(形參表)
{
宣告部分
執行語句
}
宣告
型別名 函式名(形參表);
2.遞迴函式
如果一個函式在其函式體中直接或者間接地呼叫了自己,則該函式稱為遞迴函式。
直接呼叫自己為直接遞迴;間接呼叫自己為間接遞迴。
圖解如下:
1)從數學角度看遞迴
例如
等差數列:
首項,即第一項的值a1;
遞推公式,即連續項間的關係(an = an-1 +9)
當呼叫a(n)即執行a(n-1)+9,同時呼叫a(n-1)即a(n-2)+9……這樣一直下去,最後到首項時,不再呼叫函式,直接返回數值。此時一路反向加回去,結束遞迴。
圖解如下:
2)遞迴的注意點
1)結束條件:遞迴需要有明確的終止條件(首項)
2)逼近過程:處理好問題和子問題之間的關係,使得每次遞迴呼叫都要逼近終止條件
3)初始引數:呼叫遞迴函式的引數
3)遞迴的應用
1.請設計一個程式,利用遞迴求n!
小程式碼示例:
// C語言
#include<stdio.h>
int multiple(int n) {
if (n == 1)
return 1;
else
return n*multiple(n - 1);
}
int main() {
int n,m;
scanf("%d", &n);
m = multiple(n);
printf("%d", m);
return 0;
}
// C++
#include<iostream>
using namespace std;
int multiple(int n) {
if (n == 1) {
return 1;
}else {
return n*multiple(n - 1);
}
}
int main() {
int n,m;
cin >> n;
m = multiple(n);
cout << m;
return 0;
}
2.有一對兔子,從出生後第三個月起每個月都生一對兔子,小兔子長到第三個月後,每個月又生一對兔子。假設兔子都不死,問第20個月的兔子的對數為多少
小程式碼示例
// C語言
#include<stdio.h>
int birth(int n) {
int result;
if (n == 1)
result = 1;
else if (n == 2)
result = 1;
else if (n == 3)
result = 2;
else
result = birth(n-1)+birth(n-3);
return result;
}
int main()
{
int n,x;
scanf(“%d”,&n);
x=birth(n);
printf(“%d”,x);
return 0;
}
// C++
#include<iostream>
using namespace std;
int birth(int n) {
int result;
if (n == 1)
result = 1;
else if (n == 2)
result = 1;
else if (n == 3)
result = 2;
else
result = birth(n-1)+birth(n-3);
return result;
}
int main()
{
int n,x;
cin >> n;
x=birth(n);
cout << x;
return 0;
}
3.函式的優缺點
函式用於包裝一些程式碼片段,使得他能夠方便的被重複使用。
函式主要有以下的幾個優點:
1)函式是實現程式碼重用的一種方式
2)友好的函式名字便於傳達程式碼的含義
3)函式會簡化程式碼的實現,使思路更清晰
同時,函式主要也有以下的幾個缺點:
1)呼叫函式會時間和空間的消耗
2)遞迴函式擁有棧溢位的風險
四、OJ小技巧
1.關於輸入問題
1)做題的時候儘量使用scanf printf。cin cout比scanf printf慢20倍左右,一旦遇到大資料量,光是讀入就有可能跪掉。
2)scanf和cin混用可能就會造成一些奇怪的錯誤。
3)關於輸入多組資料
#include <stdio.h>
int main(){
int input;
while(scanf("%d",&input) != EOF) {
//在此處理資料
printf("%d\n",input);
}
return 0;
}
還可以:
while( ( scanf(“%d”,&a) ) != -1 )
while( ( scanf(“%d”,&a) ) == 1 )
while( ~( scanf(“%d”,&a) ) )
while(cin>>a) //C++
讀到一個0時,程式結束,可用:
while( scanf(“%d”,&a) ,a)
while( scanf(“%d”,&a) &&a!=0)
while (cin>>i,i) //C++
2.關於輸出格式(presentation error)
1)行末空格:比如我輸出需要列印多個數需要使用空格分隔的時候,我們迴圈使用printf(“%d “,x);這種會很方便,但是這樣會導致行末多一個空格,後臺系統會嚴格比對你的輸出和.out檔案,這樣也會被判錯誤
2)換行問題:對於每個樣例,建議輸出完全之後都換行一下。對於一些題目,可能就是不換行就導致了後面輸入資料錯位,那就肯定不可能過了。
3)大部分題處理一組資料後可直接輸出,不需要用陣列儲存每一個Case的資料。
3.關於陣列問題
1)陣列定義int a[10]={0};可以對其全部元素賦值為0;但是陣列太大不要這樣。
2)定義陣列時,陣列大小最好比告訴的最大範圍大一點。
3)字元陣列大小必須比字串最大長度大1。
4)處理字元陣列時不要忘了在最後加’/0’或者0。
4.關於Runtime error
1)下標越界
2)要表示的數值太大,超出了定義型別數的範圍。
3)未賦值的變數就直接使用
4)在無限遞迴或函式裡使用了太大的陣列變數
!一定要好好排查,不仔細一般找不出來。
5.關於字串
1)純字串用puts()輸出,會增快速度。
2)先用scanf(),再用gets()會讀入回車。要使用getchar()吸收空格和回車的錄入。
!使用c語言讀字元和字串一定要十分小心。儘量寫好就自己輸出一下看看是否是自己需要的值被讀入。
6.總結
1)輸入輸出是不是按照題意進行的。
2)是不是有些步驟沒有完成。
3)對於邊界輸入的檢查
4)演算法的複雜度是不是過高
牢記:
程式碼不通過肯定是自己哪裡出了什麼問題,檢查程式碼!再三看題讀懂題意!!!
7.OJ小例題
輸入
輸入包含多個測試用例。每個測試用例以數字N開始(0 < N <= 1000)——分佈的氣球總數。接下來的N行每一行都包含一種顏色。氣球的顏色是由15個小寫字母組成的字串。
輸出
對於每一種情況,列印氣球顏色最流行的問題在一行。保證每個測試用例都有唯一的解決方案。
sample input:
orange
orange
pink
red
blue
sample
output:
orange
程式碼小示例:
#include <stdio.h>
#include <string.h>
main(){
int n, i, j, t, max, num[1000];
char color[1000][16];
while(scanf("%d", &n) != EOF){
if(n){
num[0]=0;
scanf("%s", color[0]);
for(i=1; i <n; i++){
num[i]=0;
scanf("%s", color[i]);
for(j=0; j <i-1; j++)
if(strcmp(color[i], color[j])==0) num[i] +=1;
}
max=num[0];
t=0;
for(i=1; i <n; i++)
if(max <num[i]) {max =num[i]; t=i;}
printf("%s\n",color[t]);
}
}
}