380 likes | 654 Views
5 장 . 스택 (stack) 1 절 . 스택 2 절 . 배열을 이용한 스택 3 절 . 연결 리스트를 이용한 스택 4 절 . 스택응용 – 괄호검사 5 절 . 스택 응용 – 수식의 후위 표기식 변환 6 절 . 스택 응용 – 수식의 후위 표기식 계산. 이 완 직 ( wjlee@pnu.ac.kr ) 2010 년 1 학기. 1. 스택. 데이터를 삭제 (pop) 할 때에는 가장 최근에 삽입한 데이터를 꺼내는 구조
E N D
5장. 스택(stack) 1절. 스택 2절. 배열을 이용한 스택 3절. 연결 리스트를 이용한 스택 4절. 스택응용 – 괄호검사 5절. 스택 응용 – 수식의 후위 표기식 변환 6절. 스택 응용 – 수식의 후위 표기식 계산 이 완 직 (wjlee@pnu.ac.kr) 2010년 1학기
1. 스택 • 데이터를 삭제(pop)할 때에는 가장 최근에 삽입한 데이터를 꺼내는 구조 • 가장 최근에 들어온 데이터가 가장 먼저 나가기 때문에 후입선출(後入先出), LIFO(Last-In, First-Out: 라이포 리포), LCFS(Last-Come, First-Served)라고 한다.
1. 스택 • 스택의 연산
1. 스택 • Push 연산 • Pop 연산
2. 배열을 이용한 스택 • 최대 MAX_STACK_SIZE개의 원소를 저장할 수 있는 스택을 1차원 배열로 선언 char stack[MAX_STACK_SIZE]; //스택에 원소를 저장하기 위한 배열 int top = -1 //스택 초기화 int isEmpty() { return (top == -1); }
void push(StackObject item) { //스택이 가득 차 있는지를 확인한다 if( isFull() ) { printf("stack is full, can not add element.\n"); } else { //TOP 인덱스를 증가한 후 현재 TOP에 원소 삽입 stack[++top] = item; } } 2. 배열을 이용한 스택 int isFull() { return (top == (MAX_STACK_SIZE-1)); }
StackObject pop() { //스택이 비어 있는지 확인한다 if( isEmpty() ) { printf("stack is empty\n"); } else { //현재 TOP에서 원소를 삭제한 후 TOP 인덱스를 감소시킨다 return stack[top--]; } } 2. 배열을 이용한 스택
3. 연결 리스트를 이용한 스택 • 스택의 top을 표현하기 위해서 리스트의 헤드(head) 포인터를 스택의 top포인터로 정의한다.
3. 연결 리스트를 이용한 스택 • 스택의 push 및 pop 과정
3. 연결 리스트를 이용한 스택 • 스택을 구현하기 위한 정의 • typedef struct StackNode { • element data; • //다음 노드를 가리키는 포인터변수 • struct StackNode *link; • } StackNode; • push 함수 • void push(element item) • { • StackNode* temp=(StackNode *)malloc(sizeof(StackNode));//❶ • temp->data = item; • temp->link = top; //❷ • top = temp; //❸ • }
3. 연결 리스트를 이용한 스택 ❶ 우선 새로운 노드 공간을 확보해야 한다. ❷ 새로운 노드가 현재 상태의 첫 노드를 가리키게 한다. ❸ top이 새로운 노드를 가리키게 한다.
3. 연결 리스트를 이용한 스택 • pop 함수 구현 • element pop() • { • element item; • StackNode* temp=top; //❶ • if(top == NULL) { //스택이 비어 있으면 • printf(“\n\n Stack is empty !\n”); • return 0; • } • else { • item = temp->data; • top = temp->link; //❷ • free(temp); //❸ • return item; • } • }
3. 연결 리스트를 이용한 스택 ❶ top 포인터를 temp에 백업해둔다 ❷ top이 다음 노드를 가리키게 한다. ❸ 이전 top 노드의 공간을 반납한다. 반납 후에 이전 top 데이터를 리턴해야 하므로 top 데이터를 미리 복사해놓는다.
4. 스택 응용 – 괄호 검사 • 수식은 연산자(Operator)와 피연산자(Operand)로 구성 • 수식의 예 연산자 X = A / B - C 피연산자 • 수식에서 연산자의 우선 순위 • 단항 – (unary minus), ! • *, /, % • +, - • 프로그래머는 괄호를 사용하여 연산자의 우선 순위를 변경할 수 있다. • 예) X = (A/(B-C))
4. 스택 응용 – 괄호 검사 • 수식의 괄호 검사 응용 • 괄호 (중괄호([,]) 대괄호({,}) 포함) 검사의 규칙 • 수식의 괄호 검사에 스택을 이용 • 괄호는 가까운 것끼리 쌍을 이룸, 즉마지막의 열린(왼쪽) 괄호를 가장 먼저 닫아야 함 • 왼쪽 괄호들을 만나면 스택에 push • 오른쪽 괄호를 만나면 스택에서 pop한 괄호와 쌍을 맞추어 봄 ❶ 왼쪽 괄호의 개수와 오른쪽 괄호의 개수가 같아야 한다. ❷ 같은 괄호에서 왼쪽 괄호는 오른쪽 괄호보다 먼저 나와야 한다. ❸ 괄호 사이에는 포함 관계만 존재한다.
4. 스택 응용 – 괄호 검사 • 괄호 검사 알고리즘 • 수식을 왼쪽에서 오른쪽으로 하나씩 읽으면서 괄호 검사 • 왼쪽 괄호를 만나면 • 스택에 push한다. • 오른쪽 괄호를 만나면 • 스택을 pop하여 현재 (오른쪽) 괄호와 비교한다. • 같은 종류가 아니면 오류! • 스택을 pop할 수 없으면(비워있으면), 오류! • 수식의 끝에 도달 • 스택이 비워 있지 않으면 오류! • 스택이 비워있으면 성공!
5. 스택 응용 – 수식의 후위 표기식 변환 • 수식을 표현하는 3 가지 방법 • 전위 표기식(prefix notation) • 연산자를 앞에 표기하고 그 뒤에 피연산자를 표기하는 방법 • +AB • 중위 표기식(infix notation) • 연산자를 피연산자의 가운데 표기하는 방법 • A+B • 후위 표기식(postfix notation) • 연산자를 피연산자 뒤에 표기하는 방법 • AB+
5. 스택 응용 – 수식의 후위 표기식 변환 • infix=> prefix 변환 ❶ 수식의 각 연산자에 대해서 우선순위에 따라 괄호를 사용하여 다시 표현한다. ❷ 각 연산자를 그에 대응하는 왼쪽 괄호의 앞으로 이동시킨다. ❸ 괄호를 제거한다.
5. 스택 응용 – 수식의 후위 표기식 변환 • infix=> postfix 표기식 변환 ❶ 수식의 각 연산자에 대해서 우선순위에 따라 괄호를 사용하여 다시 표현한다. ❷ 각 연산자를 그에 대응하는 오른쪽 괄호의 뒤로 이동시킨다. ❸ 괄호를 제거한다.
5. 스택 응용 – 수식의 후위 표기식 변환 • 컴퓨터에서 수식 계산을 위한 postfix notation으로 변환 • 괄호를 사용하지 않아도 된다(이미 연산자의 우선 순위가 고려). • 수식 계산이 용이하다(postfix에서 즉시 연산을 수행). • infix를 postfix로 변환하는 알고리즘 • 피연산자는 출력 • 연산자는 현재 연산자와 스택의 연산자를 비교 • 현재 연산자 순위가 높으면 => 현재 연산자를 스택에 push • 그렇지 않으면 => 스택의 연산자를 pop하여 출력 • 수식이 끝나면 • 스택의 모든 연산자를 pop하여 출력한다.
5. 스택 응용 – 수식의 후위 표기식 변환 a + b * c로부터 abc * + 를 생성하려면 다음과 같이 연산자를 스택에 저장해 두었다가 출력해야 한다. 피연산자를 만나면 출력한다.
5. 스택 응용 – 수식의 후위 표기식 변환 연산자는 스택에 저장해둔다. 피연산자를 만나면 출력한다.
5. 스택 응용 – 수식의 후위 표기식 변환 연산자를 만나면 이 시점에서 ‘*’를 스택에 push해야 할것인지, 아니면 ‘+’를 pop해서 출력할 것인 지를 결정하여야 한다. => ‘*’ 순위 > ‘+’ 순위 이므로 ‘*’ 를 스택에 저장한다. 피연산자를 만나면 출력한다.
5. 스택 응용 – 수식의 후위 표기식 변환 이제 입력 수식이 더 이상 없으므로 스택에 남아 있는 연산자들을 모두 출력하여 다음을 얻는다.
5. 스택 응용 – 수식의 후위 표기식 변환 • 괄호를 포함한 infix => postfix로 변환 • 변환 알고리즘 • 연산자/피연산자: 앞의 알고리즘과 동일 • 왼쪽 괄호: 무조건 스택에 push • 주의) 스택 내의 왼쪽 괄호: 가장 낮은 우선순위 연산자로 취급 • 오른쪽 괄호: • 스택 안의 왼쪽 괄호를 만날때 까지 • 스택 안의 연산자를 pop하여 출력 • 스택 안의 왼쪽 괄호를 만남 • 왼쪽 괄호와 현재의 오른쪽 괄호를 모두 제거(출력하지는 않음)
6. 스택 응용-수식의 후위 표기식 계산 • postfix에서 수식 계산 • postfix의 장점 때문에 컴퓨터의 수식 계산은 아래와 같은 두 단계로 수행 • infix=> postfix 변환 • postfix=> 수식 연산 • postfix에서 연산 수행 알고리즘 • 피연산자: 스택에 push • 연산자: 스택에서 두 개의 피연산자를 pop • operand2 = pop(statck); • operand1 = pop(statck); • [operand1 연산자 operand2] 계산 수행 • 결과를 다시 stack에 push • 수식 종료 • 스택에서 pop한 피연산자가 최종 연산 결과가 됨 • 이때 스택에 최종 결과를 제외한 다른 피연산자가 존재해서는 안된다. (수식 오류)