115 高普考普通考試 資訊處理 程式設計概要 考古題詳解
第 一 題24 分
請完成以下 Java 程式(class Circle:code 1~code 3,class Rectangle:code 4~code 6,main:code 7~code 8),使其可以印出最後一張圖的內容。
- 第一、三個方框:code 1、code 4,class Circle/Rectangle 宣告繼承父類別。
- 第二個方框:code 2、code 3,實作 Circle 計算面積、周長的方法。
- 第四個方框:code 5、code 6,實作 Rectangle 計算面積、周長的方法。
- 第五個方框:code 7、code 8,多型方式宣告 Circle/Rectangle 物件。
程式碼如下:
package PDconcept_OO;
import java.util.ArrayList;
//===== Interface:定義所有幾何形狀都必須實作的方法 =====// interface IShape { double computeArea(); double computePerimeter(); }
//===== 父類別 Shape,負責統一對外呼叫、顯示結果 =====// abstract class Shape implements IShape { protected String shapeName;
public Shape(String shapeName) {
this.shapeName = shapeName;
}
public abstract double computeArea();
public abstract double computePerimeter();
public void showResult() {
System.out.println("Shape: " + shapeName);
System.out.printf("Area: %.2f%n", computeArea());
System.out.printf("Perimeter: %.2f%n", computePerimeter());
System.out.println("--------------------");
}
}
//===== Circle 類別:繼承 Shape,實作圓形計算 =====// class Circle ____ { private double radius;
public Circle(double radius) {
super("Circle");
this.radius = radius;
}
____ // code 2:實作計算面積
____ // code 3:實作計算周長
}
//===== Rectangle 類別:繼承 Shape,實作矩形計算 =====// class Rectangle ____ { private double width; private double height;
public Rectangle(double width, double height) {
super("Rectangle");
this.width = width;
this.height = height;
}
____ // code 5:實作計算面積
____ // code 6:實作計算周長
}
//===== 主程式呼叫範例 =====// public class OO { public static void main(String[] args) { Shape s1 = new Circle(5); Shape s2 = new Rectangle(4, 6);
s1.showResult();
s2.showResult();
ArrayList<Shape> shapes = new ArrayList<>();
shapes.add(____); // code 7:宣告物件
shapes.add(____); // code 8:宣告物件
for (Shape shape : shapes) {
shape.showResult();
}
}
}
程式輸出如下:
Shape: Circle Area: 78.54 Perimeter: 31.42
Shape: Rectangle Area: 24.00 Perimeter: 20.00
Shape: Circle Area: 314.16 Perimeter: 62.83
Shape: Rectangle Area: 29.25 Perimeter: 22.00
登入後即可作答並保存紀錄。
核心觀念
本題考查 Java 的繼承、抽象類別、多型與方法覆寫,以及圓形、矩形的面積和周長公式。
IShape是介面,定義所有形狀都必須提供的computeArea與computePerimeter。- 抽象類別
Shape實作IShape,並將這兩個方法宣告為抽象方法。子類別必須提供方法實作。 Circle與Rectangle繼承Shape,以@Override覆寫計算方法。Shape型別的參考可以指向Circle或Rectangle物件。呼叫覆寫方法時,Java 會依物件的實際型別執行對應方法,這就是多型。
計算公式為:
解題方法
先依類別關係填入繼承宣告:Circle 與 Rectangle 都繼承 Shape,因此使用 extends Shape。
接著,依各類別的欄位撰寫計算方法:
Circle使用radius計算面積與周長。Rectangle使用width、height計算面積與周長。- 方法回傳型別為
double,與父類別宣告及介面規格一致。
最後,ArrayList<Shape> 的元素型別是 Shape,因此可加入以 Shape 型別宣告、實際建立為圓形或矩形的物件。以下以半徑 10 的圓,以及寬 3.5、高 4.5 的矩形,使輸出符合題目。
填入程式碼
class Circle extends Shape {
private double radius;
public Circle(double radius) {
super("Circle");
this.radius = radius;
}
@Override
public double computeArea {
return Math.PI * radius * radius;
}
@Override
public double computePerimeter {
return 2 * Math.PI * radius;
}
}
class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
super("Rectangle");
this.width = width;
this.height = height;
}
@Override
public double computeArea {
return width * height;
}
@Override
public double computePerimeter {
return 2 * (width + height);
}
}
main 中的兩個空格填入:
第 二 題20 分
請說明如下 C# 程式,正確執行時的輸出結果為何?如若無法正確執行(即會出現執行時期的錯誤),請說明應如何修正才能正常執行及輸出結果為何。
public class ReferenceDT { public static void refDT(int[] rdt) { rdt[0] = 10; rdt = new int[] { 100, 200, 300 }; rdt[1] = 20; }
public static void refDT(ref int[] rdt)
{
rdt[0] = 10;
rdt = new int[] { 100, 200, 300 };
rdt[1] = 20;
}
public static void printArray<E>(E[] source)
{
if (source == null) {
Console.WriteLine("null");
return;
}
for (int i = 0; i < source.Length; i++) {
Console.Write(source[i] + " ");
}
Console.WriteLine();
}
}
// 主程式中,執行的 code int[] data = { -10, -20, -30 };
Console.Write("Source --> "); ReferenceDT.printArray(data);
ReferenceDT.refDT(data); Console.Write("After refDT(data) --> "); ReferenceDT.printArray(data);
ReferenceDT.refDT(ref data); Console.Write("After refDT(ref data) --> "); ReferenceDT.printArray(data);
登入後即可作答並保存紀錄。
核心觀念
本題考查 C# 陣列是參考型別,以及一般參數傳遞與 ref 參數傳遞的差異。
- 呼叫
refDT(int[] rdt)時,方法取得的是陣列參考的副本。方法可透過此參考修改原陣列內容,但將rdt指向另一個新陣列,只會改變方法內的區域參考,不會改變呼叫端的data。 - 呼叫
refDT(ref int[] rdt)時,ref讓方法直接操作呼叫端的變數。方法將rdt指向新陣列後,呼叫端的data也會指向該新陣列。 - 兩個方法名稱相同,但參數是否含
ref不同,因此是不同的多載。呼叫時必須配合參數宣告使用ref關鍵字。
解題方法
依序追蹤呼叫端的 data 指向哪個陣列,以及各陣列元素如何變化。
- 初始時,
data指向陣列{-10, -20, -30},因此第一次印出:
Source --> -10 -20 -30
- 呼叫
refDT(data),執行的是未使用ref的版本。
rdt[0] = 10;透過參考副本修改原陣列,故原陣列變成{10, -20, -30}。rdt = new int[] { 100, 200, 300 };只讓方法內的rdt指向新陣列,呼叫端的data仍指向原陣列。rdt[1] = 20;修改新陣列,但方法結束後該陣列不再由data參照。
因此第二次印出:
After refDT(data) --> 10 -20 -30
第 三 題20 分
請說明如下 C 程式,正確執行時的輸出結果為何?如若無法正確執行(即會出現執行時期的錯誤),請說明應如何修正才能正常執行及輸出結果為何。
int* find2(int source[], int len, bool flag, int* newLen) { int first; int second; int startInd = 2; static int result[2];
if (source == NULL || len < 2) {
*newLen = 0;
return NULL;
}
if (flag)
{
if (source[0] <= source[1]) {
first = source[0];
second = source[1];
}
else {
first = source[1];
second = source[0];
}
for (int i = startInd; i < len; i++)
{
if (source[i] > first) {
second = first;
first = source[i];
}
else if (source[i] < second) {
second = source[i];
}
}
printf("StartInd: %d, first: %d, second: %d\n",
startInd, first, second);
}
else
{
if (source[0] >= source[1]) {
first = source[0];
second = source[1];
}
else {
first = source[1];
second = source[0];
}
while (startInd < len)
{
if (source[startInd] > first) {
second = first;
first = source[startInd];
}
else if (source[startInd] > second) {
second = source[startInd];
}
startInd++;
}
printf("StartInd: %d, first: %d, second: %d\n",
startInd, first, second);
}
result[0] = first;
result[1] = second;
*newLen = 2;
return result;
}
// End of find2
void main() { int source[] = { 35, 12, 23, 11, 24, 36, 59, 48, 47 }; int len = sizeof(source) / sizeof(source[0]); int* data = source;
data = find2(data, len, true, &len);
printf("Result 1: %d, Result 2: %d\n", data[0], data[1]);
data = find2(data, len, false, &len);
printf("Result 1: %d, Result 2: %d\n", data[0], data[1]);
}
登入後即可作答並保存紀錄。
核心觀念
本題考查陣列走訪、指標與回傳值、static 區域陣列,以及函式參數經指標修改呼叫端變數的效果。
find2 依 flag 分別尋找兩個數值:
flag == true:尋找最大值與第二大值;程式以<更新second,所以相同最大值不會被視為第二大值。flag == false:尋找最大值與次大值;程式以>更新second,相同最大值可以成為第二個值。- 結果存放在
static int result[2],函式回傳的指標指向這個陣列,因此函式返回後資料仍有效。 *newLen = 2會改寫呼叫端傳入的整數。主程式把len同時當作來源陣列長度及newLen,因此第一次呼叫後,len會從 9 變成 2。
解題方法
先逐次追蹤呼叫中的 len,再依照每個分支的比較條件更新 first、second。
第一次呼叫:find2(data, len, true, &len)
呼叫時 len = 9,startInd = 2。前兩個元素為 35、12,因此初始化為 first = 35、second = 12。接著由索引 2 掃描至索引 8:
| 索引 | 值 | 更新後的 first、second |
|---|---|---|
| 2 | 23 | 35、23 |
| 3 | 11 | 35、23 |
| 4 | 24 | 35、24 |
| 5 | 36 | 36、35 |
| 6 | 59 | 59、36 |
| 7 | 48 | 59、48 |
| 8 | 47 | 59、48 |
迴圈結束時 startInd 仍是 2,因為 for 迴圈的索引變數是 i,不會改變 startInd。函式印出:
StartInd: 2, first: 59, second: 48
之後函式設定 *newLen = 2,也就是把主程式的 len 改成 2,並回傳 result。主程式接著印出:
Result 1: 59, Result 2: 48
第二次呼叫:find2(data, len, false, &len)
此時 data 指向第一次呼叫回傳的 result,內容為 {59, 48};而 len 已經是 2。因此第二次呼叫檢查的是這兩個結果,不是原始的九元素陣列。
因為 59 >= 48,初始化為 first = 59、second = 48。
第 四 題18 分
請說明如下 Python 程式,使用 PQ_recursive(3) 呼叫後,正確執行時的輸出結果為何?如若無法正確執行(即會出現執行時期的錯誤),請說明應如何修正才能正常執行及輸出結果為何。
def PQ_recursive(n, c1='Z', c2='Y', c3='X'): if n <= 0 or n > 9: return
PQ_recursive(n - 1, c1, c3, c2)
print(f"Move {n}: {c1} -> {c3}")
PQ_recursive(n - 1, c2, c1, c3)
登入後即可作答並保存紀錄。
核心觀念
本題考查 Python 函式的遞迴呼叫、預設參數,以及參數傳遞順序。程式意圖以遞迴方式列出移動步驟;每次呼叫都將三個位置參數 c1、c2、c3 傳入下一層。
解題方法
呼叫 PQ_recursive(3) 時,初始參數為 c1='Z'、c2='Y'、c3='X'。但遞迴呼叫會在尚未輸出任何文字時,先一路進入:
PQ_recursive(n - 1, c1, c3, c2)
各層的參數如下:
n | c1 | c2 | c3 |
|---|---|---|---|
| 3 | Z | Y | X |
| 2 | Z | X | Y |
| 1 | Z | Y | X |
| 0 | Z | X | Y |
當 n=0 時,符合 n <= 0,函式直接 return。之後程式開始回到上一層執行,但該層接著呼叫:
PQ_recursive(n - 1, c2, c1, c3)
在 n=1 這層,傳入的參數為 n=0, c1='Y', c2='Z', c3='X'。這組值也會觸發基底條件並返回。此時 n=1 層執行 print,再回到 n=2 層。
第 五 題18 分
請完成如下的 JavaScript function 觸動方式(第一條粗黑線)及內容(第二~第六條粗黑線),可以顯示如下網頁頁面,並在按下「Submit」按鈕後,觸動 JS function 根據使用者的輸入,顯示計算複利的本利和。
🖼️【此處有附圖,請對照原卷】
HTML 程式碼如下:
<body> <h2>複利計算程式</h2><form onsubmit="____">
<div>
<label for="principal">本金:</label>
<input type="number"
id="principal"
min="1000"
max="100000"
step="1000"
value="10000"
required>
</div>
<div>
<label for="year">年數:</label>
<input type="number"
id="year"
min="1"
max="20"
step="1"
value="1"
required>
</div>
<div>
<label for="rate">年利率(%):</label>
<input type="number"
id="rate"
min="0.01"
max="100"
step="0.01"
value="2.0"
required>
</div>
<div>
<label for="amount">本利和:</label>
<input type="text" id="amount" readonly>
</div>
<button type="submit">Submit</button>
</form>
<script>
function calculateCompoundInterest(event) {
event.preventDefault();
let principal = ____;
let year = ____;
let rate = ____;
let amount = ____;
____ = amount.toFixed(2);
}
</script>
</body>
其中需填入:
- 第一條粗黑線:
onsubmit="____" - 第二條粗黑線:
let principal = ____; - 第三條粗黑線:
let year = ____; - 第四條粗黑線:
let rate = ____; - 第五條粗黑線:
let amount = ____; - 第六條粗黑線:
____ = amount.toFixed(2);
登入後即可作答並保存紀錄。
核心觀念
本題考查:
- HTML 表單
onsubmit事件的觸發方式。 - 透過
document.getElementById(...).value取得輸入值。 - JavaScript 字串轉數值。
- 複利公式:
其中:
- :本金
- :年利率的小數值
- :年數
- :本利和
題目中的利率輸入單位是百分比,例如 2.0 代表 ,因此計算時須除以 。
解題方法
第一條粗黑線位於 <form onsubmit="...">,按下 Submit 後會觸發表單提交事件,因此填入:
calculateCompoundInterest(event)
函式內先使用 event.preventDefault,避免表單送出後重新載入頁面。
本金、年數、年利率均由輸入欄位取得。由於 .value 取得的是字串,須使用 parseFloat 轉成數值:
let principal = parseFloat(document.getElementById("principal").value);
let year = parseFloat(document.getElementById("year").value);
let rate = parseFloat(document.getElementById("rate").value) / 100;
複利計算使用:
let amount = principal * Math.pow(1 + rate, year);
最後將結果四捨五入至小數點後兩位,並設定到 id="amount" 的文字輸入欄位:
document.getElementById("amount").value = amount.toFixed(2);
完整程式碼
<form onsubmit="calculateCompoundInterest(event)">