데이타구조
2016-03-15
배열, 포인터, 동적할당, 구조체
귀납적 정의 (Inductive Definition)
리스트, 트리
퀴즈
- 추상 데이타 타입 (Abstract Data Type) 이란?
답: 인터페이스(interface) 와 구현(implementation)을 분리해서 생각 - 추상 데이타 타입을 사용하는 이유? (효과랄까?)
답: 인터페이스를 유지하면서 내부 구현을 바꿀 수 있다 (더 효율적이거나 새로운 기술 도입) - 크기가 n인 배열 a[n]에 대한 다음 프로그램의 시간복잡도로 맞는 것을 모두 고르시오 ... 답: 3,4
- 1. O(1) 2. O(n) 3. O(n^2) 4. O(n^3)
for (int i = 0; i < n; ++i) {
for (int j = i+1; j <n; ++ i) {
swap(a+i, a+j) // O(1)
}
}
kyagrd@korea.ac.kr
제목: [퀴즈0315] 이름 학번
과제 제출 안내
- Google Drive 공유 폴더를 통해 (종이 X, 메일 X)
-
[새로 만들기] 버튼을 눌러
DS16<이름><학번> 폴더를 만들고 (예: DS16김연아123456)
만들어진 폴더를 우클릭하여
폴더 공유설정으로 kyagrd@gmail.com 에게 공유 (편집권한) - Google 메일 계정만 있으면 Google Drive 서비스 이용 가능
- Google 메일 계정은 무료로 만들 수 있으며
참고로 안드로이드 스마트폰 사용자는 누구나 이미 보유
배열과 포인터 요약 정리
-
T a[N]; // T 타입의 길이 N짜리 배열
- a는 첫 칸 주소를 가리키는 포인터와 같은 역할
- *a == a[0] 또는 a == &(a[0])
- sizeof(a) == sizeof(T) * N
- a는 첫 칸 주소를 가리키는 포인터와 같은 역할
- T* p = a; // p도 배열 a의 첫 칸 주소를 가리킴
- 그러나 sizeof(p) 는 보통은 sizeof(int) 와 같다
- p[i] == *(p + i) == *(i + p) == i[p] // 네번째는 비추
- 할당된 메모리의 끝의 바로 다음까지는 계산해도 됨
- a + N 또는 p + N 까지 하는 것은 괜찮다
- a[N] 또는 *(a + N) 는 하면 안된다
동적 (메모리) 할당
-
C++의 new 문법이 훨씬 간결하므로 C++ 기준으로 설명
(C의 동적할당이 궁금하면 교과서에서 찾아볼 것) - 정적 할당 (일반 변수 및 배열)
- 실행 전에 필요한 메모리 크기가 결정됨
- 변수 스코프를 벗어나면 알아서 메모리가 해제됨
- 동적 할당
- 프로그램 실행 중에 메모리가 필요한 만큼
- C/C++에서는 기본적으로 수동으로 메모리를 해제해야
- 동적 할당된 메모리를 자동으로 해제하는 방식으로는 Reference Counting과 Garbage Collection이 있다
동적 (메모리) 할당
-
T* p = new T;
- T 타입의 값을 하나 저장할 수 있는 메모리 공간 할당
- delete p; 와 같이 해제
- T* p = new T[N]; // 동적 배열 할당
- T 타입의 값을 N개 저장할 수 있는 연속적 공간 할당
- delete [] p; 와 같이 해제
- N값을 프로그램 실행 중에 계산할 수 있음
- 포인터일 뿐 sizeof(p) 는 그냥 주소값 정수 크기
배열처럼 할당된 공간을 sizeof로 알 수 없다
- 이 수업에서는 메모리 수동 해제는 생략할 방침
이차원 이상 배열 동적할당 팁
- ??????? p = new T[M][N1][N2]...[Nn];
- 이거 무슨 포인터 타입인지 생각하면 머리아픔
- 결론적으로는 T[N1][N2]...[Nn] 에 대한 포인터인데
이걸 C/C++ 문법으로 어떻게 쓸건지도 머리아픔
- 그러므로 typedef 활용해서 컴파일러가 알아서 하도록
- typedef int MyInt;
- typedef T MyArray[N1][N2]...[Nn];
int main(void) {
MyArray* = new MyArray[M];
}
동적할당하면서 초기화 팁
- T* p = new T( 초기값 );
- int* p = new int(3); // *p == 3
구조체
-
struct MyType { T1 name1; T2 name2; ...; Tn namen };
-
struct list { int val; list* next; };
-
struct tree { int val; tree* left; tree* right; };
-
struct point { float x; float y; };
-
-
point p = { 1.3, 4.5 }; // 배열과 초기화와 같은 문법
-
p.x == 1.3
-
(&p)->y == 4.5
-
-
point* ptr = new point( { 1.3, 4.5 } ); // 동적 할당 + 초기화
-
ptr->x == 1.3
-
(*ptr).y == 4.5
-
귀납적 정의 (Inductive Definition)
-
자연수의 귀납적 정의
-
0 은 자연수 (base case)
-
n 이 자연수면 1+n 도 자연수 (inductive case)
-
- 참고: 수학적귀납법
P(0)가 참임을 보이고 (base case)
P(n)이 참이라면 P(1+n)도 참임을 보이면 (inductive case)
모든 자연수에 대해 P라는 성질이 만족함을 증명한 것이다
재귀적(recursive) 데이타 구조의 귀납적 정의
-
리스트의 귀납적 정의
-
[] 는 리스트 (base case)
-
l 이 리스트면 v :: l 도 리스트 (inductive case)
-
- Binary Tree (두갈래나무 또는 이진트리)의 귀납적 정의
-
nil 은 두갈래나무
-
t1 과 t2 가 두갈래나무라면 도 두갈래나무
-
t1
t2
v
(참고: 교과서에서는 recursion을
"재귀" 대신 "순환"이라 번역함)
귀납적 정의를 코드로 옮기면
-
struct list { int val; list* next };
-
NULL // 또는 0
-
// v가 int 값이고 l은 list 포인터일 때
new list( { v, l } )
-
- struct tree { int val; tree* left; tree* right; }; // binary tree
-
NULL // 또는 0
-
// v가 int 값이고 t1과 t2가 tree 포인터일 때
new tree { v, t1, t2 }
-
과제 (Due: 3/2월요일 밤 1번만)
-
정수 배열로부터 다음을 구하는 프로그램 작성
-
평균값(mean) -- 쉽다
-
중간값(median) -- 힌트는 정렬
-
최빈값(mode) -- 힌트는 역시 정렬
-
-
이번 수업에서 다룬 NULL로 끝나는 연결 리스트에 대해
- 리스트의 맨 끝에 원소를 하나 추가하는 프로그램 작성
- 순서를 거꾸로 뒤집은 리스트를 만드는 프로그램 작성
- 이번 과제는 main함수 이외에 다른 함수 작성 안해도 됩니다.
- Google Drive 자신의 공유폴더에 hw1.cpp 파일명으로 제출
- 반드시 컴파일되는지 확인. 컴파일 에러나면 0점.
데이타구조
By 안기영 (Ahn, Ki Yung)
데이타구조
2016-03-15
- 1,987