Q. 시간 복잡도

Download Report

Transcript Q. 시간 복잡도

자료 구조
제 4 장 : 리스트
이형원
강릉대학교 컴퓨터공학과
학습 내용
포인터
단순 연결 리스트
리스트 활용의 예
 스택과 큐
 다항식
 희소 행렬
추가 리스트 연산들
이중 연결 리스트
2
순차적 vs. 연결된 표현
순차적 표현
 연속된 원소들이 차례대로 저장
 장점 : 스택이나 큐의 삽입/삭제에 적합
 단점 : 임의의 원소의 삽입/삭제 Q. Why ?
크기가 가변적인 순서 리스트 조작 Q. Why ?
연결된(linked) 표현
 임의의 위치에 저장
 장점 : 순차적 표현의 문제점 해결
 단점 : 다음 원소에 대한 정보 필요
• 리스트 원소(노드) = 데이타 요소 + 포인터(링크)
3
C 언어에서의 포인터
모든 data type T에 대해 pointer data type T’가 존재
포인터 변수의 실제 값은 메모리의 주소
연산자
① & : 주소 연산자
② * : 역참조(간접 지시) 연산자
int *pi;
*pi = 1;
error !! Q. Why ?
③ 포인터 지정 연산자
int i, *p, *q;
p = &i;
q = p;
④ 4칙 연산 (∵ 포인터는 음이 아닌 정수)
4
C 언어에서의 포인터(계속)
널 포인터
 어떤 객체/함수도 가리키지 않음
 NULL이라는 매크로로 정의
 관계 연산에 사용  false로 해석 : if (pi==NULL), if (!pi)
포인터의 위험성
 실제로 대상을 가리키지 않는 경우는 NULL로 설정
 포인터 타입간의 변환 시 명시적인 type casting
pi = (int *) malloc(sizeof(int));
pf = (float *) pi;
 함수에 대한 반환 값의 타입을 명확히 정의
5
C 언어에서의 포인터(계속)
동적 할당 기억장소의 사용
 실행 중 메모리 할당 (실행 전에는 크기를 예상 못함)
int i, *pi;
float f, *pf;
pi = (int *) malloc(sizeof(int));
pf = (float *) malloc(sizeof(float));
*pi = 1024; *pf = 3.14;
printf(“an integer = %d, a float = %f\n”, *pi, *pf);
free(pi);
free(pf);
 dangling reference가 발생하지 않도록 주의
6
단순 연결 리스트
연결 리스트를 만드는 방법
① 노드의 구조를 정의: 자체 참조 구조 사용
typedef struct list_node *list_pointer;
typedef struct list_node {
int data;
list_pointer link;
};
list_pointer ptr = NULL;
ptr
10
NULL
② 필요한 노드 생성
ptr = (list_pointer)malloc(sizeof(list_node));
③ 연결 리스트의 필드 값 지정
ptr->data = 10; /* (*ptr).data = 10; 과 동일*/
ptr->link = NULL;
7
단순 연결 리스트(계속)
두개의 노드를 가진 연결 리스트의 생성
list_pointer create2() {
list_pointer first, second;
first = (list_pointer)malloc(sizeof(list_node));
second = (list_pointer)malloc(sizeof(list_node));
second->link = NULL;
second->data = 20;
first->data = 10;
first->link = second;
return first;
}
first
10
20
NULL
8
단순 연결 리스트(계속)
data=50인 노드를 리스트 ptr의 node 뒤에 삽입
#define IS_FULL(ptr) (!(ptr))
void insert(list_pointer *ptr, list_pointer node) {
list_pointer temp = (list_pointer)malloc(sizeof(list_node));
if (IS_FULL(temp)) {
fprintf(stderr, "The memory is full");
exit(1);
insert(&ptr, ptr);
}
temp->data = 50;
10
20 NULL
if (*ptr) {
ptr
temp->link = node->link;
node->link = temp;
}
50
temp
else {
temp->link = NULL;
*ptr = temp;
9
}
}
단순 연결 리스트(계속)
원소 삭제
void deleteq(list_pointer *ptr, list_pointer trail, list_pointer
node) {
/* trail은 삭제될 node의 선행노드이며 ptr은 리스트의 시작 */
if (trail) trail->link = node->link;
else *ptr = (*ptr)->link;
free(node);
}
ptr
삭제 전 :
10
delete(&ptr, NULL, ptr); 호출 후
ptr
50
20 NULL
50
20 NULL
ptr, ptr->link); 호출 후
ptrdelete(&ptr,
10
20 NULL
10
동적 연결 스택과 큐
연결 리스트를 이용 : 삽입과 삭제가 편리
top
원소 링크
…..
front
null
rear
원소 링크
…..
null
11
동적 연결 다중 스택
선언
#define MAX_STACKS 10 /* 스택의 최대 원소수 */
typedef struct {
int key;
/* 기타 필드 */
} element;
typedef struct stack *stack_pointer;
typedef struct stack {
element item;
stack_pointer link;
};
stack_pointer top[MAX_STACKS];
스택 초기화 : top[i]=NULL, 0≤i<MAX_STACKS
12
동적 연결 다중 스택(계속)
삽입 : add(&top[stack_no], item);
void add(stack_pointer *top, element item) {
/* 스택의 top에 원소를 삽입 */
stack_pointer temp = (stack_pointer) malloc(sizeof
(stack));
if (IS_FULL(temp)) {
fprintf(stderr,"The memory is full");
exit(1);
}
temp->item = item;
temp->link = *top;
*top = temp;
} Q. How to implement “IS_FULL” ?
13
동적 연결 다중 스택(계속)
삭제 : item = delete(&top[stack_no]);
element delete(stack_pointer *top) {
/* 스택으로부터 원소를 삭제 */
stack_pointer temp = *top;
element item;
if (IS_EMPTY(temp)) {
fprintf(stderr,"The stack is empty");
exit(1);
}
item = temp->item;
*top = temp->link;
free(temp);
return item;
} Q. How to implement “IS_EMPTY” ?
14
동적 연결 다중 큐
선언
#define MAX_QUEUES 10 /* 큐의 최대 원소 수 */
typedef struct queue *queue_pointer;
typedef struct queue {
element item;
queue_pointer link;
};
queue_pointer front[MAX_QUEUES],
rear[MAX_QUEUES];
큐 초기화 : front[i]=NULL, 0≤i<MAX_QUEUES
15
동적 연결 다중 큐(계속)
삽
입
addq(&front[queue_no],&rear[queue_no],item);
void addq(queue_pointer *front, queue_pointer *rear,
element item) {
/* 큐의 rear에 원소를 삽입 */
queue_pointer temp = (queue_pointer) malloc(sizeof
(queue));
if (IS_FULL(temp)) {
fprintf(stderr,"The memory is full");
exit(1);
}
temp->item = item;
temp->link = NULL;
if (*front) (*rear)->link = temp;
16
else *front = temp;
:
동적 연결 다중 큐(계속)
삭제 : item=deleteq(&front[queue_no]);
element deleteq(queue_pointer *front) {
/* 큐에서 원소를 삭제 */
queue_pointer temp = *front;
element item;
if (IS_EMPTY(*front)) {
fprintf(stderr,"The queue is empty");
exit(1);
}
item = temp->item;
*front = temp->link;
free(temp);
return item;
} Q. How to implement “IS_EMPTY” ?
17
다항식 : 단순 연결 리스트 표현
typedef struct poly_node *poly_pointer;
typedef struct poly_node {
int coef;
int expon;
poly_pointer link;
};
poly_pointer a, b, c;
a
3x14 + 2x8 + 1
3 14
2
8
1
0 null
8x14 - 3x10 + 10x6
8 14
-3 10
10
6 null
b
18
다항식 : 덧셈
poly_pointer padd(poly_pointer a, poly_pointer b) {
poly_pointer front, rear, temp; int sum;
rear = (poly_pointer)malloc(sizeof(poly_node));
…..
front = rear;
while(a && b)
switch (COMPARE(a->expon, b->expon)) {
case -1: attach(b->coef,b->expon,&rear); b = b->link; break;
case 0 : sum = a->coef + b->coef; if (sum) attach(sum,a>expon,&rear);
a = a->link; b->link; break;
case 1 : attach(a->coef,a->expon,&rear); a = a->link;
}
for (; a; a = a->link) attach(a->coef,a->expon,&rear);
for (; b; b = b->link) attach(b->coef,b->expon,&rear);
rear->link = NULL;
temp = front; front = front->link; free(temp);
return front;
19
다항식 : 덧셈(계속)
void attach(float coefficient, int exponent, poly_pointer *ptr)
{
/* coef=coefficient이고 expon=exponent인 새로운 노드를
생성 하고, 그것을 ptr에 의해 참조되는 노드에 첨가한다. ptr
을 갱신하여 이 새로운 노드를 참조하도록 한다. */
poly_pointer temp;
temp = (poly_pointer)malloc(sizeof(poly_node));
if (IS_FULL(temp)) {
fprintf(stderr, "The memory is full");
exit(1);
}
temp->coef = coefficient;
temp->expon = exponent;
(*ptr)->link = temp;
20
*ptr = temp;
다항식 : 제거
void erase(poly_pointer *ptr) {
/* ptr에 의해 참조되는 다항식을 제거 */
poly_pointer temp;
while (*ptr) {
temp = *ptr;
*ptr = (*ptr)->link;
free(temp);
}
}
Q. 시간 복잡도 ?
21
다항식:원형 연결리스트 표현
 단순 연결 리스트
 체인(chain)
ptr
3 14
2
8
1
0 null
3 14
2
8
1
0
 원형 리스트
ptr
available space list
 더 이상 필요 없는 노드는 체인으로 유지
 새 노드가 필요하면 available space list에서 하나를 가져
옴
22
 malloc대신 get_node, free대신 ret_node
다항식:원형 연결리스트 표현(계속)
poly_pointer get_node(void) {
void ret_node(poly_pointer ptr) {
/* 사용할 노드를 제공 */
/* 가용 리스트에 노드를 반환 */
poly_pointer node;
ptr->link = avail;
if (avail) {
avail = ptr;
node = avail;
}
avail = avail->link;
}
else {
node = (poly_pointer) malloc(sizeof(poly_node));
if (IS_FULL(node)) {
fprintf(stderr, "The memory is full");
exit(1);
}
}
return node;
}
23
다항식:원형 연결리스트 표현(계속)
원형 리스트의 제거
void cerase(poly_pointer *ptr) {
/* 원형 리스트 ptr을 제거 */
poly_pointer temp;
if (*ptr) {
temp = (*ptr)->link;
(*ptr)->link = avail;
avail = temp;
ptr
*ptr = NULL;
}
}
avail
Q. 시간 복잡도 ?
...
...
null
24
다항식:원형 연결리스트 표현(계속)
모든 다항식의 앞에 헤드 노드
 함수 cerase에서 제로 다항식 검사가 불필요
 헤드 노드의 expon을 -1로 하면 함수 padd에서 마
지막 2개의 for loop가 불필요
ptr
-
-1
ptr
-
-1
3 14
2
8
1
0
25
다항식:원형 연결리스트 표현(계속)
poly_pointer cpadd(poly_pointer a, poly_pointer b) {
poly_pointer starta, d, lastd; int sum, done = FALSE;
starta = a;
/* a의 시작을 기록 */
a = a->link; b = b->link;
/* a와 b의 헤드 노드를 건너 뜀 */
d = get_node();
/* 합산용 헤드 노드를 가져 옴 */
d->expon = -1; lastd = d;
do {
switch (COMPARE(a->expon, b->expon)) {
case -1: attach(b->coef,b->expon,&lastd); b = b->link; break;
case 0 : if (starta == a) done = TRUE;
else {
sum = a->coef + b->coef; if (sum) attach(sum,aexpon,&lastd);
a = a->link; b = b->link;
}
break;
case 1 : attach(a->coef,a->expon,&lastd); a = a->link;
}
} while (!done);
26
lastd->link =d;
return d;
체인 연산
체인의 역순화
list_pointer invert(list_pointer lead) {
list_pointer middle, trail;
middle = NULL;
lead
while (lead) {
middle=
trail = middle;
NULL
middle = lead;
middle
lead = lead->link;
trail =
null
middle->link = trail;
NULL
}
trail
return middle;
} Q. 시간 복잡도 ?
null
null
lead
null
middle
lead
null
27
체인 연산(계속)
두 체인의 연결
list_pointer concatenate(list_pointer ptr1, list_pointer ptr2)
{
/* 리스트 ptr1 뒤에 리스트 ptr2가 접합된 새로운 리스트를
생성한다. ptr1이 가리키는 리스트는 영구히 바뀐다.*/
list_pointer temp;
if (IS_EMPTY(ptr1)) return ptr2;
else {
if (!IS_EMPTY(ptr2)) {
for (temp = ptr1; temp->link; temp = temp->link) ;
temp->link = ptr2;
}
return ptr1;
}
28
} Q. 시간 복잡도 ?
희소 행렬
각 열과 각 행을 원형 연결 리스트로 표현
헤드 노드
down head right
행 리스트
next
열 리스트
헤드 노드
엔트리 노드
tag
down entry row col right
같은 행에
value
같은 열에서 0이 아닌 다음
항
서 0이 아
닌 다음
항
 헤드 노드의 총수 = max{행수, 열수}
∵ i행과 i열에 대한 헤드 노드는 동일
 헤드 노드 리스트의 헤드 노드: 엔트리 노드의 구조와 같
음 (단, row, col은 행렬의 크기 저장)
 총 노드 수
• max{num_rows,num_cols}+num_terms+1
29
희소 행렬(계속)
희소 행렬 표현의 C 선언 : union 사용
#define MAX_SIZE 50 /* 최대 행렬 크기 */
typedef enum {head,entry} tagfield;
typedef struct matrix_node *matrix_pointer;
typedef struct entry_node { int row; int col; int value;};
typedef struct matrix_node {
matrix_pointer down;
matrix_pointer right;
tagfield tag;
union {
matrix_pointer next;
entry_node entry;
}u;
};
30
matrix_pointer hdnode[MAX_SIZE];
이중 연결 리스트
단순 연결 리스트의 제한 : 이동이 한 방향
예) 삭제 시 전위 노드를 알아야 함
이중 연결 리스트
 포인터를 양 방향으로 이동
 노드 구조
typedef struct node *node_pointer;
typedef struct node {
node_pointer llink;
element item;
node_pointer rlink;
};
 원형/체인
 ptr = ptr->llink->rlink = ptr->rlink->llink
31
이중 연결 리스트(계속)
헤드 노드를 가진 이중 연결 원형 리스트
ptr
헤드 노드
llink item rlink
32
이중 연결 리스트(계속)
이중 연결 리스트의 삽입
void dinsert(node_pointer node, node_pointer newnode) {
/* newnode를 node의 오른쪽에 삽입 */
newnode->llink = node;
newnode->rlink = node->rlink;
node->rlink->llink = newnode;
node->rlink = newnode;
}
node
node
2
newnode
1
1
2
33
이중 연결 리스트(계속)
이중 연결 리스트의 삭제
void ddelete(node_pointer node, node_pointer deleted) {
if (node == deleted) printf(“deletion of head node not
permitted.");
else {
deleted->llink->rlink = deleted->rlink;
deleted->rlink->llink = deleted->link;
free(deleted);
node
node
}
}
1
2
deleted
1
34