25-1
[회원]과 [적립] 테이블이 아래와 같을 때, 주어진 SQL 문이 반환하는 결과를 적으시오.
[회원]
| 번호 | 이름 |
|---|---|
| 201 | 한지우 |
| 202 | 서민재 |
| 205 | 오하늘 |
| 207 | 백도윤 |
| 209 | 문가은 |
[적립]
| 번호 | 포인트 |
|---|---|
| 201 | 450 |
| 202 | 800 |
| 205 | 300 |
| 207 | 1200 |
| 209 | 790 |
SELECT 이름, 포인트
FROM 회원, 적립
WHERE 회원.번호 = 적립.번호 AND 포인트 >= 800;| 이름 | 포인트 |
|---|---|
| 서민재 | 800 |
| 백도윤 | 1200 |
[해설]
두 테이블을 번호가 같은 행끼리 연결(동등 조인)한 뒤 포인트가 800 이상인 행만 남긴다.
- 201 한지우 450, 205 오하늘 300: 800 미만이라 제외
- 209 문가은 790: 800에 10이 모자라 제외
- 202 서민재 800: 조건이 이상(>=)이므로 포함
- 207 백도윤 1200: 포함
결과는 서민재 800, 백도윤 1200 두 행이다.
25-1
다음 설명에 해당하는 프로토콜을 영문 약어로 각각 적으시오.
- ( ① ): 통신할 상대의 IP 주소는 알고 있지만 그 장비의 물리 주소(MAC 주소)를 모를 때, 브로드캐스트 질의로 MAC 주소를 알아낸다.
- ( ② ): 저장 장치가 없어 자신의 IP 주소를 보관하지 못하는 호스트가, 자기 MAC 주소를 내보여 서버로부터 IP 주소를 얻어 온다.
① ARP
② RARP
[해설]
IP 주소와 MAC 주소를 서로 바꿔 찾아 주는 주소 해석 프로토콜이다.
- ARP(Address Resolution Protocol)는 IP 주소를 알 때 브로드캐스트로 물어서 상대의 MAC 주소를 얻는다.
- RARP(Reverse ARP)는 디스크 없는 호스트가 자기 MAC 주소를 보내 서버에서 자신의 IP 주소를 받는다.
외우는 요령: IP→MAC은 ARP, 반대 방향 MAC→IP는 Reverse가 붙은 RARP다. RARP는 오늘날 BOOTP·DHCP로 대체되었다.
25-1
아래 Java 프로그램의 실행 시 출력값을 적으시오.
class Base {
static int acc = 1;
int w = 3;
Base() {
acc += w * 2;
step();
}
void step() {
acc -= 1;
}
}
class Derived extends Base {
int w = 5;
Derived() {
w -= 1;
acc += --w;
step();
}
@Override
void step() {
acc = acc * 2 + w;
}
}
public class Main {
public static void main(String[] args) {
new Derived();
System.out.println(Base.acc);
}
}37
[해설]
new Derived()는 먼저 부모 생성자를 실행하고, 그다음 자식 필드 초기화와 자식 생성자 본문을 실행한다.
- Base(): acc = 1 + 3×2 = 7
- Base()의 step()은 오버라이딩된 Derived.step()이 호출된다. 이때 Derived의 w는 아직 초기화 전이라 0 → acc = 7×2 + 0 = 14
- Derived 필드 초기화: w = 5, 본문 w -= 1 → 4
- acc += --w: w가 3이 된 뒤 더해져 acc = 17
- step(): acc = 17×2 + 3 = 37
static 변수 acc는 두 클래스가 공유하므로 최종 출력은 37이다. 필드 w는 오버라이딩되지 않고 각 클래스에 따로 존재한다.
25-1
화이트박스 테스트를 위해 아래 C 함수의 제어 흐름을 순서도로 옮겼다. 순서도의 노드와 연결 관계는 표와 같다.
int scan(int v[], int n, int lim) {
int k = 0;
while (k < n && v[k] != lim) {
if (v[k] > lim)
v[k] = lim;
k++;
}
return k;
}| 노드 | 형태 | 다음 노드 |
|---|---|---|
| ① | 처리 | ② |
| ② | 판단 | 참 → ③, 거짓 → ⑥ |
| ③ | 판단 | 참 → ④, 거짓 → ⑤ |
| ④ | 처리 | ⑤ |
| ⑤ | 처리 | ② (반복) |
| ⑥ | 종료 | — |
(1) 노드 ①~⑥에 들어갈 코드(문장 또는 조건식)를 각각 적으시오.
(2) 모든 문장을 한 번 이상 실행하는 문장(구문) 커버리지 100% 경로를 완성하시오.
① → ② → ( ) → ( ) → ( ) → ( ) → ( )
(1) ① int k = 0
② k < n && v[k] != lim
③ v[k] > lim
④ v[k] = lim
⑤ k++
⑥ return k
(2) ③ → ④ → ⑤ → ② → ⑥
[해설]
초기화가 처리 노드 ①, while 조건이 첫 판단 노드 ②, if 조건이 둘째 판단 노드 ③이다. ③이 참일 때만 ④를 거치고, 참·거짓 모두 ⑤(k++)로 모여 ②로 되돌아간다.
문장 커버리지는 모든 문장을 최소 한 번 실행하면 되므로, if가 참인 반복을 한 번 거친 뒤 루프를 빠져나오면 된다.
- ① → ② 참 → ③ 참 → ④ → ⑤ → ② 거짓 → ⑥
- 예: v = {9}, n = 1, lim = 5이면 9 > 5라 ④가 실행되고, k=1이 되어 루프를 끝낸다.
정답 경로는 ①→②→③→④→⑤→②→⑥이다. ③의 거짓 분기까지 요구하는 것은 문장이 아니라 분기(결정) 커버리지다.
25-1
아래 Python 프로그램을 실행했을 때 출력값을 적으시오.
class Cell:
def __init__(self, key):
self.key = key
self.kids = []
def build(vals):
cells = [Cell(x) for x in vals]
for idx in range(1, len(cells)):
cells[(idx - 1) // 2].kids.append(cells[idx])
return cells[0]
def walk(node, depth=0):
own = node.key if depth % 2 == 0 else -node.key
return own + sum(walk(k, depth + 1) for k in node.kids)
root = build([4, 7, 1, 6, 2, 9, 3, 5])
print(walk(root))11
[해설]
build는 리스트 인덱스 idx의 부모를 (idx−1)//2로 정해 완전이진트리를 만든다.
- 깊이 0: 4
- 깊이 1: 7, 1
- 깊이 2: 6, 2, 9, 3
- 깊이 3: 5 (인덱스 7의 부모는 인덱스 3의 노드 6)
walk는 깊이가 짝수면 값을 더하고 홀수면 뺀 뒤 자식 결과를 모두 합친다.
4 − (7+1) + (6+2+9+3) − 5 = 4 − 8 + 20 − 5 = 11이다.
25-1
다음 설명이 공통으로 가리키는 오류 검출 방식을 영문 약어(3글자)로 적으시오.
- 송신 측은 데이터를 미리 약속한 생성 다항식으로 나누어 얻은 나머지를 덧붙여 보낸다.
- 수신 측은 받은 비트열 전체를 같은 다항식으로 다시 나누어 나머지가 0인지로 손상 여부를 판단한다.
- 여러 비트가 연속해서 깨지는 집단(버스트) 오류에 강해 네트워크 프레임, 저장 장치 등에 널리 쓰인다.
CRC
[해설]
생성 다항식으로 나눈 나머지를 검사값으로 덧붙이는 방식은 CRC(Cyclic Redundancy Check, 순환 중복 검사)이다.
수신 측은 같은 다항식으로 나눠 나머지가 0이면 정상, 아니면 오류로 판단한다. 연속된 비트가 깨지는 버스트 오류 검출에 강해 네트워크 프레임·저장 장치에 쓰인다.
혼동 주의: CRC는 오류를 검출만 하며, 정정까지 하는 것은 해밍 코드 같은 FEC 방식이다.
25-1
아래 C 프로그램의 출력 내용을 적으시오.
#include <stdio.h>
#include <stdlib.h>
typedef struct Item {
int num;
struct Item *link;
} Item;
Item *push_back(Item *head, int num) {
Item *node = (Item *)malloc(sizeof(Item));
node->num = num;
node->link = NULL;
if (head == NULL)
return node;
Item *cur = head;
while (cur->link != NULL)
cur = cur->link;
cur->link = node;
return head;
}
Item *bring_front(Item *head, int target) {
if (head == NULL || head->num == target)
return head;
Item *before = head;
while (before->link != NULL && before->link->num != target)
before = before->link;
if (before->link == NULL)
return head;
Item *hit = before->link;
before->link = hit->link;
hit->link = head;
return hit;
}
int main(void) {
Item *head = NULL, *cur, *tmp;
for (int v = 7; v <= 35; v += 7)
head = push_back(head, v);
head = bring_front(head, 28);
head = bring_front(head, 14);
for (cur = head; cur != NULL; cur = cur->link)
printf(cur == head ? "%d" : " %d", cur->num);
while (head != NULL) {
tmp = head;
head = head->link;
free(tmp);
}
return 0;
}14 28 7 21 35
[해설]
push_back은 새 노드를 리스트 끝에 붙이므로 처음 리스트는 7 → 14 → 21 → 28 → 35다.
bring_front는 target 값을 가진 노드를 찾아 앞 노드와의 연결을 끊고, 그 노드를 맨 앞(head)으로 옮긴다.
- bring_front(28): 28 → 7 → 14 → 21 → 35
- bring_front(14): 14 → 28 → 7 → 21 → 35
첫 노드는 "%d", 나머지는 " %d"로 찍어 공백으로 구분하므로 14 28 7 21 35가 출력된다.
25-1
빈칸 ( ㉮ )에 들어갈 공격 기법의 명칭을 적으시오.
- 1990년대 해커 케빈 미트닉이 활용한 것으로 알려진 수법으로, TCP 연결을 관리하는 방식의 허점을 파고든다.
- TCP 연결 설정(3-Way Handshake)이 끝나 정상적으로 맺어진 연결에, 공격자가 순서 번호(Sequence Number) 등을 맞춰 끼어들어 인증 절차 없이 그 연결을 빼앗는 공격을 TCP ( ㉮ )(이)라 한다.
세션 하이재킹(Session Hijacking)
[해설]
3-Way Handshake로 이미 맺어진 정상 연결을 가로채는 공격은 세션 하이재킹(Session Hijacking)이다.
공격자는 순서 번호(Sequence Number)를 추측하거나 스니핑해 위조 패킷을 끼워 넣고, 인증 없이 그 연결을 차지한다. 이때 양쪽의 ACK 번호가 어긋나 ACK가 폭주하는 ACK Storm이 탐지 단서가 된다.
혼동 주의: 연결을 맺을 때 신뢰받는 IP로 위장하는 것은 IP 스푸핑이고, 이미 맺어진 연결을 빼앗는 것이 세션 하이재킹이다.
25-1
아래 Java 프로그램을 실행하면 출력되는 값을 적으시오.
public class Main {
static int calc(int n) {
if (n <= 2) return 1;
return calc(n - 1) + calc(n - 3);
}
static int calc(String s) {
int n = Integer.parseInt(s);
if (n <= 2) return n;
return calc(n - 2) * 2;
}
public static void main(String[] args) {
System.out.println(calc("7"));
}
}8
[해설]
calc("7")은 인자가 문자열이라 String 버전이 호출되고, 그 안의 calc(n − 2)는 정수 인자라 int 버전으로 넘어간다(오버로딩).
String 버전은 calc(5) × 2를 반환하고, int 버전은 n ≤ 2이면 1, 아니면 calc(n−1) + calc(n−3)을 반환한다.
calc(3) = calc(2) + calc(0) = 1 + 1 = 2
calc(4) = calc(3) + calc(1) = 2 + 1 = 3
calc(5) = calc(4) + calc(2) = 3 + 1 = 4
4 × 2 = 8
혼동 주의: n ≤ 2일 때 n을 그대로 돌려주는 것은 String 버전뿐이다. 재귀 호출은 전부 int 버전이라 1을 돌려준다.
25-1
어떤 PC에 IP 주소 192.168.35.10과 서브넷 마스크 255.255.252.0이 설정되어 있다. 이 PC가 자기 네트워크 전체에 브로드캐스트 패킷을 보냈을 때 이를 받게 되는 호스트 주소를 아래 표에서 모두 골라 기호로 적으시오.
| 기호 | IP 주소 |
|---|---|
| ㄱ | 192.168.32.19 |
| ㄴ | 192.168.33.138 |
| ㄷ | 192.168.34.1 |
| ㄹ | 192.168.35.50 |
| ㅁ | 192.168.35.200 |
ㄱ, ㄴ, ㄷ, ㄹ, ㅁ(모두)
[해설]
마스크 255.255.252.0은 /22이므로 셋째 옥텟의 하위 2비트까지 호스트 부분이다.
- 35 = 0010 0011, 252 = 1111 1100 → AND = 0010 0000 = 32
- 네트워크 주소 192.168.32.0, 브로드캐스트 주소 192.168.35.255
- 호스트 범위: 192.168.32.1 ~ 192.168.35.254
보기의 다섯 주소는 셋째 옥텟이 32~35 사이이고 네트워크·브로드캐스트 주소도 아니다. 따라서 다섯 개 모두 같은 네트워크에 속해 브로드캐스트를 받는다.
25-1
아래 C 프로그램을 실행했을 때 화면에 찍히는 값을 적으시오.
#include <stdio.h>
#include <stdlib.h>
void fill(int **g, const int *src, int r, int c) {
for (int k = 0; k < r * c; k++)
g[k / c][(k + 1) % c] = src[k];
}
int main(void) {
int r = 2, c = 4, acc = 0;
int src[] = {6, 1, 9, 3, 7, 2, 8, 4};
int **g = (int **)malloc(sizeof(int *) * r);
for (int i = 0; i < r; i++)
g[i] = (int *)malloc(sizeof(int) * c);
fill(g, src, r, c);
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
acc += ((i + j) % 2 == 0) ? g[i][j] : -g[i][j];
for (int i = 0; i < r; i++)
free(g[i]);
free(g);
printf("%d", acc);
return 0;
}-2
[해설]
fill은 k번째 원소를 행 k/c, 열 (k+1)%c에 넣으므로 각 행 안에서 열이 한 칸씩 오른쪽으로 밀려 들어간다.
- 0행: src[0..3] = 6, 1, 9, 3 → 열 1, 2, 3, 0 → [3, 6, 1, 9]
- 1행: src[4..7] = 7, 2, 8, 4 → 열 1, 2, 3, 0 → [4, 7, 2, 8]
합산은 (i+j)가 짝수면 더하고 홀수면 뺀다(체크무늬 부호).
- 0행: +3 −6 +1 −9 = −11
- 1행: −4 +7 −2 +8 = 9
합계는 −11 + 9 = -2다.
25-1
다음 특징을 모두 가진 악성 소프트웨어를 [보기]에서 하나 골라 적으시오.
- "바이러스 수십 개가 발견되었습니다", "시스템이 곧 손상됩니다"와 같은 거짓 경고 창을 띄운다.
- 겁을 먹은 사용자가 가짜 백신이나 유료 최적화 프로그램을 사거나 설치하도록 유도한다.
- 이름은 '겁주다'라는 뜻의 영어 단어에서 따왔으며, 기술적 침투보다 심리적 압박(사회공학)에 기댄다.
[보기] 그레이웨어, 랜섬웨어, 루트킷, 스케어웨어, 스파이웨어, 애드웨어, 웜
스케어웨어(Scareware)
[해설]
공포심을 자극해 가짜 보안 제품 구매를 유도하는 것은 스케어웨어(Scareware)이다.
- 랜섬웨어: 파일을 실제로 암호화하고 복구 대가를 요구한다.
- 스파이웨어: 사용자 몰래 정보를 수집해 외부로 보낸다.
- 애드웨어: 광고를 강제로 노출해 수익을 얻는다.
- 루트킷: 침입 흔적과 악성 프로세스를 운영체제 수준에서 숨긴다.
스케어웨어는 실제 감염이 없는데도 감염된 것처럼 꾸민다는 점에서 랜섬웨어와 구별된다.
25-1
아래 C 프로그램이 표준 출력으로 내보내는 내용을 적으시오.
#include <stdio.h>
char word[6] = {'G', 'C', 'K', 'M', 'P'};
int main(void) {
char key = 'H';
int pos = 0, hold, nxt;
printf("%d\n", word[4] - word[2]);
while (pos < 5 && word[pos] <= key)
pos++;
hold = word[pos];
word[pos] = key;
for (pos = pos + 1; pos < 6; pos++) {
nxt = word[pos];
word[pos] = hold;
hold = nxt;
}
for (pos = 0; pos < 6; pos++)
printf("%c", word[pos]);
return 0;
}5
GCHKMP
[해설]
문자끼리 빼면 아스키 코드의 차이가 정수로 나온다. word[4]는 'P'(80), word[2]는 'K'(75)라서 첫 줄은 5다.
while은 값이 key 'H'(72) 이하인 동안 pos를 늘린다. 'G'(71)와 'C'(67)를 지나 'K'에서 멈추므로 pos = 2다.
- word[2]의 'K'를 hold에 옮기고 그 자리에 'H'를 넣는다.
- for가 hold를 한 칸씩 뒤로 넘겨 K는 word[3], M은 word[4], P는 word[5]로 밀린다.
- 배열 크기가 6이라 마지막 'P'도 잘리지 않는다.
둘째 줄은 GCHKMP다. 앞부분이 정렬돼 있지 않아도(C가 G 뒤에 있음) 조건만 맞으면 건너뛴다는 점에 주의한다.
25-1
관계 데이터베이스의 무결성 제약조건에 관한 설명이다. 빈칸 ①~③에 알맞은 무결성의 이름을 적으시오.
- ( ① ) 무결성: 기본키를 이루는 속성에는 NULL이 들어갈 수 없고, 같은 기본키 값을 가진 튜플이 둘 이상 존재할 수 없다.
- ( ② ) 무결성: 외래키 값은 NULL이거나, 참조되는 릴레이션에 실제로 존재하는 기본키 값 중 하나여야 한다.
- ( ③ ) 무결성: 각 속성의 값은 그 속성에 정의된 자료형과 허용 범위를 벗어날 수 없다.
① 개체
② 참조
③ 도메인
[해설]
관계 데이터 모델의 무결성 제약조건은 지키는 대상에 따라 개체·참조·도메인으로 나뉜다.
- 개체 무결성은 기본키에 NULL과 중복을 막아 각 튜플을 식별할 수 있게 한다.
- 참조 무결성은 외래키가 NULL이거나 참조 릴레이션에 실제로 있는 기본키 값이어야 한다는 규칙이다.
- 도메인 무결성은 속성 값이 정의된 자료형과 범위(CHECK 제약 등) 안에 있어야 한다는 규칙이다.
외우는 요령: 기본키는 개체, 외래키는 참조, 속성 값은 도메인으로 짝지어 둔다.
25-1
아래 Java 프로그램을 실행하면 화면에 무엇이 찍히는지 적으시오.
public class Main {
public static void main(String[] args) {
int[] box = {8, 4, 0, 2};
int total = 0;
for (int k = 0; k < box.length; k++) {
try {
total += 16 / box[k];
System.out.print("P");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.print("Q");
} catch (ArithmeticException e) {
System.out.print("R");
} catch (Exception e) {
System.out.print("S");
} finally {
System.out.print(k);
}
}
System.out.println(" " + total);
}
}P0P1R2P3 14
[해설]
반복마다 try 블록이 끝난 뒤 finally가 반드시 실행되어 인덱스 k가 찍힌다.
- k=0: 16/8=2, total=2 → "P0"
- k=1: 16/4=4, total=6 → "P1"
- k=2: 16/0에서 ArithmeticException 발생 → 두 번째 catch의 "R", 이어서 finally의 "2"
- k=3: 16/2=8, total=14 → "P3"
예외가 난 k=2에서는 덧셈이 수행되지 않아 total은 2+4+8=14다. 마지막 줄까지 합치면 P0P1R2P3 14가 출력된다.
catch는 위에서부터 차례로 검사해 처음 맞는 하나만 실행하며, 예외가 나도 반복문은 멈추지 않고 다음 k로 넘어간다.
25-1
모듈 사이의 결합도에 관한 설명이다. 빈칸 ①~④에 해당하는 결합도의 이름을 적으시오.
- ( ① ): 한 모듈이 다른 모듈 내부의 지역 데이터나 코드 일부를 직접 참조하거나 수정한다.
- ( ② ): 두 모듈이 배열·레코드·객체 같은 자료구조를 통째로 넘겨받지만 그중 일부만 사용한다.
- ( ③ ): 매개변수로 넘기지 않고, 모듈 바깥에 선언된 전역 변수를 여러 모듈이 함께 읽고 고치며 서로 영향을 준다.
- ( ④ ): 호출할 때 매개변수로 꼭 필요한 단순 값(자료 요소)만 주고받으며, 결합도 가운데 가장 약하다.
① 내용 결합도(Content Coupling)
② 스탬프 결합도(Stamp Coupling)
③ 공통 결합도(Common Coupling)
④ 자료 결합도(Data Coupling)
[해설]
결합도는 모듈끼리 의존하는 정도이며, 약한 것부터 자료 → 스탬프 → 제어 → 외부 → 공통 → 내용 순서다.
- 내용 결합도는 다른 모듈의 내부 데이터나 코드를 직접 참조·수정하는 가장 강한 결합이다.
- 스탬프 결합도는 배열·레코드 같은 자료구조를 통째로 넘기고 그중 일부만 쓴다.
- 공통 결합도는 여러 모듈이 전역 변수를 함께 읽고 고쳐 서로 영향을 준다.
- 자료 결합도는 꼭 필요한 단순 값만 매개변수로 주고받는 가장 약한 결합이다.
결합도는 약할수록 좋은 설계다. 혼동 주의: 응집도는 반대로 강할수록 좋다.
25-1
아래 C 프로그램이 출력하는 정수를 적으시오.
#include <stdio.h>
typedef struct {
const char *tag;
int bits[3];
} Rec;
int mask(int v) {
return v & 0x3C;
}
int total(const Rec *r) {
int s = 0;
for (int j = 0; j < 3; j++)
s += mask(r->bits[j]);
return s;
}
int main(void) {
Rec list[2] = {
{"P1", {0x5F, 0x21, 0xC6}},
{"P2", {0x3A, 0x94, 0x7D}}
};
const Rec *p = list;
int out = 0;
for (int i = 0; i < 2; i++)
out += total(p + i);
printf("%d", out);
return 0;
}200
[해설]
mask는 각 값과 0x3C(0011 1100)를 비트 AND 하여 가운데 4비트만 남긴다.
- P1: 0x5F→0x1C(28), 0x21→0x20(32), 0xC6→0x04(4), 합 64
- P2: 0x3A→0x38(56), 0x94→0x14(20), 0x7D→0x3C(60), 합 136
포인터 p + i로 두 구조체를 차례로 넘겨 합하면 64 + 136 = 200이다. 문자열 tag는 계산에 쓰이지 않는다.
25-1
다음 설명에 모두 해당하는 GoF 디자인 패턴의 이름을 적으시오.
- 기존 클래스를 고치지 않고 재사용하기 위해, 클라이언트가 기대하는 형태로 그 인터페이스를 바꿔 주는 중간 객체를 둔다.
- 다른 객체를 감싼다는 의미에서 래퍼(Wrapper)라고도 부른다.
- 상속으로 구현하는 클래스 방식과, 감싼 객체에 일을 넘기는(위임) 객체 방식 두 형태가 있다.
- 인터페이스가 맞지 않아 함께 쓸 수 없던 클래스들을 연결해 주는 구조 패턴이다.
Adapter(어댑터)
[해설]
호환되지 않는 인터페이스를 바꿔 연결하는 GoF 구조 패턴은 Adapter(어댑터)다.
전원 플러그 변환기처럼 기존 클래스(Adaptee)를 감싸서, 클라이언트가 기대하는 인터페이스(Target)에 맞춰 준다. 상속으로 만들면 클래스 어댑터, 감싼 객체에 일을 넘기면(위임) 객체 어댑터다.
혼동 주의: Decorator도 래퍼라고 부르지만, 인터페이스는 그대로 두고 기능만 덧붙인다.
25-1
아래 Java 프로그램이 콘솔에 출력하는 값을 적으시오.
public class Main {
static int pick(int[] d, int lo, int hi) {
if (lo > hi) return 0;
int m = (lo + hi) / 2;
return d[m] + Math.max(pick(d, lo, m - 1), pick(d, m + 1, hi));
}
public static void main(String[] args) {
int[] nums = {4, 9, 2, 11, 6, 7};
System.out.println(pick(nums, 0, nums.length - 1));
}
}19
[해설]
pick은 구간의 가운데 원소를 더하고, 왼쪽·오른쪽 절반 중 결과가 큰 쪽을 골라 재귀한다. 구간이 비면(lo > hi) 0이다.
- pick(0,5): m=2 → 2 + max(pick(0,1), pick(3,5))
- pick(0,1): m=0 → 4 + max(0, pick(1,1)=9) = 13
- pick(3,5): m=4 → 6 + max(pick(3,3)=11, pick(5,5)=7) = 17
따라서 2 + max(13, 17) = 2 + 17 = 19다.
25-1
릴레이션 구조와 관련된 용어이다. 빈칸 ①~⑥에 알맞은 것을 [보기]에서 골라 영문으로 적으시오.
- ( ① ): 한 릴레이션을 구성하는 속성(열)의 수
- ( ② ): 한 릴레이션에 들어 있는 튜플(행)의 수
- ( ③ ) Key: 어떤 릴레이션의 속성이 다른 릴레이션의 기본키를 참조할 때, 그 속성
- ( ④ ): 한 속성이 가질 수 있는, 같은 자료형의 원자값 전체 집합
- ( ⑤ ): 릴레이션의 가로 한 줄로, 개체 하나에 대한 속성값들의 모음
- ( ⑥ ): 릴레이션의 세로 한 칸으로, 개체가 가진 특성 하나를 이름 붙여 나타낸 것
[보기] Alternate, Attribute, Candidate, Cardinality, Degree, Domain, Foreign, Primary, Schema, Tuple
① Degree
② Cardinality
③ Foreign
④ Domain
⑤ Tuple
⑥ Attribute
[해설]
릴레이션 구조 용어는 행·열의 개수와 행·열 자체를 나눠 짝지어 외운다.
- Degree(차수) — 속성(열)의 수.
- Cardinality(기수) — 튜플(행)의 수.
- Foreign Key(외래키) — 다른 릴레이션의 기본키를 참조하는 속성.
- Domain(도메인) — 한 속성이 가질 수 있는 같은 자료형 원자값 전체의 집합.
- Tuple(튜플) — 행 하나로, 개체 하나의 속성값 모음.
- Attribute(속성) — 열 하나로, 개체의 특성 하나.
혼동 주의: Degree는 열, Cardinality는 행의 개수이며, Degree는 스키마가 바뀌어야 달라지지만 Cardinality는 데이터를 넣고 지울 때마다 바뀐다.