260 likes | 585 Views
자료 구조. 제 2 장 : 배열과 구조 이 형 원 강릉대학교 컴퓨터공학과. 학습 내용. 배열과 구조체의 정의 및 C 언어에서의 표현 배열과 구조체를 이용한 예제 다항식 희소 행렬 다양한 정방 행렬과 배열 표현. 배열 ADT. 배열 i) 일련의 연속적인 메모리 위치 구현 측면 ii) <index, value> 쌍으로 구성된 집합 Structure Array
E N D
자료 구조 제 2 장 : 배열과 구조 이 형 원 강릉대학교 컴퓨터공학과
학습 내용 • 배열과 구조체의 정의 및 C 언어에서의 표현 • 배열과 구조체를 이용한 예제 • 다항식 • 희소 행렬 • 다양한 정방 행렬과 배열 표현
배열 ADT • 배열 i) 일련의 연속적인 메모리 위치 구현 측면 ii) <index, value> 쌍으로 구성된 집합 • StructureArray objects: index의 각 값에 대해 집합 item에 속한 한 값이 있는 <index,value>쌍의 집합. index는 일차원 or 다차원의 유한 순서 집합. functions: AArray, i index, xitem, j, sizeintegerArray Create(j,list) ::= return j차원의 배열. Item Retrieve(A, i) ::= if (iindex) return배열 A의 인덱스 i와 관련된 항목else return에러.Array Store(A,i,x) ::= if (iindex) return새로운 쌍<i,x>가 삽입된 배열 Aelse return에러. endArray
C에서의 일차원 배열 • int list[5], *plist[5]; • 5 개의 연속적인 메모리 장소 할당 • list[i]: 정수, plist[i]: 정수로의 포인터 • addrlist[i] = addrlist[0] + i*sizeof(int) • list = list[0]를 가리키는 포인터 • list + i = list[i]를 가리키는 포인터 • (list+i) = &list[i], *(list+i) = list[i] • 배열이 함수의 매개 변수로 사용되는 경우 • 일차원 배열의 범위는 주프로그램에서만 정의 • Q. 배열의 크기가 부프로그램에서 필요하다면 ? • call-by-value를 이용한 call-by-reference 효과
배열 프로그램의 예 #define MAX_SIZE 100float sum(float [], int);float input[MAX_SIZE], answer;int i;void main(void) { float sum(float list[], int n) { for (i = 0; i < MAX_SIZE; i++) float tempsum = 0; input[i] = i; for (i = 0; i < n; i++) answer = sum(input, MAX_SIZE); tempsum += list[i]; printf("The sum is: %f", answer); return tempsum;} } • 호출시 input(=&input[0])은 임시 장소에 복사되고 formal parameter list와 연관됨
구조 : struct • type이 다른 데이타를 그룹화(레코드) • 항목은 타입과 이름으로 식별 struct {char name[10]; int age ; float salary; } person; • typedef 문장을 사용한 구조 데이타 타입 생성 typedef struct human_being { typedef struct {char name[10]; char name[10]; int age; 또는 int age; float salary; float salary; }; } human_being ; • 변수 선언 : human_being person1, person2 ;
구조 : struct(계속) • 구조 속의 또다른 구조 정의 typedef struct { typedef struct human_being { int month; char name[10]; int day; int age; int year; float salary; } date ; date dob; } ; [예] person1.dob.month = 2; person1.dob.day = 11; person1.dob.year = 1944;
유니언 • union의 필드들은 메모리 공간을 공용 • 한 필드만 어느 한 시점에 활동적이 되어 사용 가능 typedefstruct sex_type { typedefstruct human_being {enum tag {female, male} sex; char name[10];union { int age; int children; float salary; int beard; date dob;} u ; sex_type sex_info; } ; }; • 값 할당 human_being person1, person2; person1.sex_info.sex = male; person1.sex_info.u.beard = FALSE; person2.sex_info.sex = female; person2.sex_info.u.children = 4;
자체 참조 구조 • 구성요소 중 자신을 가리키는 포인터가 있는 구조 • 동적 기억장소 관리 루틴(malloc, free)이 필요 typedef struct list { char data; list *link; } ; list item1, item2, item3;item1.data = 'a'; item2.data = 'b';item3.data = 'c';item1.link = item2.link = item3.link = NULL;item1.link = &item2; item2.link = &item3;
순서 리스트 • 순서 리스트(ordered list, linear list) • 원소들의 순서가 있는 모임 : (a0, a1, ..., an-1) 예) Days-of-week : (Mon, Tue, Wed, Thu, Fri, Sat, Sun) : list1st 2nd 3rd 4th 5th 6th 7th : order • 연산 ⅰ. length n ⅱ. reading (RL, LR) ⅲ. retrieve i-th element, 0 ≤ i < n ⅳ. update i-th element's value, 0≤ i < n ⅴ. insertion (i번째 위치, 0 ≤ i≤n) : i, i+1, ..., n-1 i+1, i+2, ..., n ⅵ. deletion (i번째 항목, 0≤ i < n) : i+1, ..., n-1i, i+1, ..., n-2 • 표현 • 순차적 사상(배열) • 비순차적 사상(연결 리스트)
다항식 • 다항식의 기초 • A(x)=anxn + an-1xn-1 + … + a1x1 + a0x0 • 각 항이axe where a : 계수(coefficient) an0 e : 지수(exponent) - unique x : 변수(variable) • 차수(degree) : 다항식에서 가장 큰 지수 • A(x) = aixi, B(x) = bixi • A(x) + B(x) = (ai + bi) xi • A(x)B(x) = (aixi ( bjxj )) • Q. 다항식과 순서 리스트와의 관계 ?
다항식: ADT Polynomial Objects : P(x) =a1xe1+…+anxen:<ei,ai>의 순서쌍 집합 (ei(≥0):정수) Functions :poly, poly1, poly2 다항식, coef 계수, expon 지수 Polynomial Zero() ::= returnp(x) = 0 Boolean IsZero(poly) ::= if (poly) return FALSE else return TRUE Coefficient Coef(poly,expon) ::= if (exponpoly) return계수 else return 0 Exponent Lead_Exp(poly) ::= return poly에서 제일 큰 지수 Polynomial Attach(poly, coef, expon) ::= if (exponpoly) return오류 else return <coef, exp>항이 삽입된 다항식poly Polynomial Remove(poly, expon) ::= if (exponpoly) return지수가 expon인 항이 삭제된 다항식 poly else return 오류 Polynomial SingleMult(poly,coef,expon) ::= return다항식 polycoefxexpon Polynomial Add(poly1, poly2) ::= return다항식 poly1 + poly2 Polynomial Mult(poly1, poly2) ::= return다항식 poly1 * poly2
다항식: 함수 padd /* 다항식 d=a+b (다항식 표현에 독립) */ d = Zero(); while (! IsZero(a) && ! IsZero(b)) do { switch COMPARE(Lead_Exp(a), Lead_Exp(b)) { case -1: d = Attach(d, Coef(b, Lead_Exp(b)), Lead_Exp(b)); b = Remove(b, Lead_Exp(b)); break; case 0 : sum = Coef(a, Lead_Exp(a)) + Coef(b, Lead_Exp(b)); if (sum) { Attach(d, sum, Lead_Exp(a)); a = Remove(a, Lead_Exp(a)); b = Remove(b, Lead_Exp(b)); } break; case 1 : d = Attach(d, Coef(a, Lead_Exp(a)), Lead_Exp(a)); a = Remove(a, Lead_Exp(a)); }}a 또는 b의 나머지 항을 d에 삽입한다.
다항식: 표현 방법 • 다항식의 표현 방법 (I) • #define MAX_DEGREE 101 /* 다항식의 최대 차수 + 1 */ typedef struct { int degree; float coef[MAX_DEGREE]; } polynomial; • 예) x4+10x3+3x2+1를 polynomial type a에 저장 a.degree = 4 a.coef 1 10 3 0 1 ….. • 단점 : 기억 장소의 낭비 가능성 Q. when ?
다항식: 표현 방법(계속) • 다항식의 표현 방법 (II) • typedef struct {float coef; int expon;} polynomial; polynomial terms[MAX_TERMS]; • 예) A(x)=2x1000+1, B(x)=x4+10x3+3x2+1를 배열 terms에 저장 starta finisha startb finishb avail coef 2 1 1 10 3 1 exp 1000 0 4 3 2 0 • 장점: sparse polynomial의 경우 기억 장소 문제 해결 terms안에 저장될 다항식의 수에 제한이 없음 • 단점: 최악의 경우, (I) 보다 2배의 기억장소 Q. when ?
다항식: 알고리즘 padd void padd(int starta, int finisha, int startb, int finishb, int *startd, int *finishd) {float coefficient;*startd = avail;while (starta <= finisha && startb <= finishb) switch (COMPARE(terms[starta].expon, terms[startb].expon)) case -1: attach(terms[startb].coef, terms[startb].expon); startb++; break; case 0: coefficient = terms[starta].coef + terms[startb].coef; if (coefficient) attach(coefficient, terms[starta].expon); starta++; startb++; break; case 1: attach(terms[starta].coef, terms[starta].expon); starta++;for(; starta <= finisha; starta++) attach(terms[starta].coef,terms[starta].expon);for(; startb <= finishb; startb++) attach(terms[startb].coef, terms[startb].expon); *finishd = avail-1; }
다항식: 알고리즘 padd(계속) void attach(float coefficient, int exponent) { /* 새 항을 다항식에 첨가 */if (avail >= MAX_TERMS) { fprintf(stderr, "다항식에 항이 너무 많다."); exit(1); }terms[avail].coef = coefficient;terms[avail++].expon = exponent; } • padd의 분석 (m,n: A와 B의 0이 아닌 항의 수) • 시간 복잡도 while 루프 : 각 반복마다 starta나 startb 또는 둘 다 값이 증가 최대 반복 횟수 = m+n-1 Q.When ? for 루프 : O(m+n) • 문제점 : avail = MAX_TERMS ? • 불필요한 다항식 제거 후 배열 끝에 연속적인 가용공간 생성 • 데이타 이동시간, 각 다항식의 starti, finishi변경
희소행렬의 표현 • 행렬의 표준 표현 • 2차원 배열 • 희소 행렬(sparse matrix)의 경우 기억 장소 낭비 • 희소 행렬의 표현 방법 • store only the nonzero elements typedef struct {int col; int row ; int value ; } term; term a[MAX_TERMS]; • 추가 고려 사항 • 행의 수, 열의 수, non-zero elements의 수, 순서 (열 우선 or 행 우선)
희소행렬의 표현(계속) • 표준 표현 희소 행렬 표현 열0 열1 열2 열3 열4 열5 행 열 값 행0 15 0 0 22 0 -15 a[0] 6 6 8 행1 0 11 3 0 0 0 a[1] 0 0 15 행2 0 0 0 -6 0 0 a[2] 0 3 22 행3 0 0 0 0 0 0 a[3] 0 5 -15 행4 91 0 0 0 0 0 a[4] 1 1 11 행5 0 0 28 0 0 0 a[5] 1 2 3 a[6] 2 3 -6 a[7] 4 0 91 a[8] 5 2 28 • a[0].row: 행수, a[0].col: 열수, a[0].value: 0이 아닌 항의 총수 • 행 우선 & 행 내에서는 열우선
행렬의 전치 ⑴ 일반적인 행렬 표현법 • 행렬 전치의 예 15 10 0 15 5 0 5 0 0 ==> 10 0 20 0 20 0 0 0 0 • 알고리즘 void normal_transpose(term a[], term b[], int columns, int rows) { /* a를 전치시켜 b에 저장 */ int i, j;for (j=0; j<columns; j++) for (i=0; i<rows; i++) b[j][i] = a[i][j]; } Q. 시간 복잡도 ?
행렬의 전치(계속) ⑵ 희소 행렬(행우선) 표현법 행 열 값 행 열 값a[0] 6 6 8 b[0] 6 6 8 a[1] 0 0 15 b[1] 0 0 15a[2] 0 3 22 b[2] 0 4 91a[3] 0 5 -15 b[3] 1 1 11a[4] 1 1 11 b[4] 2 1 3a[5] 1 2 3 b[5] 2 5 28a[6] 2 3 -6 b[6] 3 0 22a[7] 4 0 91 b[7] 3 2 -6a[8] 5 2 28 b[8] 5 0 -15 • 각 행 i에 대해서 <i,j,value><j,i,value> : 행 우선이 유지 X • 각 열 j에 대해서 <i,j,value><j,i,value> : 행 우선이 유지됨
행렬의 전치(계속) void transpose(term a[], term b[]) { /* a를 전치시켜 b에 저장 */ int n, i, j, currentb;n=a[0].value; b[0].row=a[0].col; b[0].col=a[0].row; b[0].value=n; if (n > 0) { currentb = 1; for (i =0; i < a[0].col; i++) /* a에서 열별로 전치*/ for (j = 1; j <= n; j++) /* 현재 열로부터 원소를 찾는다. */ if (a[j].col == i) { /* 현재 열에 있는 원소를 b에 첨가 */ b[currentb].row = a[j].col; b[currentb].col = a[j].row; b[currentb].value = a[j].value; currentb++; }} } Q.시간 복잡도 ?
행렬의 전치(계속) ⑶ 희소 행렬의 빠른 전치 void fast_transpose(term a[], term b[]) { /* a를 전치 b에 저장 */int row_terms[MAX_COL], starting_pos[MAX_COL];int i,j, num_col = a[0].col, num_terms = a[0].value;b[0].row = num_cols; b[0].col = a[0].row; b[0].value = num_terms;if (num_terms > 0) { for(i=0; i < num_cols; i++) row_terms[i] = 0; for(i = 1; i <= num_terms; i++) row_terms[a[i].col]++; starting_pos[0] = 1; for(i=1; i<num_cols; i++) starting_pos[i]=starting_pos[i-1]+row_terms[i-1]; for(i = 1; i <= num_terms; i++) { j = starting_pos[a[i].col]++; b[j].row = a[i].col; b[j].col = a[i].row; b[j].value = a[i].value; }} } Q. 시간 복잡도 ?
행렬 전치 알고리즘의 분석 • 시간 복잡도 • 희소 행렬 (원소 수 << columns*rows)⑴ Ο(columns·rows) ⑵ Ο(columns·elements) ⑶ Ο(columns+elements) • 희소 행렬이 아닌 경우 (원소 수 columns*rows) ⑴ Ο(columns·rows) ⑵ Ο(columns·elements) = Ο(columns2·rows) ⑶ Ο(columns+elements) = Ο(columns·rows) Q. What can you say from these ?
다양한 형태의 정방 행렬 • 대각 행렬(diagonal matrix) A[n][n] x 0 0 0 0 x 0 0 A[i][j] = 0 if i j 0 0 x 0 0 0 0 x • 하삼각 행렬(lower triangular matrix) A[n][n] x 0 0 0 x x 0 0 A[i][j] = 0 if i < j x x x 0 x x x x
다양한 형태의 정방 행렬(계속) • 상삼각 행렬(upper triangular matrix) A[n][n] x x x x 0 x x x A[i][j] = 0 if i > j 0 0 x x 0 0 0 x • 3원 대각 행렬(tridiagonal matrix) A[n][n] x x 0 0 0 x x x 0 0 A[i][j] = 0 if |i - j| > 1 0 x x x 0 0 0 x x x 0 0 0 x x