1 / 27

자료 구조

자료 구조. 제 3 장 : 스택과 큐 이 형 원 강릉대학교 컴퓨터공학과. 학습 내용. 스택 ADT 큐 ADT 스택의 사용 예제 미로 문제 수식 계산 다중 스택과 큐. A. E D C B A. B A. C B A. D C B A. D C B A. top. top. top. top. top. top. 스택 (stack). 한쪽 끝 (top) 에서만 삽입 / 삭제가 되는 순서 리스트 Last-In-First-Out(LIFO)

ginny
Télécharger la présentation

자료 구조

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. 자료 구조 제 3 장 : 스택과 큐 이 형 원 강릉대학교 컴퓨터공학과

  2. 학습 내용 • 스택 ADT • 큐 ADT • 스택의 사용 예제 • 미로 문제 • 수식 계산 • 다중 스택과 큐

  3. A E D C B A B A C B A D C B A D C B A top top top top top top 스택(stack) • 한쪽 끝(top)에서만 삽입/삭제가 되는 순서 리스트 • Last-In-First-Out(LIFO) • 사용 예 : 시스템 스택

  4. 스택 ADT: structure Stack objects: 0개 이상의 원소를 가진 유한 순서 리스트 functions:stack∈Stack, item∈element, max_stack_size∈양정수 Stack CreateS(max_stack_size) ::= 최대 크기 max_stack_size인 공백 스택 생성Boolean IsFull(stack, max_stack_size) ::= if (stack의 원소수 == max_stack_size) return TRUE else return FALSEStack Add(stack, item) ::= if (IsFull(stack)) stack_full else stack top에 item을 삽입하고 returnBoolean IsEmpty(stack) ::= if (stack == CreateS(max_stack_size)) return TRUE else return FALSEElement Delete(stack) ::= if (IsEmpty(stack)) return else stack top의 item을 제거해서 반환

  5. 스택의 구현 Stack CreateS(max_stack_size) ::= #define MAX_STACK_SIZE 100 /*최대스택크기*/ typedef struct { int key; /* 다른 필드 */ } element; element stack[MAX_STACK_SIZE]; int top = -1;Boolean IsEmpty(Stack) ::= top < 0;Boolean IsFull(Stack) ::= top >= MAX_STACK_SIZE-1;void add(int *top, element item) { element delete(int *top) { if (*top >= MAX_STACK _SIZE-1) { if (*top == -1) stack_full(); return stack_empty(); return; return stack[(*top)--];} } } stack[++*top] = item;}

  6. A B A C B A D C B A D C B rear rear rear front front rear front front rear front 큐(queue) • 한쪽 끝(rear)에서 삽입, 반대쪽 끝(front)에서 삭제가 일어나는 순서 리스트 • First-In-First-Out(FIFO)

  7. 큐 ADT: structure Queue objects: 0개 이상의 원소를 가진 유한 순서 리스트 functions: queue∈Queue, item∈element, max_queue_size∈양 정수Queue CreateQ(max_queue_size) ::=최대 크기가 max_queue_size인 공백 큐를 생성Boolean IsFullQ(queue, max_queue_size ) ::= if (queue의 원소수 == max_queue_size) return TRUE else return FALSEQueue AddQ(queue,item) ::= if (IsFull(queue)) queue_full else queue 뒤에 item 삽입하고 반환Boolean IsEmptyQ(queue) ::= if (queue == CreateQ(max_queue_size)) return TRUE else return FALSEElement DeleteQ(queue) ::= if (IsEmpty(queue)) return else queue 앞에 있는 item을 제거해서 반환

  8. 큐의 구현: 순차 배열 Queue CreateQ(max_queue_size) ::= #define MAX_QUEUE_SIZE 100 /* 큐의 최대크기 */ typedef struct { int key; /* 다른 필드 */ } element; element queue[MAX_QUEUE_SIZE];int rear = -1; int front = -1;Boolean IsEmptyQ(queue) ::= front == rearBoolean IsFullQ(queue) ::= rear == MAX_QUEUE_SIZE-1void addq(int *rear, element item) { element deleteq(int *front, int rear) { if (*rear == MAX_QUEUE_SIZE-1) { if (*front == rear) queue_full(); return queue_empty(); return; return queue[++*front]; } } queue[++*rear] = item;}

  9. 큐의 구현: 순차 배열(계속) • 단점: rear = MAX_QUEUE_SIZE - 1이 되는 경우 • 전체 큐를 왼쪽으로 이동, front=-1, rear 조정 Q. 시간 복잡도 ? • 예제 [작업 스케쥴링] : O.S.에 의한 작업 큐의 생성 front rearQ[0] Q[1] Q[2] Q[3]설 명 -1 -1 공백큐 -1 0 J1 Job 1의 삽입 -1 1 J1 J2 Job 2의 삽입 -1 2 J1 J2 J3 Job 3의 삽입 0 2 J2 J3 Job 1의 삭제 1 2 J3 Job 2의 삭제

  10. 큐의 구현: 원형 배열 • 초기화: front = rear = 0 • 공백 큐: front = rear • 포화 큐: 원소 수 = MAX_QUEUE_SIZE-1 Q. Why ?

  11. 큐의 구현: 원형 배열(계속) void addq(int *front, int *rear, element item) {*rear = (*rear+1) % MAX_QUEUE_SIZE; if (front == *rear) { queue_full(rear); /* rear를 리세트시키고 에러를 프린트 */ return; } queue[*rear] = item;} void deleteq(int *front, int rear) { element item; /* queue의 front 원소를 삭제하여 그것을 item에 놓음 */ if (*front == rear) return queue_empty(); *front = (*front+1) % MAX_QUEUE_SIZE; return queue[*front];}

  12. 미로 문제 : 자료 구조 • m x p 미로: 2차원 배열 maze[m+2][p+2] • maze[row][col] = 0(path) or 1(no path) • 가장 자리는 모두 1 • 입구 maze[1][1], 출구 maze[m][p] • 이동 방향: 미리 정의된 이동 테이블 move[8] • 구조 typedef struct { short int vert;short int horiz; } offsets; offsets move[8];

  13. 미로 문제 : 자료 구조(계속) • move[8]의 내용 name dir move[dir].vert move[dir].horiz N 0 -1 0 NE 1 -1 1 E 2 0 1 SE 3 1 1 S 4 1 0 SW 5 1 -1 W 6 0 -1 NW 7 -1 -1 • 현 위치 maze[row][col] 이동 위치 maze[next_row][next_col] next_row = row + move[dir].vert next_col = col + move[dir].horiz

  14. 미로 문제 : 자료 구조(계속) • 시도한 경로의 재시도 방지: mark[m+2][p+2] • mark[row][col] = 1 /* 한번 방문한 경우 (지나간 경로)*/ • 경로의 탐색 현위치 저장 후 방향 선택 : N에서 시계방향 잘못된 경로의 선택 시는 backtracking후 다른 방향 시도 • 시도한 경로의 유지: 스택 element stack[MAX_SIZE]; #define MAX_SIZE 100 /* 스택의 최대 크기 */ typedef struct { Q. 스택 크기의 최대값 ? short int row; short int col; short int dir; } element;

  15. 미로 문제 : 초기 미로 알고리즘 initiallize a stack to the maze's entrance coordinates and direction to north;while (stack is not empty) { /* 스택의 톱에 있는 위치로 이동*/ <rol, col, dir> = delete from top of stack; while (there are more moves from current position) { <next_row, next_col> = coordinate of next move; dir = direction of move; if ((next_row == EXIT_ROW) && (exit_col == EXIT_COL)) success; if (maze[next_row][next_col] == 0) && mark[next_row][next_col] == 0){ /* 가능하지만 아직 이동해보지 않은 이동 방향 */ mark[next_row][next_col] = 1; /* 현재의 위치와 방향을 저장 */ add <row, col, dir> to the top of the stack; row = next_row; col = next_col; dir = north; } }}printf("No path found");

  16. 미로 문제 : 미로 탐색 함수 void path(void) {int i, row, col, next_row, next_col, dir, found=FALSE;element position; mark[1][1]=1; top=0;stack[0].row=1; stack[0].col=1; stack[0].dir=1;while (top>-1 && !found) { position=delete(&top); row=position.row; col=position.col; dir=position.dir; while (dir<8 && !found) { next_row = row + move[dir].vert; /* dir 방향으로 이동 */ next_col = col + move[dir].horiz; if (next_row==EXIT_ROW && next_col==EXIT_COL) found = TRUE; else if (!maze[next_row][next_col] && !mark[next_row][next_col]) { mark[next_row][next_col]) = 1; position.row = row; position.col = col; position.dir = ++dir; add(&top, position); row = next.row; col = next.col; dir = 0; } else ++dir; }} …… } Q. 복잡도 ?

  17. 수식의 계산 • C의 연산자 우선 순위 계층 토큰 우선순위 결합성 --, ++ 16 LR &, *, unary - + 15 RL *, /, % 13 LR +, - 12 L R >, >=, <, <= 10 LR ==, != 9 LR && 5 L R || 4 LR

  18. 수식의 계산(계속) • 수식의 표현 중위 (infix) 표기 후위 (postfix) 표기 전위 (prefix) 표기 a * b / c a b * c / / * a b c (1 + 2) * 7 1 2 + 7 * * + 1 2 7 • 후위 표기식의 장점 : 컴파일러(기계)에게 편리 • 괄호 및 연산자간의 우선 순위가 불필요 • 한 번만 수식을 scan하면서 스택을 이용하여 쉽게 계산  중위 표기식을 후위 표기식으로 변환 후 계산

  19. 후위 표기식의 계산 • algorithm (예 : 3.14) L-->R로 scan피연산자 : 스택에 삽입연산자 : 필요한 피연산자 수만큼 스택에서 가져옴 연산 수행 후 결과를 스택에 저장식의 끝 : 스택의 top에서 해답을 가져옴

  20. 후위 표기식 처리 함수 typedef enum {lparen,rparen,plus,minus,times,divide,mod,eos,operand} precedence;int stack[MAX_STACK_SIZE]; /* 전역 배열 */char expr[MAX_EXPR_SIZE]; /* 입력 스트링 */int eval(void) { precedence token; char symbol; int op1,op2, top=-1, n=0; token = get_token(&symbol, &n); while (token != eos) { if (token == operand) add(&top, symbol-'0'); / *스택 삽입 */ else { op2 = delete(&top); op1 = delete(&top); switch(token) { case plus : add(&top, op1+op2); break; case minus : add(&top, op1-op2); break; …… case mod : add(&top, op1%op2); } } token = get_token(&symbol, &n); } return delete(&top); /* 결과를 반환 */}

  21. 후위 표기식 처리 함수(계속) precedence get_token (char *symbol, int *n) {/* 다음 토큰을 취한다. symbol은 문자 표현이며, token은 그것의 열거된 값으로 표현되고, 명칭으로 반환된다. */*symbol = expr[(*n)++];switch (*symbol) { case '(' : return lparen; case ')' : return rparen; case '+' : return plus; case '-' : return minus; case '/' : return divide; case '*' : return times; case '%' : return mod; case ' ' : return eos; default : return operand; } }

  22. 중위 표기 후위 표기 • 수작업에 의한 중위->후위 변환 ① 식을 괄호로 묶음 ② 연산자를 오른쪽 괄호와 대치 ③ 괄호 삭제 • 예. 전위 표기 : a / b - c + d * e - a * c ((((a / b) - c) + (d * e)) - (a * c)) ((((a b) / c) - (d e) *) + (a c) *) - 후위 표기 : a b / c - d e * + a c * - ==> 컴퓨터 처리로는 비효율적 (∵ 2 pass가 필요 ) • How to infix to postfix in one pass ? • 피연산자들의 순서: 중위/후위 동일 scan하면서 바로 출력 가능 • 연산자 순서: 높은 우선 순위가 먼저 출력  스택을 이용

  23. 중위 표기 후위 표기(계속) • 중위  후위 변환의 핵심 1. token = 피연산자: 출력 2. token = ‘)’: (가 나올 때까지 스택의 연산자 출력 3. 우선순위(top) ≥ 우선순위(token): 스택의 연산자 출력 4. 우선순위(top) < 우선순위(token): 스택에 token 삽입 주의. ‘)’: 스택에 넣지 않음 ‘(‘ : 스택 밖에서는 가장 높은 우선 순위 but 스택 안에서는 가장 낮은 우선 순위Q. Why ?

  24. 중위 표기 후위 표기(계속) • 중위 표기식 a*(b+c)*d의 후위 표기식으로의 변환 토큰 스택 Output [0] [1] [2] a a * * a( * ( a b * ( ab + * ( + abc * ( + abc ) * abc+ * * abc+*d * abc+*d eos abc+*d*

  25. 중위 표기 후위 표기(계속) precedence stack[MAX_STACK_SIZE]; static int isp[] = {0, 19, 12, 12, 13, 13, 13, 0}; /* 연산자 ( ) + - * / % eos의 우선순위 값 */ static int icp[] = {20, 19, 12, 12, 13, 13, 13, 0}; void postfix(void) { char symbol; precedence token; int n = 0; int top = 0; stack[0] = eos; for (token==get_token(&symbol,&n); token!=eos; token==get_token(&symbol,&n)) { if (token == operand) printf("%c", symbol); else if (token == rparen) { while (stack[top] != lparen) print_token(delete(&top)); delete(&top); /* 좌괄호를 버린다 */ } else { /* symbol의 isptoken의 icp :symbol을 제거하고 출력 */ while (isp[stack[top]] >= icp[token]) print_token(delete(&top)); add(&top, token); } } while ((token=delete(&top)) != eos) print_token(token); printf(”\n");}

  26. 다중 스택 • 2 스택 : 각 스택의 최하단 원소를 양끝으로 • n (>2) 스택 • 이용 가능한 기억장소를 n개의 세그먼트로 분할 • 예상 크기를 아는 경우 : 크기에 따라 분할 • 예상 크기를 모르는 경우 : 똑같이 분할 • Memory[m]에서 n개 스택의 초기 구성 Top[0] Top[1] 0 1 m/n 2 m/n m-1 …. …. …. Boundary[1] Top[1] Boundary[2] Top[2] Boundary[n] Boundary[0] Top[0]

  27. 다중 스택 함수 #define MEMORY_SIZE 100 /* memory 크기 */#define MAX_STACKS 10 /* 가능한 스택의 최대수 + 1 */element memory[MEMORY_SIZE];int top[MAX_STACKS];int boundary[MAX_STACKS];void create(int n) { /* n :사용자가 입력한 스택의 수 */ top[0] = boundary[0] = -1; for (i = 1; i < n; i++) top[i] = boundary[i] = (MEMORY_SIZE/n) * i; boundary[n] = MEMORY_SIZE -1;}void add(int i, element item) { /* item을 i번째 스택에 삽입 */ if (top[i] == boundary[i+1]) stack_full(i); Q. How to implement ? memory[++top[i]] = item;} element delete(int i) { /* i번째 스택에서 top 원소를 제거 */ if (top[i] == boundary[i]) return stack_empty(i); return memory[top[i]--];}

More Related