- cf. C 언어에서의 배열과 구조체
1. 배열(C)
1.1. 배열의 개념 및 1차원 배열
-
배열(Array)
- 같은 자료형의 변수를 여러 개 묶어서 사용하는 자료구조
<인덱스, 요소>의 쌍으로 구성
-
선언 및 메모리
- 선언:
자료형 배열이름[크기];(예:int A[6];) - 인덱스는 0부터 시작
- 배열의 이름(
A)은 첫 번째 요소(A[0])의 메모리 주소(base address)를 가리킨다. - 주소 계산:
base + 인덱스 * sizeof(자료형)
- 선언:
-
크기 확인
sizeof()연산자를 통해 배열 전체 크기와 요소의 크기를 확인할 수 있다.
-
초기화
- 선언과 동시에 초기화 가능 (
int A[6] = {1, 2, ...};) - 값을 적게 넣으면 나머지는 0으로 채워진다.
- 선언과 동시에 초기화 가능 (
1.2. 2차원 배열
- 구조: 행(Row)과 열(Col)로 구성된 격자 형태의 데이터
- 메모리 저장: 논리적으로는 격자 형태이나, 물리적 메모리에는 1차원(선형)으로 순서대로 저장
- 선언:
int A[2][3] = {{1, 2, 3}, {4, 5, 6}};
1.3. 문자열(String)
-
특징: 문자의 배열(char array)로 표현
-
NULL 문자
- 문자열의 끝을 알리기 위해 항상 마지막에
\0(NULL)이 포함 - 따라서 “Hello”를 저장하려면 최소 6칸의 배열이 필요
- 문자열의 끝을 알리기 위해 항상 마지막에
-
함수:
strcpy(복사),strlen(길이 계산) 등을 사용
1.4. 함수와 배열
-
전달 방식
- 배열을 함수의 매개변수로 넘길 때, 배열의 이름(주소값)이 전달
- (Call-by-Reference와 유사한 효과)
-
주의점
- 배열의 크기 정보는 함께 전달되지 않으므로,
- 배열의 크기(길이)를 별도의 매개변수로 함께 넘겨주어야 한다.
2. 배열(자료구조)
2.1. Time Complexity
| Array | Search | Best | Average | Worst |
|---|---|---|---|---|
| Unsorted | Linear Search | |||
| Sorted | Binary Search | |||
| Sorted | Interpolation Search |
-
Binary Search의 Best Case는 탐색의 관점에서 , 탐색 차수의 관점에서
-
Interpolation Search는 직선 형태의 균등 분포에서 , 불균등 분포에서
-
Insert/Delete:
2.2. Features
-
연속된 메모리 공간에 저장됨
- → Random Access(임의 접근): 빠른 인덱스 접근 가능
- → 메모리 접근 패턴이 일정해 캐시 친화적
-
(동적 배열 제외) 크기 고정
- → 메모리 낭비 가능성
- → 삽입/삭제 시 데이터 이동 발생 (삽입/삭제가 빈번하면 부적합)
2.3. Applications
- 기본적인 자료구조 구현
- 다차원 데이터 처리
- 인덱스 접근을 활용하는 비디오 프레임 버퍼
- 자주 변경되지 않는 정적 데이터 저장
3. 배열의 탐색
-
탐색: 테이블(레코드의 집합)에서 원하는 탐색키를 가진 레코드를 찾는 작업
-
테이블 구성 방법: 배열, BST, 해시 테이블 등
- 테이블 구조에 따라 탐색·삽입·삭제 성능이 달라짐
3.1. Linear Search
-
순차 탐색(선형 탐색): 일렬로 늘어선 레코드를 앞에서부터 순차적으로 비교하며 탐색
- 배열이나 연결 리스트로 구성
-
동작: 배열의
left부터right까지 순서대로 탐색키와 비교- 같으면 성공(인덱스 반환), 끝까지 없으면 실패(-1 반환)
- 시간 복잡도: 최선 O(1), 평균/최악 O(n)
- 분석: 비효율적이지만, 비정렬 테이블이라면 별다른 대안은 없음
for (int i = left; i <= right; i++)
if (A[i] == key) {
// if (i != left) { i -= int; swap(A[i], A[i+1])} // 교환 전략
return i;
]
return -1;- 개선 - 자기 구성 순차 탐색: 자주 탐색되는 레코드를 테이블의 앞쪽으로 옮겨 탐색 효율 증가
- move to front: 찾은 레코드를 맨 앞으로 이동
- transpose: 찾은 레코드를 한 칸씩 앞쪽으로 교환
- count-based: 탐색 횟수 집계 후 빈도 순으로 재배치
3.2. Binary Search
int binary_search(int A[]. int key, int low, int high) {
while (low <= high) {
int mid = (low + high) / 2;
if (key == A[mid]) return mid; // 탐색키와 레코드가 같으면 반환
else if (key < A[mid]) high = mid - 1; // 레코드가 크면 왼쪽으로
else low = mid + 1; // 레코드가 작으면 오른쪽으로
}
return -1;
}-
이진 탐색: 정렬된 배열에서 가운데 요소와 비교하여 탐색 범위를 절반씩 줄여 나가는 방법
- 구현: 재귀(recursive) 또는 반복(iterative) 구조
-
분석
- 삽입/삭제: O(n), 탐색: O(log n) (매 단계마다 범위를 절반으로 축소)
- 삽입/삭제가 빈번하면 AVL 트리
- 탐색 연산만 주로 처리하면 효율적
3.3. Interpolation Search
- 보간 탐색(Interpolation Search)
- 탐색키가 존재할 위치를 예측하여 탐색하는 방법
- 래코드의 키값과 탐색키의 비율을 고려해 탐색 위치 계산
4. 구조체
4.1. 구조체의 개념 및 정의
-
구조체(Structures)
- 서로 다른 자료형의 데이터를 하나로 묶은 모임
- (배열은 ‘같은’ 자료형의 모임)
-
선언
struct키워드 사용typedef를 사용하면 매번struct를 쓰지 않고 새로운 자료형처럼 사용할 수 있어 편리
-
접근
- 멤버 접근 연산자
.(점)을 사용 (예:student.id)
- 멤버 접근 연산자
4.2. 구조체의 연산
-
대입
- 대입 연산자(
=)를 통해 구조체 변수 간 복사는 가능
- 대입 연산자(
-
비교
- 비교 연산자(
==,!=)는 사용 불가 - 비교하려면 내부 멤버들을 일일이 비교하는 함수를 직접 만들어야 한다.
- 비교 연산자(
4.3. 구조체 응용
- 중첩 구조체: 구조체 안에 다른 구조체를 멤버로 포함할 수 있다.
- 구조체 배열: 구조체를 요소로 가지는 배열을 만들 수 있다. (예:
Friend list[45];)
4.4. 구조체와 함수
- 전달 방식: 기본적으로 Call-by-Value(값에 의한 호출)
- 함수에 구조체를 넘겨서 내용을 변경하더라도, 원본에는 영향을 주지 않는다. (복사본이 전달됨)
- 원본을 수정하려면 포인터를 사용해야 한다.
Lab. 희소 행렬 표현
- 희소 행렬(Sparse Matrix): 대부분의 항이 0인 행렬
- 효율적 표현: 2차원 배열 전체를 저장하는 대신, 0이 아닌 요소만
<행, 열, 값>의 구조체 배열로 저장하여 메모리를 절약
5. 배열과 구조체의 응용 : 다항식 프로그램
5.1. 다항식의 표현 방법
다항식 을 컴퓨터로 표현하는 두 가지 방법을 비교
-
방법 1: 모든 계수 저장 (배열)
- 배열의 **인덱스를 차수(지수)**로, 값을 계수로 사용
- 장점: 구현이 간단함
- 단점: 처럼 차수는 높은데 항이 적은 경우, 0인 계수들을 위해 많은 메모리가 낭비됨
-
방법 2: 0이 아닌 항만 저장 (구조체 배열)
- 구조체에
(계수, 차수)쌍을 저장하고, 이 구조체들의 배열로 다항식을 표현 - 장점: 희소 다항식의 경우 메모리 공간을 훨씬 절약할 수 있음
- 단점: 덧셈 등의 연산 구현이 방법 1보다 조금 더 복잡함
- 구조체에
5.2. 다항식 덧셈 알고리즘
- 두 다항식 A와 B의 최고차항부터 비교하며 덧셈을 수행하여 새로운 다항식 C를 만든다.
- A의 차수 > B의 차수: A의 항을 C에 추가
- A의 차수 < B의 차수: B의 항을 C에 추가
- A의 차수 == B의 차수: 계수를 더해서 C에 추가 (단, 계수의 합이 0이면 추가하지 않음)