本書 本 - 碁峰資訊epaper.gotop.com.tw/pdfsample/acl036300.pdf前言 - v -...
TRANSCRIPT
前言
我們長期從事資料結構教學和競賽培訓,教學實踐使我們產生了對資料結構課程的教學模
式進行改革的想法:
1) 在課程中需要增加思考方式和解題策略的引導,引導學生思考各類資料結構的本質特
徵是什麼;面對問題為什麼要採用這樣的資料結構而不宜採用那樣的資料結構;當有
多個資料結構可用時,怎樣權衡時間複雜度、空間複雜度、程式設計複雜度和思維複
雜度四個因素,尋找最合時宜的來使用,將「知識導向」與「智慧導向」真正結合起
來。
2) 在課程中需要引入案例教學,透過模擬或者重現現實生活中的一些場景,讓學生置身
問題情境之中,透過思考、討論和上機實作來學習。傳統教學將資料結構「束之高閣」,
在理論教學和筆試上兜來兜去,可能會使學生渾然不知資料結構在現實生活中究竟有
什麼用處,懵懵懂懂,最終失去了學習的意義。「紙上得來終覺淺,絕知此事要躬行」。
案例教學則是一種以問題和動手程式設計驅動學習的方式:將知識置於問題情境和實
踐過程之中,將枯燥乏味變為生動活潑。學生拿到試題後,先進行審題,然後溫習或
查閱各種他認為必要的資料結構知識,這無形中激發了他們的求知欲望,加深了他們
對知識真諦的理解。捕捉到相關的理論知識後,學生還要經過縝密思考和動手程式設
計,使之變為解決問題的程式方案。這個「認識-實踐-再認識-再實踐」的過程,
應視為知識理解上的一種提升,知識學習與應用能力之間的一種轉變和昇華。
-
提
iv -
本
提升程
基於
程式
後作
問題
而且
「學
本書
程式設
於上
式設
作為
題背
且所
學以
書試題
POJ
北京
http
ZOJ
浙江
http
UVA
UVA
http
http
Ura
Ura
http
SGU
SGU
http
設計的
上述想
設計競
為學習
背景,而
所編的
以致用
題的
J
京大學
://poj
J
江大學
://acm
A
A 線上
://uv
://liv
l
l 線上
://acm
U
U 線上
://acm
的資料
想法
競賽和
習資料
而且
的程式
用」的
的線
學線上
j.org/
學線上
m.zju
上評
a.onl
vearch
上評測
m.tim
上評
m.sgu
料結
,我們
和其他
料結構
且在相
式的
的目的
線上評
上評測
/
上評測
u.edu
測系
lineju
hive.o
測系統
mus.ru
測系
u.ru/
結構力
們近
他程
構知
相關網
正確
的。
評測
測系
測系
u.cn/o
系統
udge.
onlin
統
u/
系統
力
近年來
程式設
知識的
網站上
確性和
測系統
統
統
online
org/
nejudg
來開設
設計競
的實驗
上都
和效
統主
ejudg
ge.or
設了
競賽
驗與實
都有試
率也
主要
ge/
rg/
「資
中的
實作
試題的
也可以
要有:
資料結
的典型
作案例
的線上
以透過
:
結構實
型試題
例。這
上測
過相
實驗與
題分
這些試
測試。學
相關網
與實
門別
試題
學生
網站上
實作」
別類,
不僅
生不僅
上的
課程
精選
僅為相
僅可以
測試
程,
選了其
相關知
以帶著
試系統
並將
其中
知識
著問
統得到
將 AC
中 204
識建立
題學
到即
CM 國
4 道試
立了豐
學習資
即時檢
國際大
試題
豐富有
資料結
檢驗
大學
,翻
有趣
結構
,達
學生
翻譯
趣的
構,
達到
前言
- v -
本書按照資料結構的知識結構和循序漸進的原則,共分四個 Part(基本能力的程式設計實
作、線性資料結構的程式設計實作、層次類非線性串列的程式設計實作、群聚類非線性串
列的程式設計實作)14 個章節。每個章節為相關資料結構知識提供了大量的實作範例,並
且建立了相關的試題庫,其中實驗範例 68 道,題庫試題 136 道。每個實作範例不僅有知
識要點闡述和詳盡的試題解析,還列出了寫 有詳細注釋的參考程式;題庫中的所有試題
無論難易,都有清晰的提示。教師既可以將實作範例作為開設資料結構實作課程的教材,
也可以從相關題庫中挑選資料結構實作課程的作業、考題或指導 ACM 集訓活動的培訓資
料。每道題都注明了試題來源和線上測試系統,考慮到網站更新給讀者學習帶來不便的可
能情況,本書還整理了所有試題的英文原版描述和大部分試題的測試資料等資料的檔案供
讀者下載。我們之所以這樣做,就是力圖建構一個盡可能豐富、實用和長效的資料結構實
驗與實作課程資源庫。
需要說明的是,本書是在復旦大學 ACM 集訓隊長期活動的基礎上累積而成的。阿拉法特
居來提、姚哲雲、張昊等同學精心編寫了所有程式,每道程式都透過了嚴格的測試驗證,
其中一些程式經多次修改,精益求精。這些同學為本書的出版付出了有不心血和貢獻。在
此,向他們表示由衷的感激。另外,衷心感謝復旦大學電腦學院 2006、2007、2008 級同
學在使用本書講義過程中提出的寶貴意見和建議。
由於時間和能力所限,書中若有缺點和不足之處,熱忱歡迎學術界同仁和讀者賜教指正。
如果你在閱讀中發現了問題,請透過書信或電子郵件告訴我們,以便及時整理成勘誤表放
在本書的專門網站上,供廣大讀者查詢更正。我們更期望讀者對於本書提出建設性的意見,
以便再版時改進。我們的聯繫方式是:
通信地址:上海市邯鄲路 220 號復旦大學電腦科學技術學院 吳永輝
郵編:200433
E-mail:[email protected]
-
提
vi -
提升程
作
吳
復旦
Co
入
算機
《資
以教
程式設
作者
吳永輝
旦大
unci
ACM
機研
資料
教練
ACM
2011
2010
2009
2008
2007
2006
2005
2004
2003
2002
每年
其他
[1]
[2]
設計的
者簡
輝
大學計
l Chi
M-IC
研究與
料通信
練身份
M/IC
1ACM
0ACM
9ACM
8ACM
7ACM
6ACM
5ACM
4ACM
3ACM
2ACM
年獲得
他程式
百度
兩次
Goog
2006
的資料
簡介
博士
計算
ina)
CPC
與發展
信與網
份連續
CPC 程
M 世界
M 世界
M 世界
M 世界
M 世界
M 世界
M 世界
M 世界
M 世界
M 世界
得亞洲
式設計
之星程
冠軍
gle Co
,200
料結
介
士
機科
)成員
世界
展》、
網路
續帶隊
程式設
界總決
界總決
界總決
界總決
界總決
界總決
界總決
界總決
界總決
界總決
洲區預
計競賽
程式設
(200
ode Ja
08,2
結構力
科學與
員,復
界總決
、《軟
》和
隊進
設計
決賽第
決賽第
決賽第
決賽第
決賽第
決賽第
決賽第
決賽第
決賽第
決賽第
預賽冠
賽
設計大
09,2
am:
2011
力
與工
復旦
決賽,
軟體學
和《資
進入 A
競賽
第 27
第 11
第 14
第 13
第 26
第 39
第 6 名
第 15
第 13
第 7 名
軍。
大賽
2011
三次
程系
大學
,並取
學報》
資料通
ACM
賽
名
名
名
名
名
名
名
名
名
名
:
),兩
入圍現
系副教
學 AC
取得世
》、以
通信
M-ICP
兩次亞
現場決
教授
CM 程
世界
以及重
、計
PC 世
軍(
決賽
授,A
程式設
界第 6
重大
計算機
世界總
2005
,最好
ACM
設計
6 名的
大學術
機網路
總決
,200
好成績
-ICP
計競賽
的佳績
術會議
路與
賽,
09),
績 201
PC 中
賽隊教
績。他
議上發
開放
競賽
每年
11 全
中國
教練
他的
發表
放系統
賽的主
年多人
球第
賽區
。作
主要
表過多
統》。
主要
人入圍
6,中
區指導
者自
要研究
多篇論
獲獎
圍現場
中國選
導委
自 200
究方向
論文
獎情況
決賽
選手名
員會
01 年
向為
,參
況:
。
名列第
會(A
年起連
資料
參與翻
第 1。
ACM
連續帶
料庫,
翻譯出
M-ICP
帶隊
在《
出版
PC
隊進
計
版了
前言
- vii -
作者簡介
王建德
著名的資訊學奧林匹克競賽金牌教練,國務院特殊津貼專家,中學特級教師。他所輔導的
學生在國際奧林匹克競賽(IOI)中獲得 7 金、3 銀、2 銅的優異成績,先得出版了 24 本
關於程式設計和演算法的學術著作。其中《實用演算法的分析與程式設計》廣受好評,該
書長期以來是各類程式設計競賽的必備教材。
直
性
陣
若
在
裝
存
的
串
以
或
日
四
設
C應
直接
性串
陣列
若陣
在陣
裝置
存取
的結
串中
以陣
或非
日期
四個
設計
Ch應用
存取
列。
是儲
列元
列中
,在
任意
構。
的某
列為
線性
計算
典型
實作
ha用
取類的
陣列
儲存於
元素不
中,資
在陣列
意一個
字串
某一字
為代表
性結構
算、高
型範例
作。
ap用直
的線性
列就是
於連續
不再有
資料元
列中存
個元素
串、記
字元
表的直
構類型
高精度
例,下
pte直接
性串
是這
續儲
有分
元素
存取
素的
記錄
;可
直接
型的
度數
下面
er接
列,
類資
存空
量,該
的下
一個
時間
、檔
以按
存取
資料
的表
首先
r 0接存
指的
資料結
空間中
該序
下標間
個資料
間都為
檔案也
按記錄
取類線
料物件
表示與
先圍繞
04存取
的是可
結構
中的相
序列叫
間接反
料元素
為 O(
也都屬
錄號檢
線性串
件,都
與處理
繞這四
4
取類
可以直
典
相同
叫一維
反映
素只
(1)。
屬於
檢索
串列
都可
理、
四個
類
直接
型的
資料
維陣列
了資
要透
從這
直接
記錄
是程
採用
多項
問題
類的
接存取
的代表
料類型
列;若
資料元
透過下
這個意
接存取
錄集合
程式設
用該儲
項式的
題展開
的線
取某一
表。
型的資
若資
元素的
下標計
意義上
取類線
合或檔
設計中
儲存方
的表示
開程式
線
一指定
資料
料元
的儲
計算
上講
線性
檔案
中使
方式
示與
式設
性
定項
元素
元素為
存位
它的
,陣
串列
中的
用
。
處理
計實
性串
項而無
素的集
為陣列
位址,
的儲存
陣列的
列,例
的某一
多的
理、數
實作,
串列
無須先
集合
列,則
,而電
存位址
的儲存
例如
一記錄
的資料
數值矩
,然後
列
先存
,是
則稱
電腦
址就
存結
,可
錄。
料結
矩陣
後再
列程
取其
一種
該元
記憶
行了
構是
以按
構,
的運
展開
程式
其前驅
種定長
元素為
憶體是
了,因
是一個
按下標
無論
運算是
開字串
式
驅或後
長的線
為多維
是隨機
因此在
個可直
標直接
論是線
是陣列
串處理
設
後繼
線性
維陣
機存
在陣
直接
接存
線性
列應
理的
設計
的線
串列
列。
取的
列中
存取
取字
結構
用的
程式
計
線
列。
的
中
取
字
構
的
式
-
提
4-2
4
提升程
-
4.
日期
1)
2)
由於
需要
數字
看兩
.1.
日曆
日
按照
400
200
哪月
輸入
輸處
輸出
對
程式設
1
期由
用
分
特
元
直
性
於日
要對
字對
兩個
1
曆是
、月
照目
0 整除
00 和
月哪
入
輸入包處理
出
對每個「Day「Thu
設計的
陣
年月
一個
分別使
特徵不
元素一
直接按
性串列
期的
對應的
對應。
個實例
C
是用於
、年
前國
除的
和 240
哪日星
包含若。可以
個測試yOfWursd
的資料
陣列
月日表
個結構
使用記
不僅充
一個接
按下標
列。
的計算
的英文
計算
例。
Cal
於表述
年、世
國內使
的年是
00 是
星期幾
若干行以假設
試樣例Weekday」
料結
列
表徵
構陣列
記錄年
充分展
接一個
標存取
算和
文表述
算得出
en
述時
世紀都
使用的
是例外
是閏年
幾。
行,每設輸出
例輸出」必
,「Fr
結構力
應
。日
列儲
年月
展現
個排
取日
日曆
述,
出日
da
間的
都是
的陽
外,它
年。給
每行包出的年
出一行須是riday
力
應用
期類
儲存,
日的
現了線
排列)
期元
曆的轉
因此
期資
r
的系統
是日曆
陽曆,
它們不
給定
含一個份不會
行,該下列y」或
用一
類型的
陣列
的 3 個
線性串
、「均
元素。
轉換需
此可將
資料後
統,從
曆系統
閏年
不是
西元
個正整會超過
行包含常數
或「Sa
一:
的題
列元素
個整數
串列
均勻性
。因此
需要在
將這些
後,以
從小
統表述
年被定
是閏年
元 200
整數,過 99
含對應中的aturd
日
目可
素為
數陣
的「
性」
此儲
在表
些英
以它
時到
述時
定義
年。例
00 年
,表示99。
應的日一個day」
日期
可以用
為一個
陣列。
有限
(各
存日
表徵日
英文表
為下
到分鐘
時間的
義為能
例如:
年 1 月
示 200
日期和:「S
」。
期計
用陣列
個含年
將輸
限性」
日期
日期元
日期的
表述設
下標
鐘,從
的單位
能被 4
170
月 1 日
00 年
和星期Sunda
計算
列作為
年月
輸入的
」(日
元素
元素的
的資
設成一
,即可
從月
位。
4 整除
0、18
日後
年 1 月
期幾。ay」,
算的
為資
日資
的日
日期元
素的類
的線
料間
一個
可從
到日
除的
800、
的天
月 1 日
格式為,「Mo
的實
資料結
資訊的
期透
元素的
類型相
性串
間進行
個線性
從表中
日,
的年份
、190
天數,
日後的
為「Yonday
實作
結構
的結構
透過線
的個
相同
串列是
行運算
性的字
中找出
後從
份,但
00 和
你的
的天數
YYY y」,
作範
,儲
構體
線性
個數有
同),而
是一種
算,而
字串常
出對應
從年
但是能
和 210
的任務
。輸入
Y-MM「Tue
範例
存方
。
串列
有限)
而且
種典
而輸
常數
應的
份到
能被
00 不
務是
入 後
M-DD esday
例
方式一
列組織
)、「有
且表長
典型的
輸出的
數表,
的字串
到世紀
被 100
不是閏
是列出
後一行
Dayy」,
一般有
織起來
有序
長相對
的直接
的月份
其下
串。我
紀。術
0 整除
閏年,
出這一
行是 -
yOfWe「Wed
有兩
來,其
序性」
對固定
接存取
份或週
下標與
我們不
術語
除而不
,而 1
一天是
1,程
eek」dnes
種:
其結
(日
定,
取類
週一
與日
不妨
語小時
不能
1600
是哪
程式不
, 其day
結構
期
可
類線
一般
期
妨來
時、
能被
0、
哪年
不必
其中」,
Chapter 04 應用直接存取類的線性串列程式設計
- 4-3 -
樣例輸入: 樣例輸出:
1730 1740 1750 1751 -1
2004-09-26 Sunday 2004-10-06 Wednesday 2004-10-16 Saturday 2004-10-17 Sunday
試題來源:ACM Shanghai 2004 Preliminary
線上測試:POJ 2080,ZOJ 2420
▼解題與分析
首先設計兩個函數:
1) days_of_year(year):計算 year 年的天數。若 year 能被 4 整除,但不能被 100 整除,或
者 year 能被 400 整除,則 year 年是閏年,全年 366 天;否則 year 年是平年,全年 365
天。
2) days_of_month(month,year):計算 year 年 month 月的天數。在 month=2 的情況下,若
year 年是閏年,則該月天數為 29 天,否則該月天數為 28 天;在 month=1,3,5,7,
8,10,12 的情況下,該月天數為 31 天;在 month=4,6,9,11 的情況下,該月天數
為 30 天。
我們以 2000 年 1 月 1 日(星期六)為基準,按照如下方法計算 n 天後的年、月、日和星
期的資訊。設 year、month、day 為年、月、日變數,wstr 為星期幾的字串常數。初始時
year=2000,month=1,day=1。
首先計算星期幾:以 2000 年 1 月 1 日星期六為每週週期的開始,即 wstr[0..6]={"Saturday",
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}。顯然 wstr[n % 7] 即為
2000 年 1 月 1 日的 n 天後的星期幾資訊。
接下來計算 year:在 n > 0 的情況下,若 n ≥ days_of_year(year),則 n -= days_of_year(year),
++year,直至 year 大於 n 為止,此時的 n 為 year 內的天數。
後計算 month 和 day:在 n > 0 的情況下,若 n ≥ days_of_month(month, year),則 n -=
days_of_month(month, year),++month,直至 year 年 month 月的天數大於 n 為止,此時的
n 為 year 年 month 月內的天數。顯然 day = n+day,n=0。
-
提
4-4
提升程
-
參
#uc
i
i
i
程式設
參考程
#incusincons"Thu
int {
i r
}
int {
i
is }r
}
int {
icw
設計的
程式
cludeng nast chursda
days
if (y
retur
days
if (m
int dswitc
retur
main
int ncin >while
的資料
e <iamesphar way",
s_of_
year ret
rn y
s_of_
montret
d; ch (cascas
rn d
n(vo
n; >> ne (n intweayeamondaywhi } //按cou
料結
ostrpacewstr"Fr
_yea
% 1turn ear
_mon
h ==turn
montse 1:se 10
d brded
;
id)
; //>=
t yeaak = ar = nth =y = 1le
if
}
}
}
按照格ut <<
<<
結構力
ream>e std[][2riday
ar(in
100 =yea% 4
nth(i
= 2)day
th) : ca0: c= 3reakefau= 3
/輸入0) ar, mn % 200= 1;1; (n) f (n
els
els
格式要< ye< (d
力
>d;20] =y"};
nt y
== 0r % ==
int
s_of
{ se 3ase 1;k; ult:0;
入第 1{ mont7; 0;
{ n >= n -=++yee ifn -=++moe { day n =
要求輸ar <day <
= {"S
year)
0) 400 0 ?
mont
f_yea
3: ca12:
個測
th, d//為
day= daear; f (n = daonth//+= 0;
出對應<< '-< 10
//
Satu /
) /
== 366
th,
ar(y
ase
試用例
day,為方便
s_ofys_o
>= ys_o; 後確n;
應的日-' <? "
//預編//使用rday//星期
//返回
0 ? : 3
int
year)
5: c
例
wea便起見
f_yeaof_ye
daysof_mo
確定日
日期和< (m0"
編譯命用 C+y", "期幾的
回 ye
366 365;
year
) ==
case
ak; ,將星
ar(year(
s_ofonth
期
和星期month: ""
命令++標準"Sun的字串
ear 年
: 3
r) /
366
7:
星期六
year)year
_monh(mon
期幾h < ) <<
準程式day"
串常數
年的天
365;
/返回
6 ? 2
case
六(20
) { r);
nth(mnth,
10 ?< day
式庫中", "M
數
天數
回 yea
29 :
e 8:
000 年
//先
montyea
? "0y <<
中的所Mond
ar 年
28;
年 1 月
先列舉
th, yar);
" : < '
有識別ay",
年 mon
;
月 1 日
舉到指
year
"") ' <<
別字 "Tu
th 月
日為星
指定年
r)) {
<< wst
uesd
月的天
星期六
份
{ //再
monttr[we
ay",
天數
)作為
再列舉
th <eak]
"We
為一個
舉到指
< '- <<
edne
個星期
指定月
-' end
sday
期的開
月份
dl;
y",
始
Chapter 04 應用直接存取類的線性串列程式設計
- 4-5 -
cin >> n; //輸入下一個測試用例 } return 0; }
4.1.2 What Day Is It?
現在使用的日曆是從古羅馬時期演變來的。Julius Caesar 發明了日曆系統,後來被稱為
Julian 曆。在這個系統中,4 月、6 月、9 月和 11 月有 30 天;非閏年 2 月有 28 天,在閏年
2 月則有 29 天;其他月份有 31 天。除此之外,在這個日曆系統中,閏年是每 4 年 1 次。
這是因為古羅馬的天文學家計算出 1 年有 365.25 天,因此在每 4 年之後,需要添加額外的
一天以保持季節的正常。為此,每 4 年要在一年中增加額外的一天(2 月 29 日)。
Julian 曆規則:如果年份是 4 的倍數,則該年是閏年,即有額外的一天(2 月 29 日)。後
來天文學家們注意到,一年不是 365.25 天,而是接近 365.2425 天。因此在 1582 年,羅馬
教皇 Gregory 下令改革曆法,新修訂後的曆法稱為 Gregorian 曆,即西曆。Gregorian 曆(西
曆)規則:年份是 4 的倍數是閏年,但如果這一年是 100 而不是 400 的倍數,則不是閏年。
為了彌補在那個時候已經造成的季節與日曆的差異,日曆被挪後了 10 天:1582 年 10 月 4
日被宣佈為 10 月 15 日。
大英帝國(當然那時還包括美國)當時沒有改用西曆。一直到 1752 年才將 9 月 2 日宣佈
為 9 月 14 日(延遲改變的原因是亨利八世和教皇的關係交惡)。
請編寫一個程式,對美國使用的西曆日期進行轉換,並輸出是星期幾。
輸入
輸入是一個大於零的正整數序列,每行 3 個代表日期的整數,一個日期一行。日期的格式 是「月 日 年」,其中月是 1 至 12 的正整數(1 表示 1 月,12 表示 12 月…等等),日是一個 1 至 31 的正整數,而年則是一個正整數。
輸出
輸出按照樣例中列出的格式列出輸入的日期和星期幾。在美國使用的日曆中無效的日期或不存在的日期,則要輸出一個指出無效日期的錯誤訊息。輸入以三個 0 結束。
樣例輸入: 樣例輸出:
11 15 1997 1 1 2000 7 4 1998 2 11 1732 9 2 1752 9 14 1752 4 33 1997 0 0 0
November 15, 1997 is a Saturday January 1, 2000 is a Saturday July 4, 1998 is a Saturday February 11, 1732 is a Friday September 2, 1752 is a Wednesday September 14, 1752 is a Thursday 4/33/1997 is an invalid date.
-
提
4-6
提升程
-
試題
線上
▼
由於
c c
一旦
期的
設
的旗
&&
若
整除
我們
有了
一個
程式設
題來源
上測試
解題
於在
cons=
cons=
旦確
的字
year
旗標
& day
old=
除,
們可
isLe
days
days
vali
(1
在 1
了以
個日
計算
透過
資訊
設計的
源:A
試:Z
題與
在輸出
st ={"Sust ={"",
確定月
字串。
r、m
標,即
y <=
=true
或者
可以根
eap(y
s_of_
s_of_
d(mo
≤mo
1752
以上基
期,
算目前
過執行
訊,並
的資料
ACM
ZOJ 12
與分析
出的轉
chaundacha
, "Ja "S
月份和
month
即 old=
2))
e 且 y
者能被
根據 o
year, o
_year
_mon
onth,
onth≤
年 9
基礎
按照
前日期
行 val
並繼續
料結
Pacif
256,
析
轉換後
ar wsy","ar msanuaepte
和星期
h 和 d
=(y
。
year
被 40
old 設
old)
r(year
nth(m
day,
≤12)
月 3
,便可
照下述
期是否
lid(m
續讀下
結構力
fic No
UVA
後的
str["Mondstr[ary",ember
期的
day 為
year <
能被
00 整
設計
,判斷
r, old
month
year,
) &&
3 日至
可以
述方
否屬
month
下一
力
orthwe
A 602
的日期
][maday"][ma, "Fer",
的整數
為目
< 175
被 4 整
整除,
4 個
斷 ye
d),計
h, yea
,old)
&(1
至 13
以展開
方式進
於 17
h, day
個日
est 19
期中
axs] ,"Tuaxs] ebru"Oct
數,將
前日
52 ||
整除
則 y
個函數
ear 是
計算 y
ar, isL
,判
1≤da
日的
開主演
進行轉
752 年
y, yea
期;
997
,月份
/uesd
/uary"tobe
將其作
日期的
(yea
,則
year
數:
是否是
year
Leap(
別 ye
ay≤da
的範圍
演算法
轉換
年 9 月
ar,old
否則
份和
//表示ay",//表示", "Mr",
作為
的年月
r ==
則 yea
是閏
是閏年
年的
(year,
ear 年
ays_o
圍內)
法了
:
月 2
d) 函數
則計算
和星期
示星期"Wed
示月份Marc"Nov
為對應
月日
1752
ar 是
閏年
年。
的天數
, old)
年 mo
of_m
),則
了:反
日前
數判別
算累計
期是字
期幾的dnes份的字ch", vemb
應字串
日整數
2 &&
是閏年
。
數。
)),計
onth 月
month
有效
反覆讀
的日
別該
計西元
字串
的字串sday"字串常"Apr
ber",
串常數
數;o
& mo
年;否
計算 y
月 da
h(mon
效。
讀入
日期,
日期
元 0 年
,因
串常數","T
常數ril", "D
數陣
old 為
onth
否則若
year
ay 天
nth, y
目前
若是
是否
年至該
因此設
數 hurs
,"Maecem
陣列的
為目前
< 9)
若 ye
年 m
是否
year, i
前日期
是則旗
否為無
該日
設月份
sday
ay",mber
的下標
前日
|| (y
ear 能
month
否為無
isLea
期的 y
旗標 o
無效日
期的
份和
","F
"Jun"};
標,便
期屬
ear =
能被
h 月的
無效日
ap(ye
year
old。
日期。
的總天
星期
Frida
ne",
便可
屬於 1
== 17
4 整
的天數
日期。
ear, o
、mo
。若是
天數:
期的字
ay",
"Ju
可以直
1752
752 &
整除,
數。
。若(
ld)) &
onth
是,則
字串常
"Sat
uly",
直接取
年 9
&& m
,但不
(yea
&&(
、da
則輸
常數
turda
,"Aug
取出表
9 月
mont
不能
ar≥1
(該日
ay,每
出無
:
ay"}
gust
表述
2 日
th ==
被 1
)&&
日期不
每讀
效日
;
t",
述日
前
= 9
00
&
不
讀入
期
Chapter 04 應用直接存取類的線性串列程式設計
- 4-7 -
sum= days_of_year(i,old)+ day_of_month(i,year,isLeap(year,old))+daymonth-1i=1
month-1i=1
若該日期在 1752 年 9 月 2 日之後,則為星期 (sum % 7);否則為星期 ((sum+5)% 7),輸出轉換
後的日期,並繼續讀下一個日期。
上述過程一直進行至 year、month 和 day 全為 0 為止。
參考程式
#include <iostream> //預編譯命令 #include <cstdio> #include <cstring> using namespace std; //使用 C++標準程式庫中的所有識別字 const int maxs = 20; //字串常數表的容量 //表示星期幾的字串常數 const char wstr[][maxs] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; //表示月份的字串常數 const char mstr[][maxs] = {"", "January", "February", "March", "April","May", "June", "July", "August", "September", "October", "November", "December"}; bool isLeap(int year, bool old = false) //判斷 year 是否是閏年 { if (old) //year 年 month 月 day 日在 1752 年 9 月 2 日前 return year % 4 == 0 ? true : false; return (year % 100 == 0 ? (year % 400 == 0 ? true : false) : (year % 4 == 0 ? true : false)); } //返回 year 年 month 月的天數 int days_of_month(int month, int year, bool leap) { if (month == 2) return leap ? 29 : 28; int d; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: d = 31; break; default: d = 30; } return d; } //返回 year 年的天數 int days_of_year(int year, bool old)
-
提
4-8
提升程
-
/i
//b
/b
i
程式設
{ r
}
//返回int {
iw
r}
//若//不在bool{
i i i i r
}
//若bool{
r
}
int {
i
c
w
設計的
retur
回 s 在getN
int iwhile
retur
year在 17 val
if (y
if (m
if (d
if (y
retur
year isO
retur
main
int m
cin >
while
的資料
rn i
在 ssNum(
i = e (i ++i
rn i
r≥1 且752 年lid(
year ret
montret
day ret
year ret
rn t
r 年 mOld(
rn y(ye
n(vo
mont
>> m
e (mbooif } e
料結
sLea
s 中的char
0;< t;
< t
且 mon年 9 月int
< 1turn h < turn < 1 turn ==
turn rue;
monthint
ear ear =
id)
h, d
month
monthol ol(!va
co<<
else info
fo
suin
結構力
ap(ye
的位置r s[]
tot &
tot
nth∈月 3 日mont
1) fal0 |fal|| dfal1752fal
;
h 月 dmont
< 17== 1
day,
h >>
h || ld = alidout < " {nt sor (
or (
um +nt w
力
ear,
,如果], c
&& s
? i
∈{1.日至 1th,
se;| mose;day se;2 &&se;
day 日th,
752 752
yea
day
dayisO(mon<< mis a
um =int sum int sum = daweek
old
果 s 在const
strcm
: -1
.12}3 日的int
onth
> da
& mon
日在 1int
|| && m
ar;
y >>
y || Old(mnth, monthan in
= 0; yy =+= mm =+=
ay;= su
d) ?
在 sst ch
mp(s
1;
且 da的範圍day
> 1
ays_
nth
1752day
(yeamont
yea
yeamontdayh <<nval
= 1;days= 1;days
um %
366
中不ar s
, ss
ay∈{圍內,, in
2)
_of_m
== 9
年 9, in
r ==th ==
r;
r) {th, dy, ye< '/lid d
yy s_of_ mm s_of_
% 7;
6 : 3
不存在ss[]
s[i]
1.. 則返
nt ye
month
9 &&
月 2nt ye
= 175= 9
{ day, ear, ' <<date
< y_yea< m_mon
365;
,則返[max
))
year返回 trear,
h(mo
3 <
日前ear)
52 &&& d
yeaold day." <
year;ar(yymonthnth(m
返回-xs],
r 年 mrue; boo
onth,
<= da
,則返
&& moday <
ar);d)) y << << en
; yy+y, oh; mmmm,
-1 int
mont;否則ol o
, ye
ay &
返回
onth <= 2
//主//主
//讀
//計{//處'/'ndl;//累
++)ld);m++)year
//計
tot
th 月的則返回ld)
ar,
& da
true
< 9);
主函數主函數
讀入日
計算該處理無 <<
累計西
; r, is
計算星
t)
的天數回 fal
isLe
ay <=
e;否
9) |
數 數開始
日期
該日期無效日yea
西元 0
sLea
星期幾
數}且se
eap(
= 13
則返回
|
始
是否在期r
年至
ap(ye
幾
year
year
)
回 fa
在 17
該日期
ear,
r 年 m
r, o
alse
752 年
期的總
old
mont
ld))
年 9 月
總天數
d));
th 月
)
月 2 日
數
day 天
日前
天
Chapter 04 應用直接存取類的線性串列程式設計
- 4-9 -
if (old) //若該日期在 1752 年 9 月 2 日前 week = (week + 5) % 7; //輸出轉換後的日期和星期幾 cout << mstr[month] << ' ' << day << ", " << year << " is a " << wstr[week] << endl; } cin >> month >> day >> year; //輸入下一個測試組的日期 } return 0; }
-
提
4-10
提升程
0 -
4.
程式
電腦
過了
高精
高
用一
列中
十進
iiscnf
由上
序號
串列
高
高精
高精
高精
位處
x 和
下
f
程式設
2
式設
腦
了這
精度
高精度
一個
中。
進位
int int stricin>n=s.for
a
上可
號,
列。
高精度
精度
精度
精度
處理
和 y 按
:
for a
設計的
陣
設計語
多只
這個範
度數,
度數
個陣列
在具
位數儲
a[10n; ng s>>s; leng(i=0a[i]=
可見,
下標
度數
度數的
度數的
度數
理,高
按如
(i=0a[i]=
的資料
陣列
語言所
只能輸
範圍
有兩
數的表
列表示
具體的
儲存到
00]=
s;
gth(0; i=s[n
高精
標變數
數的基
的基本
的加和
基本
高精度
上的
0; i=a[i
料結
列
所能表
輸出
,電腦
兩個基
表示
示一個
的實作
到一個
{0};
); <n; -i-1
精度數
數的元
基本
本運算
和減
本的運
度數的
的形式
<(n1]+b[
結構力
應
表示
16 位
腦就
基本
示
個高
作中
個陣
i++)1]-'0
數按
元素
本運
算包
減
運算
的減
式儲存
1>n2 [i];
力
應用
示和處
位有效
就無法
本問題
高精度
,先
陣列中
)0';
照十
素值對
運算
包括 '+
算是加
減則要
存在
? n
用二
處理的
效的
法正確
題:高
度數
先採用
中。例
////////////
十進位
對應目
+'、'
加和減
要考慮
陣列
n1 :
二:
的整
的十進
確表示
高精度
:將數
用字串
例如
陣列n 用來字串輸入數計算位陣列
位的順
目前位
-'、'
減。和
慮借位
列 a 和
n2)
高
數和
進位數
示了
度數
數字
串來
,對
a 用來來存放s 用來數字串位長 a 從右
順序
位的
*'、'
和算
位處
和陣列
; i+
高精
和實數
數字
了。在
數的表
字按十
來接收
對於一
來按位放高精來接收串
右向左
序儲存
的十進
'/'。
算術的
處理。
列 b
++){
精度
數的精
,處
在這種
表示和
十進位
收資料
一個高
位存放精度正收資料
左,按
存在整
進位數
的加減
。例如
中,
//
度運
精度
處理 1
種情況
和高精
位分離
料,然
高精
放高精正整數料
按位儲
整數陣
數字
減規則
如,求
n1 為
/進行/逐位
運算
通常
7 位
況下
精度
離,
然後
度正
精度正數的位數
儲存高
陣列
。因
則一
求兩
為 x
行 max位相加
算的
常是有
位有效
下,只
度數的
每位
將字
正整數
正整數數
高精度
列 a 中
此 a
一樣,
兩個非
的位
x{n1加
的實
有限的
效數字
只能透
的基本
位十進
字串中
數,接
,初值
正整數
中,陣
a 是一
程式
非負的
位數,
,n2}
實作
的,
字的正
透過程
本運
進位數
中的各
接收
值全為
數
陣列下
一種典
式中高
的高
,n2
}位加
作範
如:
正確
程式
算。
數字
各位
與儲
為 0
下標
典型
高精
精度
為 y
加法
範
在雙
確率為
式設計
字依次
位數字
儲存的
標對應
的直
精度數
度整數
的位
例
雙精度
為 90%
計來解
次儲存
字轉換
的程式
應高精
直接存
數的加
數 x 和
位數
例
度方
%。如
解決
存到一
換為對
式段
精度數
存取類
加要考
和 y
,程式
方式下
如果
。對
一個
對應
段如下
數的
類線
考慮
的和
式段
下,
果超
對於
陣
應的
下:
的位
線性
慮進
和。
段如
Chapter 04 應用直接存取類的線性串列程式設計
- 4-11 -
if ( a[i]>9 ) { //進位處理 a[i]=a[i]-10; a[i+1]++; } }
例如求兩個高精度正整數 x 和 y(x > y) 相減的差,x 和 y 按如上的形式儲存在陣列 a 和陣列
b 中,n 為 x 的位數。若 x < y,則 a 和 b 對換,相減後的差取負。陣列 a 和陣列 b 相減的
程式段如下:
for (i=0; i<n; i++) { if (a[i]>=b[i]) //若對應位夠減,則直接相減,否則借位相減 a[i]=a[i]-b[i]; else { a[i]=a[i]+10-b[i]; an[i+1]--; } }
高精度數的乘和除
下面在高精度數的加和減的基礎上討論高精度數的乘和除。進行高精度數的乘法運算,首
先要確定積的位數。設兩個高精度正整數 a 和 b,LA 為 a 的位數,LB 為 b 的位數。a 和 b
乘積的位數至少為 LA+LB-1,若乘後的第 LA+LB-1 位有進位,則乘積位數為 LA+LB。所
以,高精度正整數 a 和 b 的乘積的位數上限為 LA+LB。
高精度數乘法的演算法思考方式:首先計算被乘數與乘數的每位數字的乘積,其中 a[i] 乘
b[j]的積 累加到陣列 c[i+j] 上,然後對累加結果 c 做一次性進位。
for (i=0; i<=LA-1, i++) //被乘數 a 與乘數 b 的每位數字的乘積累加到積陣列 c 的對應位置上 for (j=0; j<=LB-1; j++) c[i+j] += a[i]*b[j]; for (i=0; i<LA+LB;i++) //累加結果做一次性進位 if(c[i] >= 10) { c[i+1] += c[i]/10; c[i] %= 10; }
求高精度正整數 A÷高精度正整數 B 的商和餘數。演算法思考邏輯如下:
先比較 A 和 B,如果 A<B,則商為 0,餘數為 A;否則基於高精度正整數的減法開始整除,
根據 A 和 B 的位數之差 d1 看 A 夠減 B*10d1 的次數 a1,得到餘數 y1=A- a1*B*10d1;然後計
算 y1 和 B 的位數之差 d2,看 y1 夠減 B*10d2 的次數 a2,得到餘數 y2=y1-a2*B*10d2;⋯;依
此類推,直至得出 yk-1 夠減 B 的次數 ak 為止。 後得到餘數 y= yk-1- ak*B,a1()a2⋯()ak 即為
商(請注意:( ) 表示若 di - di+1 > 1,則 ai+1 前須補 di - di+1 -1 個 0,2≤ i ≤ k-1)。
-
提
4-12
4
提升程
2 -
比如
y1=
餘數
有興
.2.
Ma
太喜
悲劇
的意
反向
例如
字元
向數
AC
然
120
輸入
輸由
輸出
對去
樣
3 244330
試題
線上
程式設
如 A
=1234
數 y2
興趣
1
alidin
喜歡
劇改
意義
向數
如,
元為
數是
CM 需
,結果
0 或
入
輸入由由空格
出
對每個去。
樣例輸
4 1 358 705 79
題來源
上測試
設計的
A =1
45-1
2=345
趣的讀
A
nesia
歡演悲
改編為
義,所
數是將
在悲
為零要
是 21)
需要
果不
1200
由 N 個格分開
個測試
輸入:
54 4
源:A
試:P
的資料
2345
2*10
5-2*
讀者不
Add
a 的古
悲劇
為喜劇
所以這
將一個
悲劇中
要被省
)。還
要對反
不是唯
0)。
個測試開的正
試用例
ACM
POJ 15
料結
5,B
03=34
12*1
不妨可
din
古典喜
。但不
劇。顯
這項工
個阿拉
中主角
省略
還要注
反向數
唯一的
為此
試用例正整數
例,輸
Centr
504,
結構力
B=12
45;
101=1
可以
g R
喜劇
不幸
顯然
工作
拉伯
角有
,所
注意反
數進行
的,因
此,本
例組成數組成
輸出一
ral Eu
ZOJ
力
2,位
345
105;
以試編
Rev
劇演員
幸的是
然,雖
作是很
伯數字
有 124
以,
反向
行計
因為一
本題設
成。輸,這是
行,僅
urope
2001
位數之
與 1
y2 夠
編一下
ver
員(A
是,大
雖然所
很困難
字按相
45 只
如果
向數沒
計算。
一個
設定
入的第是要反
僅包含
1998
1,UV
之 d1
12 的
夠減 1
下高精
rse
Antiq
大多數
所有的
難的
相反的
只草莓
果數字
沒有零
。你的
數可
定沒有
第一行反向相
含一個
8
VA 71
1=3,
的位數
12 的
精度
ed N
que C
數古
的事
。
的次
莓,現
字結
零結尾
的任
可以是
有 0 因
行僅列相加的
個整數
13
則
數之差
次數
度除法
Nu
Come
古典戲
事物都
次序寫
現在則
尾有
尾。
務是
是幾個
因為反
列出正的數。
數,將
1234
差 d2
數 a3=
法的程
mb
edian
戲劇是
都改成
寫。把
則有
有零,
是將兩
個數
反向
正整數
將兩個
45 夠
=1,
=8,
程式
ber
ns of
是悲劇
成了它
把第一
有 542
,寫反
兩個反
數的反
向而丟
數 N,然
反向數
樣例輸
34 19981
夠減
345
終得
。
rs
Mal
劇。
它們
一個數
21 只
反向
反向
反向形
丟失
然後列
數進行
輸出
(12
夠減
得到餘
idine
所以
的反
數字寫
只草莓
數時
數相
形式(
(例
列出測
行求和
:
2*103
減(1
餘數
esia
以 AC
反面
寫成
莓了
時零會
相加,
(例如
如,
測試用
和,之
3)的
12*1
數 y=1
,AC
CM 的
,但因
成 後
。請注
會被略
,並輸
如 21
設定
用例。
之後再
的次數
01)
05-8
CM)
的戲
因為
後一個
注意
略去
輸出
1 在反
定原來
每個
再反向
數 a
的次
8*12=
喜歡
戲劇指
必須
個數字
意,數
(例
它們
反向
來的
測試用
。在輸
1=1
次數 a
=9 和
歡演喜
指導決
須保持
字,依
數字所
例如,
們的反
前可
數是
用例一
輸出時
,得到
a2=2
和商 1
喜劇
決定將
持劇本
依次類
所有的
120
反向和
可以是
是 12
一行,
時把前
到餘
,得
1028
,而
將一
本原
類推
的前
00 的
和。
是 12
)。
由 2
前導 0
餘數
得到
8。
而不
一些
原有
推。
前置
反
當
2,
2 個
0 略
Chapter 04 應用直接存取類的線性串列程式設計
- 4-13 -
▼解題與分析
設:
Num[0][0] 為被加數的長度,被加數為 Num[0][1..Num[0][0]]。
Num[1][0] 為加數的長度,加數為 Num[1][1..Num[1][0]]。
Num[2][0] 為和的長度,和為 Num[2][1..Num[2][0]]。
首先,分別輸入被加數和加數的數字串,在捨去了尾部的無用 0 後存入 Num[0]和 Num[1],
再 將它們反向儲存。然後,Num[0] 和 Num[1] 相加,得出和陣列 Num[2]。 後反向輸出
Num[2],注意略去尾部的無用 0。
參考程式
#include <iostream> //預編譯命令 #include <cstdio> #include <cstring> #include <string> using namespace std; //使用 C++標準程式庫中的所有識別字 int Num[3][1000]; //Num[0][0]為被加數的長度,被加數為 Num[0][1..Num[0][0]]; //Num[1][0]為加數的長度,加數為 Num[1][1..Num[1][0]];Num[2][0]為和的長度,和為 //Num[2][1..Num[2][0]] void Read(int Ord) //Ord=0,輸入和處理被加數;Ord=1,輸入和處理加數 { int flag=0; string Tmp; cin>>Tmp; //讀數字串 for(int i=Tmp.length()-1;i>=0;i--) //由右而左分析每個數字 { if(Tmp[i] > '0') //捨去尾部的無用 0 後存入高精度陣列 Num[Ord] flag = 1; if(flag) Num[Ord][++Num[Ord][0]] = Tmp[i] - '0'; } for(int i=Num[Ord][0],j=1;i>j;i--,j++) //計算反向數 Num[Ord] { flag = Num[Ord][i]; Num[Ord][i] = Num[Ord][j]; Num[Ord][j] = flag; } } void Add() { Num[2][0] = max(Num[0][0],Num[1][0]); //加數和被加數的 大長度作為相加次數 for(int i=1;i<=Num[2][0];i++) //逐位相加 Num[2][i] = Num[0][i] + Num[1][i]; for(int i=1;i<=Num[2][0];i++) //進位處理 { Num[2][i+1] += Num[2][i]/10; Num[2][i] %= 10;
-
提
4-14
4
提升程
4 -
i
有時
用物
.2.2輸入
分
的 輸出
對
樣
3 4
試題
線上
程式設
}i if{ }p
}
int {
icf{ }r
}
時候
物件
2 入
分別列
的答案
出
對於輸
樣例輸
3 4
題來源
上測試
設計的
if(Nu
int ffor(i
main
int Ncin>>for(N
retur
候,同
件導向
V
列出 N
案。
輸入每
輸入:
源:T
試:U
的資料
um[2Num
flag int
if( if(
tf("
n()
N; >N; N;N;
memReaReaAdd
rn 0
同類的
向的程
VER
N 和 A
每一行
THE S
UVA 1
料結
][Num[2]= 0i=1;
Numfl
flagpr
\n")
N--)
msetad(0)ad(1)d();
;
的高
程式設
RY
A 的值
行,在
SAMS
10523
結構力
um[2][0] 0; ;i<=N
[2][lag g) rint
;
(Num););
精度
設計
Y EA
值(都
在一行
S, CO
3
力
][0]++;
Num[
i] >= 1;
f("%
,0,s
度運算
計方法
AS
都是整
中輸出
ONTE
+1]
[2][0
> 0) ;
%d",N
sizeo
算需要
法可使
SY !
數,1
出對應
ST
> 0
0];i
Num[
of(N
要反
使程式
!!!
1 ≤ N
應於 N
)
++)
[2][i
Num))
覆進
式結
N ≤ 15
N 和 A
i]);
);
進行
結構更
50,0
A 的總
(例如
更為清
0 ≤ A∗總和的
如計
清晰
≤ 15∗的整數
樣例輸
1021252
//處
//反
//主//主//輸
//輸
//高//輸//輸//相
計算乘
,運
)。請
值。
輸出
處理
反向輸
主函數主函數輸入測
輸入和
高精度輸入處輸入處相加後
乘冪或
運算更
請列出
:
高位
輸出和
數 數開始測試用
和處理
度陣列處理和處理和後反向
或多
更為簡
出級數
位的進位
和(去除
始 例數
理每個測
列初始化和被加數和加數
輸出
項式
簡便
位
除前導
測試用
化為數
式)。
。
導 0)
用例
0
在這
)
這種情情況下下,採
Chapter 04 應用直接存取類的線性串列程式設計
- 4-15 -
▼解題與分析
由級數∑ i*AiNi=1 中項數 N 的上限(150)、底數 A 的上限(15)可以看出,計算乘冪、目前
項及數和非採用高精度運算不可。由於計算過程需要反覆進行高精度的乘法和加法,因此
比較適宜於採用物件導向的程式設計方法。
定義一個名稱為 bigNumber 的類別,其私有部分(private)為一個長度是 len 的高精度陣
列 a,被 bigNumber 類的物件和成員函數存取。其公共介面(public)包括:
bigNumber() 高精度陣列 a 初始化為 0。
int length() 返回高精度陣列 a 的長度。
int at(int k) 返回 a[k]。
void setnum(char s[]) 將字串 s[]轉換成長度為 len 的高精度陣列 a。
bool isZero() 判斷高精度陣列 a 是否為 0。
void add(bigNumber &x) 高精度加法運算:a←a+x。
void multi(bigNumber &x) 高精度乘法運算:a←a*x。
它們是程式可使用的全域函數。
有了以上類別的定義,可使得計算∑ i*AiNi=1 的過程變得十分簡便和清晰:
1) 首先,定義底數 a 和乘冪 ap 為 bigNumber 類別的物件(bigNumber a, ap);將底數字
串 s 轉化為高精度陣列 a(a.setnum(s));乘冪陣列 ap 初始化為 1(ap.setnum("1"));
定義數和 sum 為 bigNumber 類別的物件(bigNumber sum)。
2) 然後迴圈 n 次,每次迴圈計算目前項 i*Ai,並累加入數和 sum:
定義目前項 num 為 bigNumber 類別的物件(bigNumber num)。
num 初始化為 i(sprintf(s, "%d", i; num.setnum(s)))。
計算乘冪 ap←ap*a 和目前項 num←num*ap(ap.multi(a);num.multi(ap))。
累加目前項 sum←sum+num(sum.add(num))。
3) 輸出級數∑ ∗ 的數和 sum.at(sum.length() - 1)⋯sum.at(0)。
-
提
4-16
提升程
6 -
參
##cc c
程式設
參考程
#inc#incconscons
clasp
p
設計的
程式
cludecludest inst in
ss bipriva
publi
的資料
e <ce <cnt mnt m
igNumate: intint
ic: big }
int }
int }
voi }
boo }
voi
}
voi
料結
stdistriaxleaxs
mber
t a[mt len
gNumbmele
t lenre
t atif
re
d selefo
ol isre
d adfo
}inwh
}
le
d muif
結構力
io>ing>en = = 5
r {
maxln;
ber(emseen =
ngthetur
(int f (0
etur
etnumen =or (
sZeretur
dd(bor (
nt khile
en =
ultif (x
力
500;
en];
) {t(a, 1;
() {rn le
k) <= retu
rn -1
m(ch 0;int a[le
o() rn le
igNuint a[i]a[i a[i]
k = x (a[a[k a[k+
len
(bigx.isZsetn
; ////
////
//
, 0,
{ en;
{ k &urn 1;
har s
i = en++
{ en ==
umberi = ] += + 1] %=
x.len[k]) + 1++]
n > k
gNumbZeronum(
高精度底數字
bigN私有部
公共介
siz
& k a[k]
s[])
str] =
= 1
r &x0; x.a] +=10;
n; {] +=%= 1
k ?
ber ())"0")
度陣列字串
Numb部分
介面
zeof
< le;
{
rlenint
&& a
x) { i < a[i]= a[i;
= a[k10;
len
&x)
;
列 a 的s 的容
er 類:長度
(a))
en)
//將
(s) (s[i
a[0]
x.l; i] /
k] /
: k
{
的容量容量
類別的度為 l
;
將字串
- 1;i] -
==
en;
/ 10;
/ 10;
k;
量
宣告len 的
串 s[]
; i '0'
0;
i++
;
;
的高精
]轉換
>= 0);
) {
精度陣
//
//
//
換成長
0; i-
//
////
//
//
//
陣列 a
/a 陣
/返回
/返回
長度為
--)
/判斷
/高精/逐位
/處理
/計算
/高精
列初始
回高精
回 a[k
len
斷高精
精度加位相加
理高位
算和的
精度乘
始化為
度陣列
k]
的高精
度陣列
法運算
的進位
實際位
法運算
為 0
列 a 的
精度陣
列 a 是
算:a
位
位數
算:a←
的長度
陣列 a
是否為
a←a+
←a*x
度
a
為 0
+x
x
Chapter 04 應用直接存取類的線性串列程式設計
- 4-17 -
int product[maxlen]; memset(product, 0, sizeof(product)); for (int i = 0; i < len; i++) //被乘數 a 與乘數 x 的每位數字的乘積累加到積陣列 product 的對應位數上 for (int j = 0; j < x.length(); j++) product[i + j] += a[i] * x.at(j); int k = 0; //按照低位至高位的順序,將每一位規範為十進位數字 while (k < len + x.length() - 1) { product[k + 1] += product[k] / 10; product[k++] %= 10; } while (product[k]) { //處理高位端的進位 product[k + 1] += product[k] / 10; product[k++] %= 10; } len = k; //設置乘積數位長度 memcpy(a, product, sizeof(product)); //乘積 product 轉指定給 a } }; int main(void) { int n; //項數 char s[maxs]; //底數字串 while (scanf("%d%s", &n, s) != EOF) { //反覆輸入項數和底數 bigNumber a, ap; //定義底數 a 和乘冪 ap 為 bigNumber 類別的物件 a.setnum(s); //將底數字串轉化為高精度陣列 a ap.setnum("1"); //高精度陣列 ap 初始化為 1 bigNumber sum; //定義數和 sum 為 bigNumber 類別的物件 for (int i = 1; i <= n; i++) { bigNumber num; //定義目前項 num 為 bigNumber 類別的物件 sprintf(s, "%d", i); //將 i 轉化為高精度陣列 num num.setnum(s); ap.multi(a); //計算乘冪 ap←ap*a num.multi(ap); //計算目前項 num←num*ap sum.add(num); //累加目前項 sum←sum+num }
for (int i = sum.length() - 1; i >= 0; i--) //輸出級數 ∑ i*AiNi=1 的數值
printf("%d", sum.at(i)); putchar('\n'); } return 0; }