• 4

新手詢問C語言的問題II

audiofan wrote:
是我誤解了box59...(恕刪)


謝謝 audiofan ... 謝謝 馬赫迪 ...

以前寫 c 很少被挑毛病. 這次居然被嫌最浪費記憶體...
不都一樣是 int * 26 陣列? 不懂耶... 若要省這塊那就要改用指標囉.

算了還是藏拙...
gemini89a wrote:
1.輸入 49 時會出現 XLIX 還是 IL 呢?
2.如果將來要擴充這段程式能處理的數字位數,除了要改 roman_num 外,是不是還得修改 power10?
3.用這種方式能處理的數字最大是多少呢?輸入負數時會出現什麼情況呢?
4.雖然處理的數字位數不多,用到的除法和餘數不是很多... 不過有沒有辦法可以不用到除跟餘數呢?


1. 上面這段code跑起來是出現XLIX。(這是對的吧? )
2. 是的,不過power10若用malloc動態配置ARRAY_SIZE(roman_num)個,並以10的幕次方初使化,
就不用每次都改power10了。
3. 理論上只要roman_num定的夠,32-bit整數能除的都能處理。(羅馬數字應該沒定到那麼多吧?)
輸入負值會當做正值補數,答案會錯。
4. 目前還想不到不用除法怎麼做....
audiofan wrote:
4. 目前還想不到不用除法怎麼做....


不用除法的話就是字串處理啦,讀進來就當字串,不轉成數字
看字串長度決定位數,然後就是一位一位轉換啦
其實最多就十個字母而已,
就直接開20個變數,兩個當一組,一個紀錄字母,一個紀錄次數,
用個迴圈讓它一個一個去比對就可以了,
雖然慢,但寫很快
driftice wrote:
數字轉羅馬一個簡單原則,每位數分開處理,簡單來說
49 = 40 + 9 (不是50-1)
99 = 90 + 9 (不是100-1)
999 = 900 + 90 + 9 (不是1000-1)
這樣一來就很容易了,最直覺的就建表100~900,10~90,1~9
照順序串起來就是了

進階一點
百位數 (M,D,C)
十位數 (C,L,X)
個位數 (X,V,I)
數字部份都是套同一套法則,只是位數不同符號不同而已
例 7=VII,70=LXX,700=DCC 都是該位數 第二符號一個 + 第三符號兩個
所以弄個1~9的取符號表,然後依位數不同,拿不同符號組來取罷了

想到這裡,或許從羅馬數字轉回阿拉伯數字會比較有趣一點...



真的,原來 driftice 兄說的比較對;
49 應該是 XLIX 而不是 IL... 我誤會了。



我找到一段文字可以當作規則參考:
(來源:http://home.att.net/~numericana/answer/roman.htm)


The subtractive principle (a subtrahend preceding a minuend) may apply:

Only to a numeral (the subtrahend) which is a power of ten (I, X or C).
For example, "VL" is not a valid representation of 45 (XLV is correct).

Only when the subtrahend preceeds a minuend no more than ten times larger.
For example, "IL" is not a valid representation of 49 (XLIX is correct).

Only if any numeral preceeding the subtrahend is at least ten times larger.
For example, "VIX" is not a valid representation of 14 (XIV is correct), and "IIX" is not correct for 8 (VIII is correct).

Only if any numeral following the minuend is smaller than the subtrahend.
For example, "XCL" is not a valid representation of 140 (CXL is correct).



這樣一來就簡單多了!
而 driftice 兄所說的從羅馬數字轉回阿拉伯數字也蠻有趣的,
基本上就是把七個基本的符號轉換回對應數字再累加回來,
不過要特別注意減數喔...
如果不在意使用 2-parse 的方式來實作,
我第一時間想到的方式是:
(如果只採用七個基本符號。)
1.宣告一個整數陣列,長度為所輸入羅馬數字字串的長度。
2.第一階段:將羅馬數字字串每個字元都個別轉換成對應的阿拉伯數字,存到整數陣列中對應的位置。
3.第二階段:由高位而低位開始累加數字。要是遇到次一低位的數字比較大,代表該數字為減數,轉成負數再相加。
這樣的程式比較笨,但是比較好寫啦。


另外 driftice 兄在另外一篇回應提到,

driftice wrote:
不用除法的話就是字串處理啦,讀進來就當字串,不轉成數字
看字串長度決定位數,然後就是一位一位轉換啦


這就是我偏好的作法啦... 哈哈。
不過想想,其實 32bit 能表示的數字位數已經很多了,
羅馬數字也不適合表示超大數...
基本上羅馬數字好像就七個基本符號,
所以表示 18034 這樣的數字時,下面的表示法也是允許的:

MMMMMMMMMMMMMMMMMMXXXIV

(這也是上面所提網頁中的例子。)
只不過看來羅馬數字有些變化型態的表示方式來表示大於 1000( M ) 的數字,而且不止一種...

所以呀,其實我覺得 audiofan 兄寫的程式就很棒了,
而且我喜歡這種使用巨集的方式,我也偷偷拿去用... 哈哈。
box59453 wrote:
算了還是藏拙...


box59453 大大不要這麼灰心嘛~
程式技巧千千萬萬種,
要不用多餘的記憶體也不跑回圈從 A 檢查到 Z,也還有其他方式啊!


我舉個很簡單但是不見得比較快的方式好了。

0.比如說輸入ADAaEVSzaZ
1.先將輸入字串裡的字元全部轉成大寫。(一次掃描,變成 ADAAEVSZAZ)
2.排序。要不用多餘的記憶體那就用很簡單的氣泡排序法吧!只要多一個 char 的空間就可以了。(十次掃描,變成 AAAADESVZZ)
3.排完序就簡單啦,看看重複字元有幾個,就輸出吧!(一次掃描,簡單的在下面解說:)




for(從 1 到 9)
{
  if(和前一個字元相同)
    累加;
  else        // 和前一個字元不同
  {
    輸出剛剛的字母和之前累加的數目;
    累加歸零;
  }
}

處理最後一個字元,輸出最後一個計數結果;



(最後就輸出 A4D1E1S1V1Z2 啦!)


加起來跑 12 次,應該不會比從 A 跑到 Z 的 26 次來得慢吧?



感謝大家無私的分享.

我個人是覺得學習程式語言最難的部分是問題的邏輯分析.

像題目1大概除了我之外的朋友都知道用ASCII去做

這部份的訓練是多寫程式就可以提升的嗎?
daniel35 wrote:
這部份的訓練是多寫程式就可以提升的嗎?



多寫,多看,多思考,
能做到這三點就一定能提升自己的功力喔。

看到別人問的問題,都可以思考:如果是我我會怎麼寫?怎樣寫比較好?
還有真的有興趣的話,買些書來看也很好;
像是冼鏡光老師的「C名題精選百則」就是很好的一本書,
不管是本身喜歡思考與解題,或是要參加一些程式設計比賽等等的,都頗實用呢。
隨著功力的加深也有了物件導向的底子後,一些 design pattern 或是 refactoring 之類的的書都不能不看喔。

當然一些基本的功力也是要有,才能知道你看到的程式是好是壞;
最基本的像是去分析時間複雜度與空間複雜度就是必備的訓練,
隨著你經驗的累積,也許你也開始會去追求一些難度比較高的奇淫技巧,
這時候還得回頭去研究程式架構才行呢...



我說的實在是雜亂無章,
所以稍為整理一下好了。

學習程式有三大方向:
1.邏輯
2.架構
3.技巧

邏輯一定要有,有架構才能寫出良好的程式,技巧反而我會放在最後面...
因為大多數的程式運算都很簡單,除非牽涉到演算法的部份。
(其實一般人在寫的大多數程式都是在做資料處理的部份而已...)

要去培養這三項能力的方式,我覺得就是這三點:
1.多寫
2.多看
3.多思考

寫程式其實很有趣的,
而且可以花上一生去追尋所謂的「程式之道」...
daniel35 兄,希望您能在這領域找到樂趣啊。
  • 4
內文搜尋
X
評分
評分
複製連結
Mobile01提醒您
您目前瀏覽的是行動版網頁
是否切換到電腦版網頁呢?