1 / 102

C 중급

C 중급. 3. 자료구조. 배열 , 행렬 , 레코드. 연접리스트. 연결 리스트. 단순 , 이중 , 원형 , 복합 연결 리스트. 선형 구조. 스택. 큐. 출력제한 , 입력제한 데크. 테크. 자료구조. 일반 트리 , 이진 트리. 트리. 비선형 구조. 그래프. 방향 그래프 , 무방향 그래프. 직접 파일. 파일 구조. 순차 파일. 색인 순차 파일. 3.1 자료구조란. 다루고자 하는 자료 항목들간의 관계를 기술하는 것이다. 3.2 선형 자료 구조.

bonnie
Download Presentation

C 중급

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. C 중급

  2. 3. 자료구조

  3. 배열, 행렬, 레코드 연접리스트 연결 리스트 단순, 이중, 원형, 복합 연결 리스트 선형 구조 스택 큐 출력제한, 입력제한 데크 테크 자료구조 일반 트리, 이진 트리 트리 비선형 구조 그래프 방향 그래프, 무방향 그래프 직접 파일 파일 구조 순차 파일 색인 순차 파일 3.1 자료구조란 • 다루고자 하는 자료 항목들간의 관계를 기술하는 것이다.

  4. 3.2 선형 자료 구조 • 1. 자료구조는 실제적으로 리스트의 한 형태인데 저장구조의 차이점 때문에 리스트를 다양한 형태로 나누고 있다. • 2. 자료구조를 리스트로 취급하는 이유는 기억매체의 접근이 1차원이라는 데 있다. • 3. 모든 항목들이 일 대 일의 관계를 가지는 리스트를 선형 리스트라 한다. 이러한 선형 리스트에는 순차(연접)리스트와 연결 리스트의 2 가지 종류가 있다. • 순차리스트 • 연속적으로 저장되는 고정된 갯 수의 데이터 item • index에 의해 접근 가능 • 배열 • 연결리스트 • 동적으로 item을 삽입하거나 삭제하는 것이 가능 • 각item들을 효율적으로 재배치하는 것이 가능 • 단순 연결리스트, 원형 연결리스트, 이중 연결리스트, 복합 연결리스트 • 스택, 큐,데크

  5. L 1 2 3 I I+1 B 3.2.1 연접리스트 • 연접리스트(dense list) • 기억 장소에 연속적으로 저장되는 리스트를 의미한다. • 첫 번째 원소의 위치를 B, 원소의 길이를 L이라고 가정한다면, • 두 번째 원소의 위치는 B+L, • 세 번째 원소의 위치는 B+2L 이 된다. • I번째 원소가 시작되는 저장 장소의 위치는 다음과 같다 • I번째 원소의 저장 장소의 위치 = B+(I-1)L

  6. 3.2.2 연결 리스트 • 연접리스트 • 연접리스트의 장점 • 간단한 구조 • 구현하기가 간단하다. • 연접리스트의 단점 • 삽입과 삭제 작업이 발생할 경우 많은 양의 자료가 이동해야 하는 문제점이 있다. • 연결 리스트 • 이러한 문제를 해결하기 위해 각 노드에 다음 노드를 가리키는 포인터를 둔다. • 리스트내의 모든 노드가 다음 노드의 위치를 지적하기 위한 포인터를 갖는다. • 이러한 리스트를 연결 리스트(linked list)라고 한다. • 연결 리스트 구조를 표현 • 각 노드는 자료 필드(data field)와 연결 필드(link field)가 필요하게 된다. • 노드의 구조는 다음과 같다.

  7. A B C 3.2.2 연결 리스트 데이터 링크 포인터 D ^ • 연결 리스트의 장,단점 • 장점 • 노드의 삽입, 삭제가 용이하다. • 링크 필드의 주소 변경만으로 작업이 가능 • 연속적으로 기억 공간이 없어도 저장이 가능 • 단점 • 연접 리스트나 배열보다 기억 공간이 많이 필요하다. • 알고리즘 구현이 복잡하다. • 특정 노드 검색 시 무한 루프(infinite loop)에 빠질 수 있다.

  8. ... NULL NULL ... start 3.2.3 연결 리스트의 종류 단순 연결리스트 NULL ... start 원형 연결리스트 이중 연결리스트

  9. 3.2.4 단순 연결 리스트 • 단순 연결 리스트의 특징 • 1. 리스트에 삽입과 삭제가 용이하게 수행될 수 있다. • 2. 하나의 노드를 데이터 필드와 링크 필드로 나눈다. • 3. 링크 필드에 다음 노드를 가리키는 포인터를 저장한다. • 4. 마지막 노드의 링크 필드는 널(NULL)로 저장하는 자료 구조이다. • 5. 포인터의 특수한 형태인 NULL포인터는 아무런 항목도 가리키지 않는다는 의미이며, 마지막 노드를 인지하는 포인터의 변수이다. • 6.자료 구조의 검색은 한쪽 방향으로만 진행된다.

  10. 3.2.4 단순 연결 리스트 • 단순 연결리스트의 구조 • 1. 단순 연결 리스트는 가장 기본적인 연결 리스트 구조이다. • 2. 단순 연결 리스트의 노드는 데이터 값(value)을 저장하는 부분과 다음 노드를 가리키는 포인터로 이루어져 있다. • 3 여러 개의 노드들이 연결되어 단순 연결 리스트가 만들어진다. • 4.연결 리스트의 시작점은 임의의 포인터가 가리키고 있으며, 그 포인터로부터 연결 리스트의 각 노드를 참조할 수 있다. • 5. 연결 리스트의 시작점을 가리키는 포인터가 그 리스트의 이름이 된다.

  11. 3.2.4 단순 연결 리스트 • 단순 연결 리스트의 장단점 • 장점 • 구조가 간단하다 • 기억장소의 소모가 적다 • 단점 • 역 방향으로 리스트를 탐색할 수 없기 때문에 노드를 삽입하거나 삭제하려면 별도의 포인터가 필요하다. • 문제해결  이중 연결리스트를 사용

  12. 3.2.4 단순 연결 리스트 • 단순 연결 리스트의 동작 • 단순 연결 리스트에 노드 삽입(insert) • start 포인터: • 노드를 삽입하려는 연결리스트의 시작점을 가리킨다. • current 포인터: • 현재 참조중인 노드 • new 포인터: • 새로 삽입할 노드를 가리킨다. ... NULL start current new

  13. 3.2.4 단순 연결 리스트 • Insert • 현재 참조중인 노드가 연결 리스트의 중간 노드인 경우 • 1."new" 노드의 포인터는 "current"노드의 포인터가 가리키는 노드를 가리키도록 한다. • 2."current" 노드의 포인터는 "new" 노드를 가리키도록 한다. • 3.순서를 지키는 것이 중요하다. new ... NULL start current

  14. NULL 3.2.4 단순 연결 리스트 • Insert • 현재 참조중인 노드가 연결 리스트의 마지막 노드인 경우 • current 노드의 포인터가 새로운 노드를 가리키도록 해주면 된다. NULL new ... start current

  15. 3.2.4 단순 연결 리스트 • Delete • 현재 참조중인 노드가 연결 리스트의 처음 노드인 경우 • start = start->next; • free(current); ... NULL start start current

  16. 3.2.4 단순 연결 리스트 • Delete • 현재 참조중인 노드가 연결 리스트의 중간 노드인 경우 • new->next = current->next; • free(current); ... NULL start new current

  17. 3.2.4 단순 연결 리스트 • Delete • 현재 참조중인 노드가 연결 리스트의 마지막 노드인 경우 • new->next = current->next; • free(current); ... NULL start new current

  18. 3.2.4 단순 연결 리스트 #include <stdio.h> #include <malloc.h> #include <conio.h> #include <string.h> typedef struct record { char name[20]; int birth; struct record* next; } *LINK; void list_record(); void insert(char*, int); int del(char*); LINK start; void list_record() { LINK current; printf("\nstart = 0x%5x\n", start); for(current = start; current; current = current->next) printf("0x%5x %-20s 0x%5x\n", current, current->name, current->next); }

  19. 3.2.4 단순 연결 리스트 void insert(char*name, int year) { LINK newone, current; newone = (LINK) malloc(sizeof(struct record)); strcpy(newone->name, name); newone->birth = year; newone->next = NULL; if(start) { for(current = start; current->next; current = current->next) ; current->next = newone; } else start = newone; }

  20. 3.2.4 단순 연결 리스트 int del(char* name) { LINK current, help; if(!start) return -1; for(help = current = start; current; current = current->next) { if(strcmp(current->name, name) == 0) { if(current == start) start = current->next; else help->next = current->next; free(current); return 0; } help = current; } return -1; }

  21. 3.2.4 단순 연결 리스트 void main() { start = NULL; insert("KIM", 1996); insert("LEE", 1961); insert("BAE", 1962); insert("HWANG", 1963); insert("OH", 1964); puts("listing !\n"); list_record(); del("LEE"); list_record(); del("KIM"); list_record(); del("HWANG"); list_record(); insert("RYU", 1961); list_record(); insert("JUNG", 1996); list_record(); del("OH"); list_record(); insert("MYUNG", 1965); list_record(); insert("KONG", 1960); list_record(); getch(); }

  22. ... 3.2.5 원형 연결 리스트 • 원형 연결리스트는 연결 리스트의 마지막 노드의 링크 필드 값이 널 링크가 아닌 첫번째 노드주소를 갖는 구조이다. • 원형 연결리스트 이용 시 한 노드에서 모든 노드로의 접근이 가능하고, 삽입과 삭제연산이 편리한 장점이 있으나, 특정 노드 검색 시 무한 루프에 빠질 가능성이 있다. • 따라서 검색을 끝낼 수 있는 노드가 존재하여야 한다. • 이를 위해 헤드(head)를 두는 것도 한 방법이 될 수 있다.

  23. 3.2.5 원형 연결 리스트 #include <stdio.h> #include <malloc.h> typedef struct node { int key; struct node* next; }*LINK; void main() { int i,N,M; LINK start, current, help; scanf("%d %d", &N, &M); start = current = (LINK) malloc(sizeof(struct node)); current->key = 1; for(i = 2; i <= N; i++) { current->next = (LINK) malloc(sizeof(struct node)); current = current->next; current->key = i; } current->next = start;

  24. 3.2.5 원형 연결 리스트 while(current->next != current) { for(i=1; i<M; i++) { printf("0x%5x %d 0x%5x\n", current, current->key, current->next); current = current->next; } printf("%d %d\n\n", current->key, current->next->key); help = current->next; free(help); for(i=1; i<M; i++) { printf("0x%5x %d 0x%5x\n", current, current->key, current->next); current = current->next; } } printf("%d\n", current->key); }

  25. 3.2.6 스택 • 스택의 정의 • 1. 여러 개의 데이타 항목들이 일정한 순서로 나열된 자료 구조 • 2. 한쪽 끝에서만 새로운 항목을 삽입하거나 기존 항목을 삭제할 수 있도록 고안 • 3. 선형 리스트의 특별한 경우로서 TOP 이라는 자료 구조의 끝에서 자료의 삽입과 삭제가 발생하는 자료 구조이다. • 스택의 원리 • 1. 스택은 동전을 넣고 뺄 수 있도록 되어 있는 동전 케이스와 같은 작동 원리 • 스택의 성격 • 2. 후입 선출 리스트(Last- In-First-Out List) : 스택에 저장된 데이타 항목들 중에 먼저 삽입된 것은 나중에 삭제되고, 나중에 삽입된 것이 먼저 삭제된다.

  26. 3.2.6 스텍 • 스택의 구조 • 1. 스택은 base로부터 데이타 항목들을 차례로 쌓아올린 모양을 가진다. • 2. 삽입과 삭제는 현재 저장된 최상위 항목이 위치한 top에서만 일어난다. • 3. top 위치는 "스택 포인터"라는 지시자가 가리킨다. • 4. 스택 포인터는 스택 기저에서 시작하여 항목이 삽입되면 하나 증가하고, 삭제되면 하나 감소한다. • 5. 스택에는 한계가 있어서 그 한계를 초과하여 삽입할 수 없다.

  27. 삭제순서: D,C,B,A 삽입순서: A, B, C, D index index 4 4 D 3 3 C 2 2 B 1 1 A 삭제 삽입 3.2.6 스텍 • 그림과 같이 삽입을 한 상태에서 D가 제거되면 top은 3이 되고, C가 제거되면 top은 2가 되며,B가 제거 되면 top은 1이 된다. 마지막 A가 제거되면 top은 0이 된다.

  28. 3.2.6 스텍 • 스택의 입출력 • 삽입(push) Full 검사 • 삭제(pop) Empty 검사 • 1. 스택에 데이타 항목 삽입 (push) • 데이타 항목을 삽입하려면 스택 포인터를 하나만큼 증가시켜 주고 스택의 top 에 데이타 항목을 저장한다. 데이타 항목을 삽입하기 전에 새로운 항목을 저장할 빈 공간이 있는지 검사(full 검사)해야 한다. • stack[++top] = 데이터; • 2. 스택에서 데이타 항목 삭제 (pop) • 데이타 항목을 삭제하려면 스택의 top 에 있는 데이타 항목을 제거하고 스택 포인터를 하나만큼 감소시켜 준다. 데이타 항목을 삭제하기 전에 스택이 비어있는지를 검사 • (empty 검사 )해야 한다. • return stack[top--];

  29. 삭제순서: D,C,B,A 삽입순서: A, B, C, D index index 4 4 D 3 3 C 2 2 B 1 1 A 삭제 삽입 3.2.6 스텍 • 그림과 같이 삽입을 한 상태에서 D가 제거되면 top은 3이 되고, C가 제거되면 top은 2가 되며,B가 제거 되면 top은 1이 된다. 마지막 A가 제거되면 top은 0이 된다.

  30. 3.2.6 스텍 /*STACK : array version */ #include <stdio.h> #define MAX 5 int stack[MAX]; int top; void init_stack(void) { top = -1; } int push(int t) { if(top >= MAX-1) { printf("Stack overflow.\n"); return -1; } stack[++top] = t; return t; }

  31. 3.2.6 스텍 int pop(void) { if(top < 0) { printf("Stack underflow.\n"); return -1; } return stack[top--]; } void print_stack(void) { int i; printf("Stack contents: Top ---> Bottom\n"); if(top == -1) printf("[Stack empty]\n"); for(i = top; i >= 0; i--) { printf("%d", stack[i]); } printf("\n"); }

  32. 3.2.6 스텍 void main() { int i; init_stack(); printf("\nPush 3,2,5,7,2\n"); push(3); push(2); push(5); push(7); push(2); print_stack(); printf("\nNow statck is full, push 3\n"); push(3); print_stack(); printf("\nInitailize stack\n"); init_stack(); print_stack(); printf("\nNow stack is empty, pop\n"); i = pop(); printf("popping value is %d\n", i); print_stack(); }

  33. 3.2.6 스텍 // 링크드 리스트를 이용한 스텍 #include "stdio.h" #include "malloc.h" typedef struct struct_node { char key; struct_node* next; }node; node *head, *tail; void init_stack(void) { head = (node*)malloc(sizeof(node)); tail = (node*)malloc(sizeof(node)); head->next = tail; tail->next = tail; }

  34. 3.2.6 스텍 void clear_stack(void) { node *t, *s; t = head->next; while(t != tail) { s = t; t = t->next; free(s); } head->next = tail; } int push(char k) { node *t; if((t = (node*)malloc(sizeof(node))) == NULL) { printf("\n Out of memory..."); return -1; } t->key = k; t->next = head->next; head->next = t; return k; }

  35. 3.2.6 스텍 char pop(void) { node* t; char i; if(head->next == tail) { printf("\n Stack underflow."); return -1; } t = head->next; i= t->key; head->next = t->next; free(t); return i; }

  36. 3.2.6 스텍 void print_stack(void) { node* t; t = head->next; printf("\n Stack contents: Top---->Bottom\n"); while(t != tail) { printf("%-6d", t->key); t = t->next; } } void main(void) { int i; init_stack(); printf("\nPush 5,4,7,8,2,1"); push(5); push(4); push(7); push(8); push(2); push(1);

  37. 3.2.6 스텍 print_stack(); printf("\nPop"); i = pop(); print_stack(); printf("\n popping value is %d", i); printf("\nPush 3,2,5,7,2"); push(3); push(2); push(5); push(7); push(2); print_stack(); printf("\nInitailize stack"); clear_stack(); print_stack(); printf("\nNow stack is empty. pop"); i = pop(); print_stack(); printf("\n popping value is %d", i); }

  38. 3.2.7 큐(Queue) • 큐의 정의 • 1. 여러 개의 데이타 항목들이 일정한 순서로 나열된 자료 구조 • 2. 한쪽 끝에서 삽입, 삭제할 수 있도록 되어 있다. • 3. 스택에서 자료의 삽입/삭제는 top이라는 스택 포인터에서 이루어지는데 반해 큐의 제거는 앞에서, 삽입은 뒤에서 발생되도록 제한된다. -> 선입 선출(FIFO) • 큐의 원리 • 1. 큐는 매표소에서 표를 사기 위해 기다리는 대기자 열과 같은 원리 • 2. 대기자 열에는 먼저 온 사람부터 차례로 대기자들이 늘어서 있다. 앞쪽 끝에서는 기다리던 사람이 표를 사서 빠져나가고 (삭제), 뒤쪽 끝에서는 새로운 사람들이 대기자 열로 들어온다(삽입). • 큐의 성격 • 1. 선입 선출 리스트 (First-In-First-Out:FIFO) : • 큐에 저장된 데이타 항목들 중에 먼저 삽입된 것은 먼저 삭제되고, 나중에 삽입된 것은 나중에 삭제된다.

  39. 3.2.7 큐(Queue) • 큐의 종류 • 1. 선형 큐(linear queue) : 한 방향으로 데이타 항목들이 삽입/삭제 • 2.원형 큐(circular queue) : 시작점과 끝점이 서로 연결

  40. 삽입순서: A, B, C, D 삭제순서: A, B, C, D A B C D front rear front rear 3.2.7 선형 큐(Queue) • 큐는 운영체제에서 수행할 작업들을 스케줄링 할 때 자주 이용되는데, 큐 동작을 이해하기 위해 5개의 작업이 큐에서 운영되는 예를 표로 만들면 다음 페이지와 같다. • 이때 주의할 점은 큐의 공백(empty) 상태를 구분하기 위해 front는 큐의 실제 앞(front)보다 1이 작은 위치를 가리키게 하고, rear는 큐에 마지막으로 삽입된 원소를 가리키게 한다는 점이다.

  41. Q(1) Q(2) Q(3) Q(4) Q(5) … front rear 0 0 Queue Empty 초기조건 0 1 J1 큐에 Job1 입력 0 2 J1 J2 큐에 Job2 입력 0 3 J1 J2 J3 큐에 Job3 입력 1 3 J2 J3 큐에 Job1 출력 1 4 J2 J3 J4 큐에 Job4 입력 2 4 J3 J4 큐에 Job2 출력 2 5 J3 J4 J5 큐에 Job5 입력 3.2.7 선형 큐(Queue)

  42. 3.2.7 선형 큐(Queue) • 선형 큐 • 1. 선형 큐의 구조 (Queue1) • rear : 새로운 데이터 항목의 삽입 • front : 기존 데이터 항목의 삭제 • 2. front 포인터와 rear 포인터는 초기에 하한에서 시작하여 삽입과 삭제가 반복됨에 따라 상한쪽으로 이동한다 • 선형 큐의 동작 • 1. 선형 큐에 데이타 항목 삽입 • (full 검사 : front 포인터 = rear 포인터) • rear 포인터를 하나만큼 증가시켜 주고 그 위치에 데이타 항목을 저장한다. • 2. 선형 큐에서 데이타 항목 삭제 • (empty 검사 : front 포인터 = rear 포인터) • 큐의 front 포인터를 하나만큼 증가시키고 그 위치에 있는 데이타 항목을 삭제한다.

  43. 3.2.7 선형 큐(Queue) 큐의 삽입과 삭제

  44. 3.2.7 선형 큐(Queue) #include <stdio.h> #define MAX 10 int queue[MAX]; int front, rear; void init_queue(void) { front = rear = 0; } void clear_queue(void) { front = rear; }

  45. 3.2.7 선형 큐(Queue) int put(int k) { if((rear + 1) % MAX == front) { printf("\n Queue overflow."); return -1; } queue[rear] = k; rear = ++rear % MAX; return k; } int get(void) { int i; if(front == rear) { printf("\n Queue underflow."); return -1; } i = queue[front]; front = ++front % MAX; return i; }

  46. 3.2.7 선형 큐(Queue) void print_queue(void) { int i; printf("\n Queue contents: Front ---> Rear\n"); for(i = front; i != rear; i = ++i % MAX) printf("%-6d", queue[i]); } void main(void) { int i; init_queue(); printf("\nPut 5,4,7,8,2,1"); put(5); put(4); put(7); put(8); put(2); put(1); print_queue(); printf("\nGet"); i=get();

  47. 3.2.7 선형 큐(Queue) print_queue(); printf("\n getting value is %d", i); printf("\nPut 3,2,5,7"); put(3); put(2); put(5); put(7); print_queue(); printf("\nNow queue is full, put 3"); put(3); print_queue(); printf("\nInitialize queue"); clear_queue(); print_queue(); printf("\nNow queue is empty, get"); i = get(); print_queue(); printf("\n getting value is %d", i); }

  48. 3.2.7 원형 큐(Queue) • 원형 큐 • 원형 큐는 선형 큐의 문제점을 보완하기 위해 만들어진 자료구조 • 앞의 표에서 큐의 크기가 5라고 가정하고, front가 2이고 rear가 5인 마지막 상태에서 새로운 작업 J6을 큐에 입력할 경우 FULL이 발생되어 더 이상 입력할 수 없다. • 그러나 앞의 표를 보면 큐의 마지막 상태는 Q(1)과 Q(2)가 비어 있어서 자료를 더 입력 할 여분의 공간이 있다. 이러한 유효 공간을 활용하기 위한 방법으로 만들어진 것이 원형 큐이다.

  49. Q(5) Q(5) … … Q(4) Q(4) D Q(n-4) Q(n-4) C Q(3) Q(3) A Q(n-3) Q(n-3) B B Q(2) Q(2) A C Q(n-2) Q(n-2) D Q(1) Q(1) Q(n-1) Q(n-1) Q(0) Q(0) front = 0 rear = 4 3.2.7 원형 큐(Queue) • 아래 그림에서 데이터 A, B, C, D가 원형 큐에 입력될 때 처음 입력된 데이터가 Q(1)에 들어가고 이때 front는 0이 된다. • Q()는 공백 조건을 위해 존재하는 것이기 때문에 n개의 원소가 아닌 (n-1)개의 원소만이 Q(1: n-1)에 저장될 수 있다. 결국 큐 내의 기억장소 하나를 손실하고 알고리즘의 수행속도를 개선시키는 효과가 있다. front = n-4 rear = 0

  50. 3.2.7 원형 큐(Queue) • 지금까지 설명한 원형 큐를 표현하기 위한 조건을 요약하면 다음과 같다. • 포인터가 큐의 끝점에 있을 때 삽입이나 삭제가 일어나면 포인터가 reset 되어 다시 시작점을 가리킨다 • front: 큐에 첫번째 원소로부터 반시계 방향으로 하나 앞에 위치한다. • rear : 큐에 마지막으로 삽입된 원소를 가리킨다. • 공백 조건: front = rear • FULL 조건: front = rear empty full

More Related