記一道評論區的題目
導語 : 作為一個西電的菜雞 , 每天隻能和不超過兩天的ddl較勁 , 啥也不懂 , 啥也不會. 因為家裡硬碟不太夠了是以把作業的代碼傳到部落格裡儲存. 可以預見到的 , 遭到了真正大佬的嘲笑. 其中 , 二哥在讨論區裡留下一道題目 , 我覺得還挺有意思的. 是以試着實作了一下 , 作為部落格的第二篇拙作.
1.題目
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNCM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2csk3ZU1keFRlTxEleYhnRzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3PnBnauYTNwADOwADMzETNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
分析一下 , 是想實作一個小寫數字到中文大寫數字的轉化. 那麼 , 如果我們想要實作這個功能 , 首先我們要重新回顧一下中文數字的讀法和英文讀法的差別.
2.回顧背後的數學知識
我們在國小二年級的時候就學過數字的讀法 , 在國中的時候基本上了解到了英文的數字的讀法.
比如對于31980 , 中文讀作"三萬一千九百八十" , 英文讀作"tirty-one thousand and nine hundred eighty". 那麼中文和英文對于數字的讀法來說有什麼不同呢?
首先 , 我們要了解一下中文和英文當中對于數字的機關. 在中文中 , 有個 , 十 , 百 , 千 , 萬 , 十萬 , 百萬 , 千萬 , 億 , 十億… 在英文中 , 有1-20的不同的讀法 , x0的讀法 , hundred , thousand , million , billion… 通過比較我們不難發現其規律. 中文的數字機關是以四個為一循環 , 比如四位引出一個萬 , 再四位引出一個億. 而英語中是以三位為一個計數段 , 引出一個定義的機關.
1 , 000 , 000 , 000 1,000,000,000 1,000,000,000
英語國家的人看數字的方式.
10 , 0000 , 0000 10,0000,0000 10,0000,0000
中國人看數字的方式.
兩者相似的 , 對于比較小的位數劃分的比較詳細一些 , 而對于比較大的位數 , 中國人采取與小位數的機關相結合同時适度引入新機關來記錄數字 , 而英語采用每三位定義一個機關的方式記錄數字.
對于中文來說 , 比較特殊的一點是 , 如果在數的中間有0的話習慣中間讀一個"零"表示區分層次.
如 : 1023讀作"一千零二十三" , 但是如果從某一位開始之後全是0的情況下則不讀這個0. 而這個"零"的讀法便是這個小demo最有意思的地方.
3.程式設計和算法思路
通過上面對問題的回顧 , 我們大緻可以想到一個思路. 将一個數字按4位為一組分隔開. 将0-9999的數實作向中文的轉換 , 然後在後面加上機關即可. 比如12345 , 可以看作1,2345 , 那麼第一組2345就讀作"二千三百四十五" , 這裡為了叙述友善 , 将中文大寫數字"壹"寫作了中文小寫數字"一". 這一組因為最低位是個位 , 是以機關為空. 而第二組隻有一個1 , 讀作"一" , 它處于萬位上. 是以後面加上機關"萬". 是以讀作"一萬二千三百四十五".
下面主要讨論如何将0-9999内的數字實作. 很自然的 , 我們想到模拟人來讀數字的方法. 首先,我們将所讀數的千位 , 百位 , 十位 , 個位存在一個整型數組裡.
下 面 列 出 需 要 讨 論 的 幾 種 情 況 : 1234 1 , 2 , 3 , 4 1 0 , 0 , 0 , 1 1001 1 , 0 , 0 , 1 1000 1 , 0 , 0 , 0 1110 1 , 1 , 1 , 0 0 0 , 0 , 0 , 0 下面列出需要讨論的幾種情況:\\ 1234\\ 1,2,3,4\\ 1\\ 0,0,0,1\\ 1001\\ 1,0,0,1\\ 1000\\ 1,0,0,0\\ 1110\\ 1,1,1,0\\ 0\\ 0,0,0,0 下面列出需要讨論的幾種情況:12341,2,3,410,0,0,110011,0,0,110001,0,0,011101,1,1,000,0,0,0
首先來看第一種. 第一種讀作"一千二百三十四" , 可以看到 , 我們開始讀是從第0位開始讀的 , 而且每一位都讀到了. 這裡我們可以得出對應規則 : 第0位對應機關為"千",如果不為0應将其讀了數字名後加"千" , 之後類推.
再看第二種 , 顯然之前的三位都沒有讀到 , 是從第四位開始讀的. 這裡我們可以體會到 : 應該設定一個變量 , 我們設定為start. 我們通過start的狀态确定讀數的開始和停止.
第三種讀作"一千零一". 這裡我們引出了中間讀"零"的問題. 我們看到中間雖然有兩個0 , 但是隻讀一次. 我們可以認為隻讀第一次出現的0. 是以這裡我們引出變量firstzero , 用來确定是否為第一個0 , 隻有第一個0會讀.
第四種讀作"一千". 這裡我們可以發現一個概念. 若從某位數開始全是0 , 則這個第一個0不讀. 是以引入alwayszero變量 , 用來确定是否之後全是0 , 若是則不讀 , 不是則讀第一個0.
第五種讀作"一千一百一十". 如果我們帶入前四條對應的規則應讀作"一千一百一十零". 這是因為最後一位0也是第一個0且滿足到最後全是0 , 是以會讀出來. 那麼我們如何解決呢? 這裡我們對第三條規則做一個補充 : 隻有第一個0 ,不在最後一位(個位)上 , 且之後不全為0時才讀零.
第六種 , 對于0來說 , 由于start是遇到非0元素才開始讀 , 是以0是不會開啟讀數的. 是以 , 我們需要一個特别判定 : 當輸入數字為0時隻輸入0 , 當數字非0時才按照前五條規則開始讀數.
了解原理之後 , 廢話不多說 , 上代碼.(注 : 這裡代碼中的print函數是預先定義的讀數字的函數 , 比如print(1) , 輸出一)
//輸出0-9999的中文讀法
void thousandmaxprint(int n) {
//分離位數
int bit[4] = { 0,0,0,0 };
bit[0] = n / 1000;
bit[1] = n % 1000 / 100;
bit[2] = n % 100 / 10;
bit[3] = n % 10;
int start = 0;
//開始狀态變量,當其為1時才會開始列印
int firstzero = 1;
//尋找中間的第一個0,輸出後會置為0
int alwayszero = 1;
//是否從第一個0開始全部是0
//如果是0
if (n == 0)
print(n);
else { //如果不是0
//開始周遊
for (int tempcount = 0; tempcount < 4; tempcount++) {
if (bit[tempcount] != 0 || tempcount == 3)
//尋找到最後一位或已經周遊到最後一位
start = 1;
if (start) {
if (bit[tempcount] != 0) {
if (tempcount == 0) {
print(bit[tempcount]);
printf("千");
}
if (tempcount == 1) {
print(bit[tempcount]);
printf("百");
}
if (tempcount == 2) {
print(bit[tempcount]);
printf("十");
}
if (tempcount == 3) {
print(bit[tempcount]);
}
}
else {
if (firstzero && tempcount < 3) {
//如果是第一個0且不是最末位,則判斷是否之後全是0.
for (int i = tempcount; i < 4; i++)
if (bit[i] != 0)
alwayszero = 0;
if (!alwayszero)
//如果不是全部是0,則輸出一個0且将第一個0狀态置為0.
print(bit[tempcount]);
firstzero = 0;
}
}
}
}
}
}
上面的函數是重點. 當實作了上一個函數 , 下一個函數就好寫多了. 下面我們寫從1,0000到9999,9999的輸出函數.
這裡需要探讨這樣的問題. “一萬零一十"的問題 , 什麼時候會出現這個0呢? 是當萬位一下的數小于1000的時候會輸出這樣的"零”. 同樣的 , 當萬位之後的部分為0時 , 則不讀這個"零". 直接讀作"一萬".
那麼 , 歸納如下. 首先我們将數字分為萬以下和萬以上的部分
10 , 1234 10,1234 10,1234
如果萬位以上數字不為0 , 對于萬以上的機關 , 讀出後加上"萬"字.
然後對于萬以後的部分 , 如果它不等于0的話 , 進一步進行判斷. 若它小于1000 , 則輸出"零"後再讀這部分數 , 否則直接讀出這部分數. 代碼如下.
void tenthousandmaxprint(int n) {
int n1 = n / 10000;
int n2 = n % 10000;
if (n1 != 0) {
thousandmaxprint(n1);
printf("萬");
}
if (n2 != 0) {
if (n2 < 1000);
printf("零");
thousandmaxprint(n2);
}
}
對于一億到一萬億之間的數 , 方法和讀萬的方法基本是一緻的. 上代碼.
void hundredbillionmaxprint(int n) {
int n1 = n / 100000000;
int n2 = n % 100000000;
thousandmaxprint(n1);
printf("億");
if (n2 != 0)
tenthousandmaxprint(n2);
}
這就是這個程式的大概思路了. 還是比較清晰的 , 當然有的地方因為我的文筆問題可能會語義不清 , 但是我都能寫出來的東西. 我相信大家一定都能寫出來.
最後奉上黏貼可運作的代碼.
#include<stdio.h>
/*
print函數負責列印0到9的中文大寫.
thousandmaxprint實作不超過一萬的數的中文輸出.
tenthousandmaxprint實作不超過一億的數的中文輸出.
hundredbillionmaxprint實作不超過一萬億的中文輸出.
日常用到中文輸出的大部分是财務系統的賬目大寫,一般
不會超過一萬億.
*/
void print(int n);
void thousandmaxprint(int n);
void tenthousandmaxprint(int n);
void hundredbillionmaxprint(int n);
/*
主程式.
*/
int main() {
int n;
printf("輸入一個數字的小寫後回車可以輸出中文寫法\n");
scanf("%d", &n);
if (n >= 100000000)
hundredbillionmaxprint(n);
else{
if (n >= 10000)
tenthousandmaxprint(n);
else
thousandmaxprint(n);
}
return 0;
}
void print(int n) {
if (n == 0)
printf("零");
if (n == 1)
printf("一");
if (n == 2)
printf("二");
if (n == 3)
printf("三");
if (n == 4)
printf("四");
if (n == 5)
printf("五");
if (n == 6)
printf("六");
if (n == 7)
printf("七");
if (n == 8)
printf("八");
if (n == 9)
printf("九");
}
void thousandmaxprint(int n) {
int bit[4] = { 0,0,0,0 };
bit[0] = n / 1000;
bit[1] = n % 1000 / 100;
bit[2] = n % 100 / 10;
bit[3] = n % 10;
int start = 0;
//開始狀态變量,當其為1時才會開始列印
int firstzero = 1;
//尋找中間的第一個0,輸出後會置為0
int alwayszero = 1;
//是否從第一個0開始全部是0
//如果是0
if (n == 0)
print(n);
else {
//開始周遊
for (int tempcount = 0; tempcount < 4; tempcount++) {
if (bit[tempcount] != 0 || tempcount == 3)
//尋找到最後一位或已經周遊到最後一位
start = 1;
if (start) {
if (bit[tempcount] != 0) {
if (tempcount == 0) {
print(bit[tempcount]);
printf("千");
}
if (tempcount == 1) {
print(bit[tempcount]);
printf("百");
}
if (tempcount == 2) {
print(bit[tempcount]);
printf("十");
}
if (tempcount == 3) {
print(bit[tempcount]);
}
}
else {
if (firstzero && tempcount < 3) {
//如果是第一個0且不是最末位,則判斷是否之後全是0.
for (int i = tempcount; i < 4; i++)
if (bit[i] != 0)
alwayszero = 0;
if (!alwayszero)
//如果不是全部是0,則輸出一個0且将第一個0狀态置為0.
print(bit[tempcount]);
firstzero = 0;
}
}
}
}
}
}
/*
分離萬以上和萬以下的部分應用上面定義好的函數.
*/
void tenthousandmaxprint(int n) {
int n1 = n / 10000;
int n2 = n % 10000;
if (n1 != 0) {
thousandmaxprint(n1);
printf("萬");
}
if (n2 != 0) {
if (n2 < 1000);
printf("零");
thousandmaxprint(n2);
}
}
/*
原理基本同上.
*/
void hundredbillionmaxprint(int n) {
int n1 = n / 100000000;
int n2 = n % 100000000;
thousandmaxprint(n1);
printf("億");
if (n2 != 0)
tenthousandmaxprint(n2);
}
運作結果
後記
完成以後在CSDN查了一下 , 發現這樣的代碼有很多 , 可能不是最聰明的方法 , 但希望是最能令我這種"蠢人"了解的方法.