數(shù)字的秘密問(wèn)題分析(C語(yǔ)言)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 原創(chuàng)---子衿兄
1
【問(wèn)題】
在數(shù)字王國(guó)中,人人都有一個(gè)號(hào)碼,人人想個(gè)號(hào)碼對(duì)自己意味著什么。國(guó)一他不是你做了很多個(gè)盒子,每個(gè)盒子擁有一個(gè)號(hào)碼。人們需要通過(guò)一定的方法才能確定哪個(gè)例子有自己的秘密。這個(gè)辦法就是把自己的數(shù)字N的全部因子相加求和。例如12,他因子之和就是1+2+3+4+6=16?,F(xiàn)在他們邀請(qǐng)你幫助編寫(xiě)一個(gè)函數(shù) ,尋找他們的密碼盒子。
**輸入:**輸入數(shù)據(jù)的第一行是一個(gè)數(shù)字
T(1<=T<=50000),它表明有1個(gè)需要進(jìn)行測(cè)試的數(shù)字,然后1個(gè)測(cè)試數(shù)據(jù),每個(gè)測(cè)試數(shù)據(jù)為一個(gè)數(shù)字N(1<=N<=50000).
**輸出 :**對(duì)于每個(gè)測(cè)試數(shù)據(jù),請(qǐng)輸出一個(gè)代表輸入數(shù)據(jù)的密碼編號(hào) 。
例:
輸入:
3
2
10
20
輸出:
1
8
22
注:由于測(cè)試數(shù)據(jù)關(guān)系,如果N==0的話(huà),請(qǐng)輸出1
【分析需求】
分析下題目,會(huì)發(fā)現(xiàn),題目中有很多包裝或場(chǎng)景性術(shù)語(yǔ),歸根到底,它的要求就是求一組的數(shù)因子之和,是數(shù)據(jù)問(wèn)題。具體細(xì)化它的要求:
1) 要計(jì)算因子和的數(shù)有T個(gè),這個(gè)數(shù)目不固定,動(dòng)態(tài)輸入,有一個(gè)范圍是[1,50000]
2) 求它的全部因子,注意因子包括1,,但不包括它本身。
3) 每個(gè)數(shù)值也是有范圍[1,50000], 0也可以,但輸出 因子固定為1
4) 輸入輸出是每行顯示一個(gè)數(shù)。
【設(shè)計(jì)】
經(jīng)過(guò)上面的需求分析,那我們就要進(jìn)行概要設(shè)計(jì)
1、 分配存放測(cè)試數(shù)據(jù)的空間
2、 輸入需要測(cè)試多少個(gè)數(shù),T ,由于<50000,用int就可以
3、 輸入所有測(cè)試數(shù)據(jù)
4、 求每一個(gè)測(cè)試數(shù)據(jù)所有因子,并計(jì)算其和
5、 打印所有結(jié)果
【編碼】

源代碼就如此,你會(huì)發(fā)現(xiàn)這個(gè)代碼很簡(jiǎn)單就實(shí)現(xiàn)了我們的功能,輸入輸出是否和要求一致,到這里貌似我們已經(jīng)完成了任務(wù),是否結(jié)束了?那么我肯定的告訴你,這個(gè)代碼是幼兒小班同學(xué)寫(xiě)的,別不信,我們從以下幾個(gè)維度來(lái)分析此代碼。
1、 從功能完整性
前面的分析里提到,我們輸入的數(shù)據(jù)是可以為0,只不過(guò)固定為1,那么我們運(yùn)行上面的代碼,會(huì)發(fā)現(xiàn)輸出為0

那這肯定說(shuō)明我們代碼有考慮不到的地方。
原因就在于30行,我們是從1開(kāi)始除的,默認(rèn)這里的數(shù)是大于等于1,所以我們要關(guān)注為0的時(shí)候故需要修改代碼

2、從數(shù)據(jù)安全
? 題目中有要求僌的數(shù)據(jù)個(gè)數(shù)范圍為[1,50000],也就是說(shuō)最多不能超過(guò)50000,我們的代碼用于存儲(chǔ)數(shù)據(jù)大小是50001,其實(shí)也是有風(fēng)險(xiǎn)的,假如我輸入了60000個(gè)數(shù)據(jù),那么這個(gè)數(shù)組在使用的時(shí)候就會(huì)越界,可能會(huì)使用到其他空間,嚴(yán)重引起系統(tǒng)異常。由于數(shù)據(jù)量太大,我3個(gè)數(shù)為例作演示。

那么我們就需要對(duì)輸入數(shù)據(jù)進(jìn)行有效判斷 ,確認(rèn)是在這個(gè)范圍,修改代碼

同樣,我們也要對(duì)測(cè)試數(shù)據(jù)進(jìn)行類(lèi)似的判斷,因?yàn)轭}目中有要求

大伙再看看,數(shù)據(jù)都覆蓋完了嗎?
很遺憾,依然沒(méi)有,如果輸入一個(gè)負(fù)數(shù)呢?

可以修改為:

那么大家再想想,是否有其他辦法,比如將數(shù)據(jù)類(lèi)型修改無(wú)符號(hào)是否可行?
3、從存儲(chǔ)空間利用率
題目中有要求輸入的數(shù)據(jù)個(gè)數(shù)最大為50000,所以我們之前申請(qǐng)的數(shù)組大小就為50001*sizeof(int),但實(shí)際上我們開(kāi)始驗(yàn)證的時(shí)候只輸了幾個(gè)數(shù),你們可以想想,我們提著大尼龍口袋去銀行只取了100塊錢(qián)放在里面,是不是感覺(jué)大材小用了。這種在資源比較緊張的嵌入式設(shè)備里絕對(duì)絕對(duì)不允許這么 做的。又要按照題目要求動(dòng)態(tài)輸入個(gè)數(shù),那么只好使用動(dòng)態(tài)申請(qǐng)空間嘍

別忘了用完了得釋放

4、 從執(zhí)行效率
當(dāng)數(shù)據(jù) 特別大的時(shí)候,我們可以看到在求所有因子時(shí)是從1遍歷到N-1,但事實(shí)上是完全不用的,最基礎(chǔ),最簡(jiǎn)單的提升效率就是只算[1,N/2],想想為什么?

還有更多更好的優(yōu)化,就不詳述了,大伙自行去想想!
4、 從代碼規(guī)范
看起來(lái)這代碼挺規(guī)范的,沒(méi)有什么可以改善的了,其實(shí)不然
1) 所有的參數(shù)要初始化喲,包括前面的數(shù)組,指針,變量等。

注意這里是指第一次使用前初始化。
2) 編寫(xiě)的函數(shù)要做到功能單一,所以一般來(lái)說(shuō)要將求因子之和放到一個(gè)單獨(dú)的函數(shù)中去,main調(diào)用

3)注意編碼安全規(guī)范,像scanf這些屬于非安全函數(shù),要修改成安全函數(shù)
如scanf_s
4)其他如命名,返回值定義,異常處理,入?yún)⑴袛嗟?/p>
? 經(jīng)過(guò)上面五個(gè)方面的改進(jìn),基本上可以用了,是不是覺(jué)得寫(xiě)個(gè)代碼不容易!哈哈!我這里只是拋磚引玉,可能各位還會(huì)發(fā)現(xiàn)有需要優(yōu)化的哈,僅作參考。
1
注:本文屬原創(chuàng),若轉(zhuǎn)載請(qǐng)注明出處!
附代碼
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
//求輸入n的所有因子之和
int factor(int n) {
? ? int j;
? ? int sum = 0;
? ?
? ? if (n == 0)
? ? ? ? return 1;
? ? for (j = 1; j <= n / 2; j++) {
? ? ? ? if (n % j == 0)
? ? ? ? ? ? sum += j;
? ? }
? ? return sum;
}
int main() {
? ? int T = 0;? //需要測(cè)試數(shù)據(jù)的個(gè)數(shù)
? ? int *N_p = NULL;? //N[50001]; //可能測(cè)試的數(shù)據(jù)會(huì)有50000個(gè)
? ? int i,j,temp; //臨時(shí)變量
? ? int sum; //因子之和
? ? //獲取測(cè)試數(shù)據(jù)
? ? scanf("%d", &T);
? ? if ((T < 0 ) || (T > 50000)) {
? ? ? ? printf("輸入數(shù)據(jù)個(gè)數(shù)超過(guò)要求\n");
? ? ? ? return -1;? ? //這里是要退出呢,還是再重輸,各位看著辦
? ? }
? ?
? ? N_p = (int*)malloc(T * sizeof(int));
? ? if (N_p == NULL) {
? ? ? ? printf("malloc fail\n");
? ? ? ? return -2;
? ? }
? ? //獲取T個(gè)測(cè)試數(shù)據(jù)
? ? for (i = 0; i < T; i++) {
? ? ? ? scanf("%d", N_p+i);
? ? ? ? if ((T < 0) || (T > 50000)) {
? ? ? ? ? ? printf("輸入測(cè)試數(shù)據(jù)超過(guò)[1,5000],退出\n");
? ? ? ? ? ? return -1;? ? //這里是要退出呢,還是再重輸,各位看著辦
? ? ? ? }
? ? }
? ? //求每個(gè)數(shù)據(jù)的全部因子,計(jì)算其和,并打印
? ? for (i = 0; i < T; i++) {
? ? ? ? sum = factor(*(N_p + i));
? ? ? ? printf("%d\n", sum);
? ? }
? ? if (N_p) {
? ? ? ? free(N_p);
? ? ? ? N_p = NULL;
? ? }
? ? return 0;
}
文章最后發(fā)布于: 2019-11-10