111 地方特考三等 資訊處理 程式設計 考古題詳解
第 一 題13 分
有關 C 程式設計,回答下列問題:
(一) 下列程式執行結果為何?(13 分)
#include <stdio.h>
int func1(int a, int b){ printf("%3d %3d\n", a, b); if (b == 0) return a; else if (a % 2 && b % 2) return func1((a + b) / 2, (a - b) / 2); else if (a % 2 && !b % 2) return func1(a, b / 2); else if (!a % 2 && b % 2) return func1(a / 2, b); else return 2 * func1(a / 2, b / 2); }
int main(void) { int x = 19, y = 2; printf("%3d", func1(x, y)); }
(二) 下列程式執行結果為何?(10 分)
#include <stdio.h> #include <stdbool.h>
bool func2(int A[], int x, int y){ if (x > y) return false; else { int m = (x + y) / 2; printf("%3d %3d %3d\n", x, m, y); if (A[m] == m) return true; else if (A[m] > m) return func2(A, x, m - 1); else return func2(A, m + 1, y); } }
int main(void) { int a[] = {35, 60, 45, 7, 10, 22, 2, 50, 14, 3, 66}; printf("%3d", func2(a, 1, 10)); }
登入後即可作答並保存紀錄。
核心觀念
- 運算子優先權(Operator Precedence):
在 C 語言中,邏輯非運算子
!為單元運算子(Unary Operator),優先權等級為 2;取模運算子%為乘除類算術運算子(Multiplicative Operator),優先權等級為 3。單元運算子優先權高於算術運算子,因此運算式!b % 2依語法規則嚴格解析為(!b) % 2,而非!(b % 2)。 - C 語言之真偽值判斷: 在 C 語言中,任何非 數值皆視為真(True),數值 視為偽(False)。
- 對任意非零整數 , 之值為 ,故
(!b) % 2恆為 (False)。 - 僅當 時,,(True)。
- 遞迴函式追蹤(Recursion Tracing)與呼叫堆疊(Call Stack):
觀察函式之終止條件(Base Case)與遞迴轉移關係。回傳值若有係數乘法(如
2 * func1(...)),須於堆疊返回(Unwind)時逐層累乘。 - 格式化輸出控制碼:
printf("%3d %3d\n", a, b)代表以十進位整數格式輸出,欄寬固定為 3,向右靠齊(不足 3 位補空白),兩數之間間隔 1 個空白,並於結尾換行;main函式中的printf("%3d", ...)則無換行字元。
解題方法
1. 關鍵分支條件之嚴格語法分析
if (b == 0):遞迴終止條件,回傳 。else if (a % 2 && b % 2):當 為奇數且 為奇數時成立。else if (a % 2 && !b % 2): 依優先權規則,!b % 2等價於(!b) % 2。進入此分支前已排除 ,因此 恆成立。當 時,,。此條件結果恆為 (False),永遠不會執行。else if (!a % 2 && b % 2): 同理,!a % 2等價於(!a) % 2。當 時,,。只要 ,此條件結果亦恆為 (False),永遠不會執行。else: 當上述條件皆不成立時,執行return 2 * func1(a / 2, b / 2);。
2. 遞迴呼叫單步追蹤(Trace)
從 main 函式呼叫 func1(19, 2) 開始推導:
-
第 1 次呼叫:
func1(19, 2) -
印出:
19 2\n -
條件檢查:;(條件一不成立);條件二、條件三皆為偽。
-
執行
else:回傳 。 -
第 2 次呼叫:
func1(9, 1) -
印出:
9 1\n -
條件檢查:,滿足條件一
(a % 2 && b % 2)。 -
執行條件一:回傳 。
-
第 3 次呼叫:
func1(5, 4) -
印出:
5 4\n -
條件檢查:條件一、二、三皆不成立。
-
執行
else:回傳 。 -
第 4 次呼叫:
func1(2, 2) -
印出:
2 2\n -
條件檢查:條件一、二、三皆不成立。
-
執行
else:回傳 。 -
第 5 次呼叫:
func1(1, 1) -
印出:
1 1\n -
條件檢查:,滿足條件一。
-
執行條件一:回傳 。
-
第 6 次呼叫:
func1(1, 0) -
印出:
1 0\n -
條件檢查: 成立,回傳 。
3. 呼叫堆疊返回與計算
各層遞迴回傳值如下:
- 第 5 層:回傳
- 第 4 層:回傳
- 第 3 層:回傳
- 第 2 層:回傳
- 第 1 層:回傳
main 函式執行 printf("%3d", func1(x, y)),輸出靠右對齊之整數 8(前補 2 個空白)。
選項分析
本題為程式追蹤題,程式中各條件分支判斷如下:
if (b == 0):正確作為終止基準,成功於第 6 次呼叫終止遞迴。else if (a % 2 && b % 2):判斷兩數是否皆為奇數,於第 2 次及第 5 次呼叫觸發。else if (a % 2 && !b % 2)與else if (!a % 2 && b % 2):因運算子優先權導致!b % 2恆為 ,兩分支在此情境下均無法進入,直接落入else。else:承接所有偶數相除與分支未涵蓋之計算,提供 倍乘積的遞迴展開。
解題技巧
- 運算子優先權陷阱:
單元運算子
!的結合性強於二元運算子%。若題目欲表達「 為偶數」,正確寫法必須加括號寫成!(b % 2)或b % 2 == 0。 - 命題背景延伸探討(二元最大公因數演算法 Stein's Algorithm): 本題原型為求 的二元 GCD 演算法。
第 二 題14 分
有關 Python 程式設計,回答下列問題:
(一) 以下程式執行時,輸入正數為 15 和 21 時,其輸出結果分別為何?(14 分)
def func_2_1(x): y = 2 while y <= x: flag = True for i in range(2, y): if y % i == 0: flag = False break if flag == True: print(y, end='') y += 1
if name == "main": x = int(input('請輸入一正整數:')) print('輸出結果:') func_2_1(x) print('\n')
(二) 以下是將 整數串列,利用氣泡排序法,由小到大逐次排列,並顯示每一次排序的 Python 主程式。
if name == "main": x = [-5, 16, 30, -11, 26, -22] print('排序前:', end='') for i in range(6): print(' x[%d]=%3d' % (i, x[i]), end=' ') func_2_2(x) print()
此程式執行結果如下:
排序前: x[0] = -5 x[1] = 16 x[2] = 30 x[3] = -11 x[4] = 26 x[5] = -22 第 1 次排序: x[0] = -5 x[1] = 16 x[2] = -11 x[3] = 26 x[4] = -22 x[5] = 30 第 2 次排序: x[0] = -5 x[1] = -11 x[2] = 16 x[3] = -22 x[4] = 26 x[5] = 30 第 3 次排序: x[0] = -11 x[1] = -5 x[2] = -22 x[3] = 16 x[4] = 26 x[5] = 30 第 4 次排序: x[0] = -11 x[1] = -22 x[2] = -5 x[3] = 16 x[4] = 26 x[5] = 30 第 5 次排序: x[0] = -22 x[1] = -11 x[2] = -5 x[3] = 16 x[4] = 26 x[5] = 30
寫出氣泡排序法的 func_2_2(x) 函數,來完成上述程式。(11 分)
登入後即可作答並保存紀錄。
本題核心觀念
- 質數判定演算法(Trial Division 質數試除法):
- 質數定義為大於 且除 與本身外無其他因數之正整數。
- 程式利用巢狀迴圈:外層
while y <= x逐一檢查 至 的整數;內層for i in range(2, y)檢驗是否能被 整除。若整除(y % i == 0),則設定flag = False並提早break;若無任何因數,則flag維持True,判定為質數。
- Python 輸出格式控制:
print(y, end='')設定結尾字元為空字串,故輸出之數值不會換行亦無空格,緊密相連。
- 氣泡排序法(Bubble Sort)原理與實作:
- 概念:兩兩比較相鄰元素,若前項大於後項則進行交換(In-place swap),每一回合將目前未排序區間的最大值「沉底」推移至右側。
- 複雜度與回合數:長度為 的串列,共需進行 回合。第 次排序( 從 至 ),內部比較次數為 次。
解題方法與詳細推導
(一) 程式追蹤與輸出分析
- 函式
func_2_1(x)執行邏輯:
- 起始值 。
- 當 時:內層
range(2, 2)為空序列,for迴圈不執行,flag維持True,印出2。 - 當 時:
3 % 2 != 0,迴圈結束,印出3。 - 當 時:
4 % 2 == 0,flag = False,跳離不印出。 - 依此類推,該函式功能即為:依序找出 到 之間的所有質數,並連續不留空格印出。
- 案例 1:輸入
- 區間 的質數為:。
func_2_1(15)依序印出各質數且end='',結果為:23571113。
- 案例 2:輸入
- 區間 的質數為:。
func_2_1(21)依序印出各質數且end='',結果為:235711131719。
(二) 氣泡排序函式 func_2_2(x) 演算法設計
原始串列為 ,長度 。
- 各回合追蹤驗算:
- 第 1 次排序(比對至索引 4):
- 交換; 交換; 交換。
- 結果:(最大值 到達定位)。
- 第 2 次排序(比對至索引 3):
- 交換; 交換。
第 三 題25 分
有關 C++ 程式設計,回答以下問題:
建立一個 Rect 類別,其 Rect.h 定義如下:
class Rect { public: explicit Rect(double = 1.0, double = 1.0); void setWidth(double w); void setLength(double l); double getWidth() const; double getLength() const; double perimeter() const; double area() const;
private: double length; double width; };
其屬性有 length 和 width,每個屬性內定為 。提供計算矩形周長(perimeter)和面積(area)的成員函數。另外,提供寬度屬性的設定(setWidth)和獲取(getWidth)函數,也提供長度屬性的設定(setLength)和獲取(getLength)函數。設定函數要檢查長度和寬度均為大於 且小於 的浮點數。
以下為測試 Rect 類別的主程式:
#include <iostream> #include <iomanip> #include <stdexcept> #include "Rect.h"
using namespace std;
int main(){ Rect x, y(3.0, 4.0);
cout << fixed;
cout << setprecision(1);
cout << "x: length = " << x.getLength() << "; width = "
<< x.getWidth() << "; perimeter = " << x.perimeter()
<< "; area = " << x.area() << '\n';
cout << "y: length = " << y.getLength() << "; width = "
<< y.getWidth() << "; perimeter = " << y.perimeter()
<< "; area = " << y.area() << '\n';
}
執行結果如下:
x: length = 1.0; width = 1.0; perimeter = 4.0; area = 1.0 y: length = 4.0; width = 3.0; perimeter = 14.0; area = 12.0
寫出 Rect.h 中的 Rect()、setWidth()、setLength()、getWidth()、getLength()、perimeter()、area() 等 C++ 函數,來完成上述主程式和執行結果的功能。(25 分)
登入後即可作答並保存紀錄。
核心觀念
本題為典型的 C++ 物件導向程式設計(OOP)類別實作題,評量考生將類別規格書(介面宣告 .h)轉化為具體實作(.cpp)的實作能力。核心考點包含:
- 封裝(Encapsulation)與資料隱藏(Data Hiding):將屬性宣告為
private,並透過public的成員函數(Getter / Setter)進行存取與驗證,確保物件內部狀態的一致性與有效性。 - 建構子(Constructor)與預設引數(Default Arguments)規範:
- 標頭檔
Rect.h已宣告預設引數explicit Rect(double = 1.0, double = 1.0);。依 C++ 語法標準,在實作檔(.cpp)定義建構子時,不可重複指定預設引數,否則會引發編譯錯誤(Redefinition of default argument)。
- 常數成員函數(
constMember Functions):
- 檢查物件狀態而不修改屬性的檢索函數(如
getWidth、getLength、perimeter、area)需在函數標頭後方加上const修飾詞,實作時亦必須保留。
- 屬性驗證與例外處理機制:
- 設定函數需驗證數值範圍為 。主程式引入了
<stdexcept>標頭檔,暗示當傳入不合法數值時,物件導向標準作法為拋出std::invalid_argument例外;亦可將數值重設為預設值 。
- 幾何計算公式:
- 周長公式:
- 面積公式:
解題方法
1. 判斷建構子之參數對應順序
主程式中建立物件:
Rect x, y(3.0, 4.0);
其對應的輸出結果為:
y: length = 4.0; width = 3.0; perimeter = 14.0; area = 12.0
分析可知:傳入的引數分別為 與 ,而輸出顯示 且 。此外,在 Rect.h 的宣告順序中,setWidth 位於 setLength 之前。這明確指出建構子的第一個參數為寬度(width),第二個參數為長度(length):
2. 建構子實作策略
在建構子內部,不宜直接對私有成員變數賦值,最佳實務是直接呼叫成員函數 setWidth(w) 與 setLength(l)。如此可重用邊界檢查邏輯,避免代碼重複(DRY 原則),確保物件在初始化時即符合邊界條件。
3. 邊界檢查與設定函數(setWidth / setLength)
題目規定:「長度和寬度均為大於 且小於 的浮點數」。
條件判斷式為:
主程式已包含 #include <stdexcept>,若傳入數值未符合區間條件,丟出 std::invalid_argument 例外;
第 四 題11 分
有關 Java 程式設計,回答下列問題:
(一) 寫一個尋找小於 10,000 的完美數(Perfect number)程式。所謂完美數是指:如果一個正整數等於它所有正因數的和,但不包括它自己,則此正整數被稱為完美數。例如,。接下來是 。(11 分)
(二) 以下程式功能為何?當輸入 32、56、80 時,其輸出結果分別為多少?(16 分)
import java.util.Scanner;
public class LSE111_r4_2 { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("輸入一整數:"); int value = input.nextInt(); String oS = "";
while (value != 0) {
int s = value % 8;
oS = s + oS;
value = value / 8;
}
System.out.println("輸出為:" + oS);
}
}
登入後即可作答並保存紀錄。
核心觀念
- 完美數(Perfect Number)之數學定義與因數求和: 正整數 的「真因數(Proper Divisor)」指小於 且能整除 的所有正因數。若所有真因數之和恰好等於 本身,即滿足: 則稱 為完美數。程式設計的核心在於利用迴圈遍歷範圍內的整數,並對每個整數求其真因數總和進行比對。
- 基底轉換(Radix Conversion)之短除法原理: 十進位整數轉換為 進位制時,採用「除以基底取餘數法(短除法)」。每次將數值除以基底 :
- 餘數(
value % B)為該位數之數值。 - 商數(
value / B)作為下一輪疊代的被除數。 - 越後計算出的餘數代表越高位元(Most Significant Digit)。
- Java 字串前置串接(String Prepending):
程式碼中運算式
oS = s + oS;將新產生的低位元餘數轉為字串後串接於舊字串前端,恰好符合短除法「反向取餘數」組合出高位在前之特性。
解題方法
(一) 尋找小於 10,000 的完美數程式
要找出小於 10,000 的所有完美數,外層迴圈從 檢查至 (最小的正整數完美數為 , 的真因數總和為 ,故不為完美數)。 內層迴圈計算真因數和:最直觀的方法是走訪 到 ;亦可走訪 到 以大幅提升效率。由於 規模較小,走訪至 簡潔明瞭且執行速度極快。
public class PerfectNumbers {
public static void main(String[] args) {
System.out.println("小於 10000 的完美數有:");
for (int num = 2; num < 10000; num++) {
int sum = 0;
// 尋找 num 的所有真因數並累加
for (int i = 1; i <= num / 2; i++) {
if (num % i == 0) {
sum += i;
}
}
// 判斷真因數和是否等於自身
if (sum == num) {
System.out.println(num);
}
}
}
}
註:小於 10,000 的完美數依序為 、、、。
(二) 程式功能分析與執行追蹤
- 程式功能: 本程式的功能為將使用者輸入的十進位正整數轉換為「八進位(Octal)」字串並印出。
- 運算式
s = value % 8:求出目前最低位的八進位數字。 - 運算式
oS = s + oS:將新取得的位數置於字串最左側(高位元位置)。 - 運算式
value = value / 8:將十進位數值右移一個八進位位元(去除已處理的最低位)。
- 輸入追蹤與推導:
- 當輸入為 32 時:
- 第 1 次迴圈:,,