0.展示PTA總分
0.1 一維數組
0.2 二維數組
0.3 字符數組
1.本章學習總結
1.1 學習內容總結
1.數組是最基本的構造類型,是一組相同類型數據的有序集合。
2.在程序中使用數組,可以讓一批相同類型的變量使用同一個數組變量名,用下標相互區分。
3.數組的優點是表達簡潔,可讀性好便於使用循環結構。
4.定義一個數組,需要明確數組變量名,數組元素的類型和數組的大小(即數組中元素的數量)。
5.一維數組定義的一般形式為:
類型名指定數組中每個元素的類型;
數組名是數組變量(以下簡稱數組)的名稱,是一個合法的標識符;
數組長度是一個整型常量表達式,設定數組的大小。
6.數組是一些具有相同類型的數據的集合,數組中的數據按照一定的順序排列存放。同一數組中的每個元素都具有相同的數據類型,有統一的標識符即數組名,用不同的序號即下標來區分數組中的各元素。
7.在定義數組之后,系統根據數組中元素的類型及個數在內存中分配了一段連續的存儲單元用於存放數組中的各個元素,並對這些單元進行連續編號,即下標,以區分不同的單元。每個單元所需的字節數由數組定義時給定的類型來確定。只要知道了數組第一個元素的地址以及每個元素所需的字節數,其余各個元素的存儲地址均可計算得到。
8.C語言規定,數組名表示該數組所分配連續內存空間中第一個單元的地址,即首地址。由於數組空間一經分配之后在運行過程中不會改變,因此數組名是一個地址常量,不允許修改。數組名是一個地址常量,存放數組內存空間的首地址。
9.定義數組后,C語言規定,只能引用單個的數組元素,而不能一次引用整個數組。
10.數組元素的引用要指定下標,形式為:
11.下標可以是整型表達式,它的合理取值范圍是[0,數組長度-1],下標不能越界,這些數組元素在內存中按下標遞增的順序連續儲存。
12.區分數組的定義和數組元素的引用:
兩者都要用到“數組名[整型表達式]“,定義數組時,方括號內是常量表達式,代表數組長度,它可以包括常量和符號常量,但不能包含變量。也就是說,數組的長度在定義時必須指定,在程序的運行過程中是不能改變的。而引用數組元素時,方括號內是表達式,代表下標,可以是變量,下標的合理取值范圍是[0,數組長度-1]。
13.對一維數組賦初值時,其一般形式為:
14.雖然C適言規定,只有靜態存儲的數組才能初始化,但一般的C編譯系統都允許對動態儲存的數組賦初值。
15.靜態存的數組如果沒有初始化,系統自動給所有的數組元素賦0。數組的初始化也可以只針對部分元素。
16.數組的應用離不開循環。
17.數組的長度在定義時必須確定,如果無法確定需要處理的數據數量,至少也要估計其上限,並將該上限值作為數組長度。
18.C語言支持多維數組,最常見的多維數組就是二維數組,主要用於表示二維表和矩陣。
19.二維數組定義的一般形式為:
20.引用二維數組的形式為:
21.由於二維數組的行(列)下標從0開始,而矩陣或二維表的行(列)從1開始,用二維數組表示二維表和矩陣時,就存在行(列)計數的不一致。為了解決這個問題,可以把矩陣或二維表的行(列)也看成從0開始,即如果二維數組的行(列)下標為k,就表示矩陣或二維表的第k行(列);或者定義二維數組時,將行長度(列長度)加1,不再使用數組的第0行(列),數組的下標就從1開始。一般都采取第一種方法。
22.二維數組的初始化方法有兩種:
①分行賦初值
②順序賦初值
23.將二維數組的行下標和列下標分別作為循環變量,通過二重循環,就可以遍歷二維數組,即訪問二堆數組的所有元素。由於二維數組的元素在內存中按行優先方式存放,當行下標作為外循環的循環變量,列下標作為內循環的循環變量,可以提高程序的執行效率。
24.在C語言中,字符串的存儲和運算可以用一維字符數組來實現、數組長度取上限80,以回車符'\n'作為輸入結束符。
25.字符串常量是用一對雙引號括起來的字符序列,它有一個結束標志'\0',整數0也代表字符'\0'。
26.初始一個字符串數組,如:
ps:三者等價
27.將字符串存入字符數組時,由於它有一個結束符”\0,數組長度至少是字符串的有效長度+1。
28.如果數組長度大於字符串的有效長度+1,則數組中除了存入的字符串,還有其他內容,即字符串只占用了數組的一部分。
29.字符串遇'\0'結束,所以第一個'\0'之后的其他數組元素與該字符串無關。
30.字符串由有效字符和字符串結束符'\0'組成。
31.區分”a”和’a’:前者是字符串常量,包括’a’和’\0’兩個字符,用一維字符數組存放;后者是字符常量,只有一個字符,可以給字符變量。
32.輸入的情況有些特殊,由於字符串結束符’\0’代表空操作,無法輸人,因此,輸入字符串時,需要事先設定一個輸入結束符。一旦輸入它,就表示字符串輸入結束,並將輸入結束符轉換為字符串結束符’\0’。
33.sizeof() 是計算所占用的空間字節大小。
34.strlen() 是計算字符串數組的長度,遇 0 則止。
35.數組中目前學到排序方法:
1>.冒泡排序
void bubbleSort(int a[], int n)
{
int i;
int j;
int n;
int temp;
for (i = 0; i < n; i++)
{
for (j = 0; j < n - 1; j++)
{
if (a[j] > a[j + 1])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
2>.選擇排序
void selectionSort(int a[], int n)
{
int i;
int j;
int temp;
for (i = 1; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
if (a[j] > a[i])
{
temp = a[j];
a[j] = a[i];
a[i] = temp;
}
}
}
}
36.數組中如何插入數據?
1>.輸入一個數據k,將數組中的數據與k逐一比較,如果大於k,記錄下數據的下標,然后此數據下標和其后的數據的下標都加一,相當於都向后挪一位,然后將k賦值給數組的那個下標
我的代碼
#include<stdio.h>
#include <string.h>
#define N 100
int main()
{
int n;//數組元素的個數
int a[N];
int i;
int j;
int k;//插入的數
scanf("%d\n", &n);
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
scanf("%d", &k);
for (i = 0; i < n; i++)
{
if (a[i] > k)
{
break;
}
}
for (j = n - 1; j >= i; j--)
{
a[j + 1] = a[j];
}
a[i] = k;
for (i = 0; i < n + 1; i++)
{
printf("%d ", a[i]);
}
return 0;
}
運行示例
2>.將要插入的數據放在數組最后,然后和前面的數據逐一比較,如果k小於某元素a[i],則將a[i]后移一個位置,否則將k至於a[i+1]的位置
我的代碼
#include<stdio.h>
#include <string.h>
#define N 100
int main()
{
int n;//數組元素的個數
int a[N];
int i;
int j;
int k;//插入的數
scanf("%d\n", &n);
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
scanf("%d", &k);
a[n] = k;
for (i = n - 1; i >= 0; i--)
{
if (a[i] > k)
{
a[i + 1] = a[i];
}
else
{
a[i + 1] = k;
break;
}
}
for (i = 0; i < n + 1; i++)
{
printf("%d ", a[i]);
}
return 0;
}
運行示例
37.數組中如何刪除數據?
#include<stdio.h>
#include <string.h>
#define N 100
int main()
{
int n;//數組元素的個數
int a[N];
int i;
int j;
int k;//進行k次刪除
int x;//每行要刪除第x個元素
int temp;
scanf("%d\n", &n);
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
scanf("%d", &k);
for (i = 0; i < k; i++)
{
scanf("%d", &x);
for (j = x; j < n; j++)
{
a[j - 1] = a[j];
}
}
for (i = 0; i < n - k; i++)
{
if (i == n - k - 1)
{
printf("%d", a[i]);
}
else
{
printf("%d ", a[i]);
}
}
return 0;
}
38.數組中如何查找數據?
1>.二分查找法
我的代碼
int dichotomySearch(int* a, int n, int x)
{
int left;
int right;
int mid;
left = 0;
right = n - 1;
while (left <= right)
{
mid = (left + right) / 2;//從中間開始
if (x == a[mid])
{
break;
}
else if (x < a[mid])
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
if (left <= right)
{
return mid; // 找到返回下標
}
else
{
return -1;//找不到返回 - 1
}
}
運行示例
2>.遍歷數組
我的代碼
#include<stdio.h>
#define N 10
int main()
{
int a[N] = { 1,2,3,4,5,6,7,8,9,10 };
int x;
int i;
int flag;
flag = 0;
scanf("%d", &x);//輸入要找的數
for (i = 0; i < N; i++)//遍歷數組
{
if (a[i] == x)
{
flag = 1;//找到則flag=1,退出循環
break;
}
}
if (flag == 1)
{
printf("下標:%d", i);
}
else
{
printf("NOT FOUND!");
}
return 0;
}
運行示例
39.數組做枚舉用法的案例:
題目
求整數序列中出現次數最多的數 (15 分)
本題要求統計一個整型序列中出現次數最多的整數及其出現次數。
代碼
#include<stdio.h>
#define N 1000
int main()
{
int n;
int a[N];
static int count[N];
int i;
int j;
int max;
int maxIndex;
scanf("%d", &n);
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
if (a[i] == a[j])
{
count[i]++;
}
}
}
max = count[0];
for (i = 1; i < n; i++)
{
if (max <= count[i])
{
max = count[i];
maxIndex = i;
}
}
printf("%d %d\n", a[maxIndex],max);
return 0;
}
40.哈希數組用法及目前學過的案例
用法
hash就是為了把一個復雜的字串,通過一定的轉換,得到一個簡單的數字,作為一個數組的下標來用。這樣的話,如果要去查詢一個字串是否存在,就不需要對一個數組使用字符串循環對比這樣的慢操作,而直接先得到某個字串的hash值,再用這個hash值,在數組下標里直接找,這樣速度要快上很多,特別是數據比較多的時候。
題目
有重復的數據I (10 分)
在一大堆數據中找出重復的是一件經常要做的事情。現在,我們要處理許多整數,在這些整數中,可能存在重復的數據。
你要寫一個程序來做這件事情,讀入數據,檢查是否有重復的數據。如果有,輸出“YES”這三個字母;如果沒有,則輸出“NO”。
代碼
#include<stdio.h>
#define Max 100001
int IsSame(int n);
int main()
{
int n;
scanf("%d", &n);
if (IsSame(n))
{
printf("YES");
}
else
{
printf("NO");
}
return 0;
}
int IsSame(int n)
{
int i;
int data;
static int hash[Max];
for (i = 1; i <= n; i++)
{
scanf("%d", &data);
if (hash[data] == 1)
{
return 1;
}
else
{
hash[data] = 1;
}
}
return 0;
}
1.2 本章學習體會
1.2.1 學習體會
- 在這一章的學習中,我學會了數組的使用方法,學會了將數據存入到數組中,但是數組這一章中的方法有很多,比如說冒泡排序,選擇排序等等,有時候寫代碼時還是比較混亂。
- 數組在寫的時候常常會因為for語句的條件而越界,或者是沒有用
static
初始化導致程序錯誤,輸出一堆亂碼。 - 這一章的PTA題目集比較多,難度也比較大,經常是一道題卡好幾天,提交列表里一片綠╮(╯▽╰)╭,需要思考思考再思考,整理整理框架,有時候只是一個
\n
或者數組的范圍再大一些的小細節方面的錯誤,有時候卻壓根兒找不出錯誤點在哪里╭(°A°`)╮。 - VS里有很多語法,在數組中經常會出現錯誤,不知道應該怎么去調整,但是在Dev-C++里可以,希望老師可以告訴一下怎么弄?_?。
1.2.2 代碼累計
我的代碼量(不包括重復)
周 | 代碼量(行) |
---|---|
4 | 241 |
5 | 506 |
6 | 771 |
7 | 842 |
8 | 793 |
9 | 724 |
10 | 1980 |
11 | 983 |
12 | 879 |
累計 | 8702 |
2.PTA實驗作業
2.1 題目名1
判斷E-mail地址是否合法 (20 分)
輸入一個字符串,判斷是否是合法郵箱(格式正確即可,不管是否真的存在)輸入的只能是字母、數字、下划線、@以及.五種, @前后只能是字母或者數字,而且.后只能是com, 是則輸出YES ,否則輸出NO。
2.1.1 偽代碼
定義i,j
定義k來儲存@的下標,m來儲存.的下標
定義flag1,flag2,flag3,flag4來儲存不同判斷的結果
定義num來儲存字符數量
定義字符數組str[]
定義len儲存真實的數組長度
給flag1,flag2,flag3,flag4,num賦初值
用gets(str)來輸入數組
用strlen函數來求出輸入的數組的長度
for i = 0 to i < N,i++
{
for j = 0 to j < N,j++
{
if ((str[i] == '@') && (str[j] == '.'))
{
k來儲存@的下標,m來儲存.的下標
for k = i to k < m,k++
{
if ((str[k] >= '0') && (str[k] <= '9') || (str[k] >= 'a') && (str[k] <= 'z') || (str[k] >= 'A') && (str[k] <= 'Z'))
{
flag1為1,即@前后只能是字母或者數字
}
}
}
}
}
if (str[len - 3] == 'c' && str[len - 2] == 'o' && str[len - 1] == 'm' && m == len - 4)
{
數組的長度的最后三位是com,倒數第四位是.,m是先前判斷出來的.的下標,所以flag2為1,即.后只能是com
}
for i = 0 to i < N,i++
{
if ((str[i] >= '0') && (str[i] <= '9') || (str[i] >= 'a') && (str[i] <= 'z') || str[i] == '_' || str[i] == '@' || str[i] == '.')
{
如果str數組中輸入的是字母或者數字或者下划線或者@或者.五種中的,則flag3=1
}
}
for i = 0 to i < len,i++
{
if (str[i] == ' ')
{
當檢測到有空格時,flag4 = 0
break;
}
else
{
沒有空格,則flag4 = 1;
}
}
if (flag1 == 1 && flag2 == 1 && flag3 == 1 && flag4 == 1)//前面四個條件都滿足
{
輸出YES
}
else
{
輸出NO
}
2.1.2 代碼截圖
2.1.3 造測試數據
輸入數據 | 輸出數據 | 說明 |
---|---|---|
adf12@qw213.com | YES | 正常數據,樣例 |
123qw 1@q.com | NO | 字符串中有空格 |
12q@w.com2 | NO | .com后有多余字符 |
12qwas.@com | NO | .@ |
142qht@.com | NO | @. |
654@@kjh.com | YES | @@ |
234jhs@uy..com | YES | .. |
hgjh hg com | 引發異常 | 空格無@. |
qw12 jhs.a.com | 引發異常 | 有空格多余的. |
f12@qw213.com&*# | NO | 合法地址后有非法字符 |
2.1.4 PTA提交列表及說明
提交列表說明:
1. 部分正確:字母數字下划線.@和樣例的測試點沒有過
2. 部分正確:有關空格的測試點沒有過,修改前用for循環輸入數組,而當修改后用fgets語句,前面沒有過的測試點過了,但是新出現了空格問題
3. 部分正確:判斷@前后只能是字母或者數字時增加了flag4語句,使循環嵌套過多,運行超時
4. 部分正確:通過strlen的函數確認輸入字符串的長度,然后再來判斷數組的最后4位是不是.com,所以又一個測試點過了
5. 部分正確:測試點9,11,12,即有關空格的測試點一直過不了,我用for循環來判斷是否有空格
6. 答案正確:當檢測到有空格時就需要退出循環,所以要加break語句,否則flag4的值會一直變,剛開始寫了這個for循環時沒有想到這一點
7. 編譯錯誤:寫注釋時發現n沒有用,然后刪除n的時候不小心把num也刪了
8. 答案正確:完善注釋,補回num
2.2 題目名2
閱覽室 (20 分)
天梯圖書閱覽室請你編寫一個簡單的圖書借閱統計程序。當讀者借書時,管理員輸入書號並按下S鍵,程序開始計時;當讀者還書時,管理員輸入書號並按下E鍵,程序結束計時。書號為不超過1000的正整數。當管理員將0作為書號輸入時,表示一天工作結束,你的程序應輸出當天的讀者借書次數和平均閱讀時間。
注意:由於線路偶爾會有故障,可能出現不完整的紀錄,即只有S沒有E,或者只有E沒有S的紀錄,系統應能自動忽略這種無效紀錄。另外,題目保證書號是書的唯一標識,同一本書在任何時間區間內只可能被一位讀者借閱。
2.2.1 數據處理
定義void函數AverageTime來統計借閱平均時間
定義n為天數
定義數組record[MAX][3],分為3列
定義number來存書號
定義hour存小時數
定義minute存分鍾數
定義字符op儲存E或S
定義i,j
定義k為數組行數
輸入正整數n(n ≤ 10),代表給出n天的紀錄
for i = 1 to i <= n,i++
{
給k賦初值
while(1)
{
輸入數據按照number op hour:minute
if (number為0時)
{
break;
}
record數組第一列存number書號
record數組第二列存op是E還是S
通過hour * 60 + minute公式把時間轉變為分鍾的格式,record數組第三列來存時間
k++,行數增加
}
調用函數AverageTime
}
}
void AverageTime(int record[][3], int k)//統計借閱平均時間的函數
{
定義i,j
定義count統計借書次數
定義float型avg統計平均時間
給count賦初值
給avg賦初值
for i = 0 to i < k,i++
{
if (record[i][1] == 'S')//找到第i行中為S的
{
for j = i + 1 to j < k,j++
{
if (書號一致且是有借書記錄)//同一本書被借閱多次,以最后一次借閱為准
{
break;
}
if (書號一致且有還書記錄)//判斷書號是否一致,后面是否有還書
{
借書次數count增加
算出總的時間avg
break;
}
}
}
}
if (count不為0,即這一天有借書)//防止除數為0
{
輸出讀者借書次數和平均閱讀時間
}
else
{
否則這一天沒有借書,輸出0 0
}
}
2.2.2 代碼截圖
2.2.3 造測試數據
輸入數據 | 輸出數據 | 說明 |
---|---|---|
![]() |
![]() |
題目樣例,有連續S和連續E |
![]() |
![]() |
同一本書被借多次 |
![]() |
![]() |
有不匹配 |
![]() |
![]() |
有S和E全反 |
2.2.4 PTA提交列表及說明
提交列表說明:
1. 答案錯誤:if語句中書號一致和借書還書這兩個條件的關系由於粗心寫成了或的關系
2. 答案正確:把代碼細細讀了一遍,改正了if語句中書號一致和借書還書這兩個條件的關系為且的關系,這道題在課堂上老師讓我們在課堂派的互動里寫過想法,當時我是在想字符,但是時間不知道如何輸入數組中,后來看了老師在超星平台上的視頻,頓時覺得,emmm,明白了
2.3 題目名3
大數加法 (20 分)
輸入2個大數,每個數的最高位數可達1000位,求2數的和。
2.3.1 數據處理
定義i,j
定義兩個字符數組str1,str2來儲存兩個大數
定義len1,len2用來儲存兩個大數的長度
定義兩個數組num1,num2來倒序存放兩個大數
定義bit來儲存大數之和的數組的最后一個下標
給i賦初值
給j賦初值
給bit賦初值
輸入第一個大數str1
輸入第二個大數str2
用strlen求第一個加數的位數,並且儲存到len1中
用strlen求第二個加數的位數,並且儲存到len2中
用strlen-1求兩個大數之和的數組的最后一個下標,並且儲存到bit中
if (bit < len2 - 1)//如果第二個大數的位數更多
{
bit變為更大的位數的下標
}
for i = len1 - 1 to i >= 0,i--
{
將第一個加數的字符數組轉化為數字數組,並倒數存放
j++
}
j重新賦為0
for i = len2 - 1 to i >= 0,i--
{
將第二個加數的字符數組轉化為數字數組,並倒數存放
j++;
}
for i = 0 to i <= 1000,i++
{
num1[i] = num1[i] + num2[i];
if (num1[i] > 9)//如果計算這一位的結果大於9,則需要進位
{
num1[i]減去10
且num1[i + 1]加1
}
}
if (num1[bit + 1] != 0)//根據同學告訴我的設置一個bit,記錄位數,然后就可以了
{
輸出num1[bit + 1]
}
for ; to bit >= 0,bit--
{
輸出 num1[bit]
}
2.3.2 代碼截圖
2.3.3 造測試數據
輸入數據 | 輸出數據 | 說明 |
---|---|---|
92345434336786876823540234787293542423 | ||
13343434323979878542919487294910345782 | 105688868660766755366459722082203888205 | 題目樣例 |
123456 | ||
11111111 | 11234567 | 位數比較少 |
111111111111111111111111 | ||
111111111111111111 | 111111222222222222222222 | 最高位沒進位 |
987654321 | ||
982345675 | 1969999996 | 最高位進位 |
4674892374353728743754765893921834783570754608 | ||
82172756576748748291948957658548784898384728357438 | 82177431469123102020692712424442706733168299112046 | 位數比較多 |
9999 | ||
99999 | 109998 | 最高位進位 |
2.3.4 PTA提交列表及說明
提交列表說明:
1. 編譯錯誤:gets在VS上應該用gets_s,在復制到PTA上時沒有改成gets
2. 部分正確:最高位沒進位正確
3. 答案錯誤:總是前面會少一位或者后面少
4. 答案錯誤:修正后算出的結果正確了,但是前面會有一堆0
5. 答案正確:根據同學告訴我的設置一個bit,記錄位數,然后就可以了
3.閱讀代碼
題目:ACM 題庫題解大全> poj 2635 The Embarrassed Cryptographer
題目截圖
題目翻譯
答案示例
代碼功能
輸入str數組和L,先判斷出數組中的數是哪兩個素數的乘積,然后再判斷其中一個因子嚴格小於所需的L,則程序應輸出“BAD p”,p是其中的最小因子,否則,程序應輸出“GOOD”。
代碼優點
1. 分裝函數的數量多,每個函數都有不同的作用
2. Check函數在不同的結果下返回了兩個值
3. 條件語句和循環語句運用熟練
4. 運用strlen()函數求數組長度,sizeof()函數求字節數
5. 邏輯思維很強,值得學習