111 經濟部聯招(台電、中油、台水、台糖)新進職員 統計資訊 國營事業聯招 (資料庫及資料探勘、程式設計)B 考古題詳解

111 年・經濟部聯招(台電、中油、台水、台糖)・新進職員・統計資訊
試題代碼 111年國營事業聯招 統計資訊(資料庫及資料探勘、程式設計)B

第 一 題16 分

某學生之成績資料如下表,請回答下列問題。(2 題,每題 8 分,共 16 分)

學期110_01學號410552223姓名陳 OO
性別F生日2001/10/5連絡住址OO 市 OO 區 OO 路 ** 號
編號P110233緊急聯絡人陳 OO關係父親
電話29123334<br>0911222333緊急聯絡人住址OO 市 OO 區 OO 路 ** 號
科目代號科目名稱學分選別成績教師編號教師姓名
C10032國文3必85T01245王 OO
C20015英文3必86T04578李 OO
C60001網頁設計2選78T06543趙 OO
C60012程式語言4必65T06543趙 OO
C61001計算機概論3必88T06578陳 OO

(一) 請將該學生成績資料進行正規化後,列出分析的資料表,並以下列方式書寫(主鍵需加註底線標示)。 資料表名稱(主鍵‾, 欄位 1, 欄位 2, … )\text{資料表名稱}(\underline{\text{主鍵}},\ \text{欄位 1},\ \text{欄位 2},\ \dots) 註:主鍵不一定是單一值,也可以是複合值。

(二) 承小題(一),請繪出對應之 E-R 圖。

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查資料庫正規化、功能相依性、主鍵與外鍵,以及由關聯綱目繪製 E-R 圖。

原始資料混合了:

  • 學生基本資料
  • 多值電話
  • 緊急聯絡人資料
  • 學期資料
  • 科目資料
  • 教師資料
  • 學生成績資料

若全部放在同一張表,會產生資料重複、插入異常、刪除異常及更新異常,因此需拆解成多張具明確功能的資料表。

正規化重點如下:

  1. 第一正規化(1NF):每個欄位只能存放不可再分割的單一值,因此學生的兩支電話不可放在同一欄。
  2. 第二正規化(2NF):非主鍵欄位必須完全相依於整個主鍵,不可只相依於複合主鍵的一部分。
  3. 第三正規化(3NF):非主鍵欄位不可透過其他非主鍵欄位間接相依。

本題以「同一學期中,每一科目由一位教師授課」為資料規則,並將「編號 P110233」視為該學生該學期的成績單編號。


解題方法

由原始資料可判斷下列功能相依性:

  • 學號 →\rightarrow 姓名、性別、生日、聯絡住址
  • 教師編號 →\rightarrow 教師姓名
  • 科目代號 →\rightarrow 科目名稱、學分、選別、教師編號
  • 編號 →\rightarrow 學號、學期
  • (編號、科目代號)→\rightarrow 成績

電話欄位有兩個值:

29123334,091122233329123334,\quad 0911222333

因此電話必須另拆成多筆資料,形成獨立的學生電話表。

成績則是「某一份成績單中的某一科成績」,因此必須以:

(編號,科目代號)(\text{編號},\text{科目代號})

作為複合主鍵。


(一)正規化後的資料表

1. 學生資料表

學生(學號‾, 姓名, 性別, 生日, 聯絡住址)\text{學生}(\underline{\text{學號}},\ \text{姓名},\ \text{性別},\ \text{生日},\ \text{聯絡住址})

資料如下:

學號姓名性別生日聯絡住址
410552223陳 OOF2001/10/5OO 市 OO 區 OO 路 ** 號

主鍵為學號,因為每位學生具有唯一學號。


2. 學生電話表

學生電話(學號, 電話‾)\text{學生電話}(\underline{\text{學號},\ \text{電話}})

資料如下:

學號電話
41055222329123334
4105522230911222333

此表採用複合主鍵 (學號,電話)(\text{學號},\text{電話}),避免同一位學生的不同電話互相衝突。

其中學號為外鍵,參照「學生」表的學號。


3. 緊急聯絡人表

緊急聯絡人(學號‾, 緊急聯絡人姓名, 關係, 緊急聯絡人住址)\text{緊急聯絡人}(\underline{\text{學號}},\ \text{緊急聯絡人姓名},\ \text{關係},\ \text{緊急聯絡人住址})

資料如下:

學號緊急聯絡人姓名關係緊急聯絡人住址
410552223陳 OO父親OO 市 OO 區 OO 路 ** 號

本題資料中每位學生只有一位緊急聯絡人,因此以學號作為主鍵,形成學生與緊急聯絡人的一對一關係。

若實際系統允許同一學生登錄多位緊急聯絡人,則此表可改用「緊急聯絡人編號」作為主鍵;本題依題目資料採用學號主鍵。


4. 學期成績單表

學期成績單(編號‾, 學號, 學期)\text{學期成績單}(\underline{\text{編號}},\ \text{學號},\ \text{學期})

資料如下:

編號學號學期
P110233410552223110_01

其中:

  • 編號為主鍵。
  • 學號為外鍵,參照「學生」表。
  • 學號與學期也可設定為候選鍵,表示同一學生在同一學期只有一份成績單。

5. 教師表

教師(教師編號‾, 教師姓名)\text{教師}(\underline{\text{教師編號}},\ \text{教師姓名})

資料如下:

教師編號教師姓名
T01245王 OO
T04578李 OO
T06543趙 OO
T06578陳 OO

教師姓名只依賴教師編號,因此獨立建立教師表,可避免教師姓名在多筆科目資料中重複。


6. 科目表

科目(科目代號‾, 科目名稱, 學分, 選別, 教師編號)\text{科目}(\underline{\text{科目代號}},\ \text{科目名稱},\ \text{學分},\ \text{選別},\ \text{教師編號})

資料如下:

科目代號科目名稱學分選別教師編號
C10032國文3必T01245
C20015英文3必T04578
C60001網頁設計2選T06543
C60012程式語言4必T06543
C61001計算機概論3必T06578

其中教師編號為外鍵,參照「教師」表。

在本題資料規則下,一個科目對應一位授課教師,因此:

科目代號→教師編號\text{科目代號}\rightarrow\text{教師編號}

7. 修課成績表

修課成績(編號, 科目代號‾, 成績)\text{修課成績}(\underline{\text{編號},\ \text{科目代號}},\ \text{成績})

資料如下:

編號科目代號成績
P110233C1003285
P110233C2001586
P110233C6000178
P110233C6001265
P110233C6100188

主鍵為複合主鍵:

(編號,科目代號)(\text{編號},\text{科目代號})

理由是:

🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

第 二 題18 分

某關聯資料庫(Relational Database)包含下列兩個資料表(Tables),有底線者為主鍵:

教師(Teacher)資料表

教師代碼<br>(Tid‾\underline{\text{Tid}})教師姓名<br>(TName)系所代號<br>(DeptNo)性別<br>(Sex)到校年<br>(ArrivalYear)身分別<br>(Separate)薪資<br>(Salary)

註:身分別(Separate)欄位的值為字元 Y 時表示專任,N 時表示兼任。

系所(Department)資料表

系所代號<br>(DeptNo‾\underline{\text{DeptNo}})系所中文名稱<br>(DeptName)所在建築<br>(Building)

針對下列問題,請分別寫出 SQL 指令以進行查詢:(3 題,每題 6 分,共 18 分)

(一) 對所有專任教師,依性別分別列出平均薪資,平均薪資欄位另取名為 AvgSalary。 (二) 列出「企管系」教師最高薪資與最低薪資的差距,差距欄位另取名為 DiffSalary。 (三) 列出到校 10 年(含)以上的教師。

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查 SQL 的下列觀念:

  • WHERE:先篩選符合條件的資料列。
  • GROUP BY:依指定欄位分組。
  • AVG:計算平均值。
  • MAX、MIN:分別取得最大值與最小值。
  • 欄位別名:使用 AS 重新命名輸出欄位。
  • JOIN:連結教師表與系所表,以系所中文名稱查詢教師資料。

題目指定以民國 111 年為基準,因此「到校 10 年(含)以上」表示:

111−ArrivalYear≥10111-\text{ArrivalYear}\geq 10

整理得:

ArrivalYear≤101\text{ArrivalYear}\leq 101

以下解答均以命題當年(民國 111 年)法規為準;本題不涉及法條。

解題方法

(一)對所有專任教師,依性別列出平均薪資

專任教師的條件是 Separate = 'Y'。篩選後,再依 Sex 分組,並使用 AVG(Salary) 計算各性別的平均薪資。

SELECT Sex, AVG(Salary) AS AvgSalary
FROM Teacher
WHERE Separate = 'Y'
GROUP BY Sex;

說明:

  1. WHERE Separate = 'Y' 篩選專任教師。
  2. GROUP BY Sex 將資料依性別分組。
  3. AVG(Salary) 計算每一組的平均薪資。
  4. AS AvgSalary 將平均薪資欄位命名為 AvgSalary。

(二)列出「企管系」教師最高薪資與最低薪資的差距

「企管系」是系所中文名稱,存放於 Department.DeptName,因此必須以 DeptNo 作為連接條件連結兩個資料表。

薪資差距的計算公式為:

DiffSalary=max⁡(Salary)−min⁡(Salary)\text{DiffSalary}=\max(\text{Salary})-\min(\text{Salary})

SQL 指令如下:

SELECT MAX(T.Salary) - MIN(T.Salary) AS DiffSalary
FROM Teacher AS T
JOIN Department AS D
 ON T.DeptNo = D.DeptNo
WHERE D.DeptName = '企管系';

說明:

  1. JOIN Department AS D 將教師表與系所表連結。
  2. ON T.DeptNo = D.DeptNo 是兩表的連接條件。
  3. WHERE D.DeptName = '企管系' 篩選企管系教師。
🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

第 三 題16 分

假設某家電腦公司銷售筆記型電腦,針對各種客戶分類,建立了銷售調查統計表,經過幾個月銷售統計,收集到下表的調查資料,請回答下列問題:(3 題,共 16 分)

人數年齡收入學生信用購買筆電
60青年高否良沒買
64青年高否優沒買
100中年高否良買
64老年中否良買
58老年低是良買
64老年低是優沒買
50中年低是優買
130青年中否良沒買
64青年低是良買
130老年中是良買
32青年中是優買
64中年中否優買
30中年高是良買
100老年中否優沒買

(一) 若你是銷售人員,請問哪一項客戶分類資料,能直接說明最有效的銷售?(3 分) (二) 請問年齡層為中年的客群,購買筆記型電腦的機率為何(2 分)?並說明原因(5 分)。 (三) 請以年齡特徵作為根節點,針對客戶分類,建立一個最有效的銷售之決策樹。(6 分)

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查分類資料的加權統計、條件機率,以及決策樹分類。

表中的「人數」是各類客戶的權數,因此計算購買率時,必須加總人數,不能只計算資料列數。

購買機率公式為:

P(購買∣分類條件)=符合條件且購買的人數符合條件的總人數P(\text{購買}\mid \text{分類條件}) = \frac{\text{符合條件且購買的人數}} {\text{符合條件的總人數}}

決策樹則是依據各特徵對「買/沒買」的區分能力進行分割。若某分支分割後全部屬於同一類別,即達到純分類,便可直接形成葉節點。


(一)最有效的客戶分類

解題方法

比較各項分類中「購買筆電」的比例。

分類條件購買人數總人數購買率
年齡:青年969635035027.43%27.43\%
年齡:中年244244244244100%100\%
年齡:老年25225241641660.58%60.58\%
收入:高13013025425451.18%51.18\%
收入:中29029052052055.77%55.77\%
收入:低17217223623672.88%72.88\%
學生:否16416451851831.66%31.66\%
學生:是36436442842885.05%85.05\%
信用:良44644663663670.13%70.13\%
信用:優14614637437439.04%39.04\%

其中,若以「單一分類特徵」作為銷售對象判斷,「學生=是」的購買率為 85.05%85.05\%,高於其他分類條件,因此最能直接說明銷售成效。

解題技巧

判斷銷售對象時,重點是比較條件購買率,而不是比較購買總人數。購買總人數最多的分類,不一定代表購買意願最高。


(二)中年客群購買機率

計算

中年客群共有:

100+50+64+30=244 人100+50+64+30=244\text{ 人}

其中購買筆電的人數為:

100+50+64+30=244 人100+50+64+30=244\text{ 人}

因此:

P(購買∣中年)=244244=1=100%P(\text{購買}\mid \text{中年}) = \frac{244}{244} =1 =100\%

原因說明

表中所有年齡為「中年」的客戶資料,其「購買筆電」欄均為「買」,沒有任何中年客戶標記為「沒買」。

🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

第 四 題15 分

有一費氏(Fibonacci)數學函式如下:(3 題,每題 5 分,共 15 分) F(n)=F(n−1)+F(n−2), n>0F(n) = F(n-1) + F(n-2),\ n > 0 F(1)=1, F(0)=0F(1) = 1,\ F(0) = 0

(一) 請以遞迴(Recursive)方式寫出上列函式程式碼。 (二) 請以非遞迴(Non-Recursive)方式寫出上列函式程式碼。 (三) 為避免因為遞迴呼叫浪費函式重複計算的時間,試修改(一)中的程式碼,仍須使用遞迴的方式,使其計算時不須重複計算 F(n−1)F(n-1) 和 F(n−2)F(n-2) 函式。

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查費氏數列的遞迴定義、迴圈迭代,以及遞迴搭配記憶化(Memoization)的最佳化方法。

費氏數列定義如下:

F(n)=F(n−1)+F(n−2),n>0F(n)=F(n-1)+F(n-2),\quad n>0 F(0)=0,F(1)=1F(0)=0,\qquad F(1)=1

其中:

  • F(0)F(0)、F(1)F(1)是遞迴終止條件。
  • F(n)=F(n−1)+F(n−2)F(n)=F(n-1)+F(n-2)是遞迴關係式。
  • 未設定終止條件時,函式會無限遞迴。

解題方法

(一)以遞迴方式撰寫

依照題目定義,當 n=0n=0 或 n=1n=1 時直接回傳結果;當 n>1n>1 時,依遞迴關係計算。

int fibonacci_recursive(int n)
{
 if (n == 0)
 return 0;

 if (n == 1)
 return 1;

 return fibonacci_recursive(n - 1)
 + fibonacci_recursive(n - 2);
}

也可以合併兩個基本條件:

int fibonacci_recursive(int n)
{
 if (n <= 1)
 return n;

 return fibonacci_recursive(n - 1)
 + fibonacci_recursive(n - 2);
}

例如:

F(4)=F(3)+F(2)F(4)=F(3)+F(2) F(3)=F(2)+F(1)F(3)=F(2)+F(1) F(2)=F(1)+F(0)F(2)=F(1)+F(0)

因此:

F(4)=3F(4)=3

此方法直接呈現數學定義,但會重複計算相同的子問題,時間複雜度約為 O(2n)O(2^n),空間複雜度為遞迴深度 O(n)O(n)。


(二)以非遞迴方式撰寫

非遞迴方式使用兩個變數保存前兩項:

  • prev2:代表前前項
  • prev1:代表前一項
  • current:代表目前計算出的項目
int fibonacci_iterative(int n)
{
 if (n <= 1)
 return n;

 int prev2 = 0; // F(0)
 int prev1 = 1; // F(1)
 int current;

 for (int i = 2; i <= n; i++)
 {
 current = prev1 + prev2;
 prev2 = prev1;
 prev1 = current;
 }

 return prev1;
}

計算 F(6)F(6)時,變數變化如下:

ii目前項目prev2prev1
初始—F(0)=0F(0)=0F(1)=1F(1)=1
2F(2)=1F(2)=111
3F(3)=2F(3)=212
4F(4)=3F(4)=323
5F(5)=5F(5)=535
6F(6)=8F(6)=858

因此:

F(6)=8F(6)=8

此方法每一項只計算一次,時間複雜度為 O(n)O(n),額外空間複雜度為 O(1)O(1)。


🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

第 五 題15 分

A 公司 1 月人事資料檔案如下表,請撰寫下列程式片段。(2 題,共 15 分)

emp-id(員工代號)dep-id(部門代號)age(年齡)s_salary(特別費)
123455ABC250
987655ABC305000
A12345AAB3010000
123455AAB30500
12345AXX255000
234561AXX3515000

(一) A 公司員工代號共 6 碼數字,第 6 碼是前 5 碼總和的個位數,請撰寫一函式 check_dit(),以檢查員工代號之正確性。(7 分) (二) 請撰寫一函式 main(),逐筆讀取人事資料檔案,並呼叫(一)函式,篩選正確員工代號資料,最後列出特別費合計超過 100,000 元之部門代號及合計金額。(8 分)

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查兩個重點:

  1. 字串格式檢查
  • 員工代號必須為長度 6 的數字字串。
  • 前 5 碼轉換成數字後相加。
  • 第 6 碼必須等於前 5 碼總和的個位數。
  1. 檔案逐筆讀取與部門彙總
  • 逐筆讀取人事資料。
  • 只有員工代號正確的資料才納入統計。
  • 依部門代號累計 s_salary。
  • 最後列出合計超過 100,000100{,}000 元的部門。

驗證公式為:

第 6 碼=(∑i=15第 i 碼) mod 10\text{第 6 碼} = \left(\sum_{i=1}^{5}\text{第 }i\text{ 碼}\right)\bmod 10

(一)check_dit 函式

解題方法

以字串方式處理員工代號,原因如下:

  • 可直接判斷長度是否為 6。
  • 可逐一檢查每一個字元是否為數字。
  • 可避免員工代號開頭為 0 時,轉成整數後遺失前導零。

函式回傳值定義如下:

  • 回傳 1:員工代號正確。
  • 回傳 0:員工代號錯誤。

C 語言程式碼

#include <stdio.h>
#include <string.h>

int check_dit(const char emp_id[])
{
 int i;
 int sum = 0;
 int last_digit;

 /* 員工代號必須剛好為 6 碼 */
 if (strlen(emp_id) != 6)
 return 0;

 /* 前 5 碼必須都是數字 */
 for (i = 0; i < 5; i++) {
 if (emp_id[i] < '0' || emp_id[i] > '9')
 return 0;

 sum += emp_id[i] - '0';
 }

 /* 第 6 碼也必須為數字 */
 if (emp_id[5] < '0' || emp_id[5] > '9')
 return 0;

 last_digit = emp_id[5] - '0';

 /* 檢查第 6 碼是否為前 5 碼總和的個位數 */
 if (last_digit != sum % 10)
 return 0;

 return 1;
}

資料驗證

員工代號前 5 碼總和正確個位數實際第 6 碼判定
1234551+2+3+4+5=151+2+3+4+5=1555正確
9876559+8+7+6+5=359+8+7+6+5=3555正確
A12345含有英文字母——錯誤
1234551+2+3+4+5=151+2+3+4+5=1555正確
12345長度為 5——錯誤
2345612+3+4+5+6=202+3+4+5+6=2001錯誤

(二)main 函式

解題方法

使用陣列儲存各部門的累計特別費:

dep_sum[i]

代表:

dep_id_list[i]

部門的特別費合計。

每讀取一筆資料時:

  1. 呼叫 check_dit。
  2. 員工代號錯誤時跳過該筆資料。
  3. 員工代號正確時,尋找部門代號。
  4. 找到既有部門便累加金額。
  5. 找不到部門便新增一筆部門資料。
  6. 檔案讀取完畢後,列出合計超過 100,000100{,}000 元的部門。

C 語言完整程式碼

假設檔案每行格式如下:

emp-id dep-id age s_salary

程式碼如下:

🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

第 六 題20 分

快速排序法(Quick Sort)是排序演算法中的一種,處理過程是先選擇一個資料為基準點,所有比基準點小的元素放在左邊,比基準點大的元素放在右邊,之後再反覆對基準點左右兩邊的數列執行相同的處理,直到數列只剩下一個數值或沒有數值時即完成排序。請撰寫一函式 QuickSort(),將傳入的一維陣列利用快速排序法,由小至大排序陣列元素。(20 分)

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

快速排序法(Quick Sort)採用「分割與征服」(Divide and Conquer)策略,核心步驟如下:

  1. 選擇一個元素作為基準值(pivot)。
  2. 將陣列重新排列,使得:
  • 小於等於 pivot 的元素位於左側;
  • 大於 pivot 的元素位於右側。
  1. 對 pivot 左右兩側的子陣列遞迴執行相同程序。
  2. 子陣列長度為 00 或 11 時,該子陣列必定已排序完成。

本題要求由小至大排序,因此分割時需將較小元素放在左方、較大元素放在右方。


解題方法

採用 Lomuto 分割法,選擇目前處理區間的最後一個元素作為 pivot。

假設目前處理範圍為:

[left,right][left, right]

令:

pivot=A[right]pivot = A[right]

並以變數 ii 表示「小於等於 pivot 的元素」區域最後位置。由 leftleft 到 right−1right-1 逐一掃描:

  • 若 A[j]≤pivotA[j] \le pivot,表示該元素應放在左側,先將 ii 加一,再交換 A[i]A[i] 與 A[j]A[j]。
  • 掃描完成後,將 pivot 與 A[i+1]A[i+1] 交換。
  • 此時 pivot 已位於最終正確位置 i+1i+1。

分割完成後,再分別處理:

[left,i][left, i]

以及:

[i+2,right][i+2, right]

因為 pivot 位於 i+1i+1,不必再參與遞迴。


Python 參考實作

def QuickSort(arr):
 def partition(left, right):
 pivot = arr[right]
 i = left - 1

 for j in range(left, right):
 if arr[j] <= pivot:
 i += 1
 arr[i], arr[j] = arr[j], arr[i]

 arr[i + 1], arr[right] = arr[right], arr[i + 1]
 return i + 1

 def quick_sort(left, right):
 if left >= right:
 return

 pivot_index = partition(left, right)

 quick_sort(left, pivot_index - 1)
 quick_sort(pivot_index + 1, right)

 quick_sort(0, len(arr) - 1)
 return arr

範例:

data = [35, 12, 8, 26, 49, 17]
QuickSort(data)
print(data)

輸出:

[8, 12, 17, 26, 35, 49]

此寫法直接在原陣列上交換元素,屬於原地排序,最後回傳排序後的陣列。


分割程序說明

以陣列:

[35,12,8,26,49,17][35, 12, 8, 26, 49, 17]

為例,第一次選擇最後元素 1717 為 pivot。

掃描後,所有小於等於 1717 的元素會被移至左側:

[12,8,17,26,49,35][12, 8, 17, 26, 49, 35]

此時 1717 已位於正確位置,接著分別對:

🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

其他考古題

統計資訊《國營事業聯招 (資料庫及資料探勘、程式設計)B》其他年度

111 年經濟部聯招(台電、中油、台水、台糖)新進職員・其他類科的《國營事業聯招 (資料庫及資料探勘、程式設計)B》