3.1 스택
삽입, 삭제가 top에서만 이루어진다.
LIFO(Last In First Out)
* 시스템 스택: 프로그램이 런타임에 함수 호출 시 사용
처음 top을 -1로 정해 빈 스택 확인
3.1.1 추상자료형
생성
삽입, isFull: 스택이 가득 찼는지 확인한 후 삽입
삭제, isEmpty: 스택이 비어있는지 확인 후 삭제
push(item);
item = pop();
3.2 동적 배열을 이용한 스택
위의 방식처럼 MAX_STACK_SIZE를 통해 스택을 생성하는 경우 최적의 크기를 알아야 한다는 결점 -> 동적 할당된 배열을 통해 해결
처음 스택의 크기를 1로 설정하여 배열 생성
스택이 가득 차있는 경우 realloc( )을 이용하여 기존 스택의 크기를 2배로 증가
: 시간 비용이 많이 드는 것처럼 보이지만 아니다!
=> 메모리 할당에 O(1), 스택 원소 복사에 O(1)의 시간 복잡도가 요구된다는 가정하에 O(스택_크기)의 시간 복잡도(스택 크기는 2의 멱수)
=> 2^k^의 원소에 대한 총 시간 복잡도 다음과 같다.
$$
{O(\sum\limits_{i=1}^{k}2^i)} = O(2^{k+1}) = O(2^k)
$$
3.3 큐
삽입과 삭제가 다른 끝에서 발생하는 리스트
삽입되는 끝: rear
삭제되는 끝: front
스택에서는 top만 이용하는 것과 달리 rear, front 2개의 변수 사용
* 작업 스케줄링: 우선순위를 사용하지 않는 OS에서 작업을 들어오는 순서대로 처리
3.3.1 추상자료형
생성
삽입, isFull: 큐가 가득 찼는지 확인 후 삽입
삭제, isEmpty: 큐가 비었는지 확인 후 삭제
rear가 MAX_QUEUE_SIZE-1가 됐을 때(큐가 가득 찼을 때), 전체 큐를 이동시켜 front가 -1이 되도록 이동 -> 비용 多
=> 원형 큐를 이용해 해결: (MAX_QUEUE_SIZE-1) + (1) = (0), (0) - (1) = (MAX_QUEUE_SIZE-1) : 모듈러 연산 이용
* 원형 큐의 문제점: 큐가 가득 차거나 비어있을 때 모두 rear == front, 구분 불가
=> 큐가 가득 차기 직전에 큐의 크기를 늘려서 rear == front인 상황이 비어있는 경우만 존재하도록 제한
3.4 동적 할당 배열을 이용한 원형 큐
realloc을 이용해 배열의 크기를 2배로 만들고 추가적인 작업 필요
[0] [1] [2] [3] [4] [5] C D E A B front = 3, rear = 2
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] C D E A B front = 3, rear = 2
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] C D E A B front = 9, rear = 2
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] A B C D E front = 11, rear = 4
- 새로운 큐 newQueue 생성
- 뒷부분에 해당하는 queue[front+1]부터 queue[capacity-1]까지를 newQueue[0]부터 newQueue[capacity-front-2]에 복사
- 앞부분에 해당하는 queue[0]부터 queue[rear]까지를 newQueue[capacity-front-1]부터 newQueue[capacity-front-1+rear]에 복사
3.5 미로 문제
3.6 수식 계산
3.6.1 수식
연산 순서를 결정하는 상위 계층 존재
안쪽 괄호 먼저 계산
C에서의 연산자 순서
- ->
( ): 함수 호출
[ ]: 배열
->, .: 구조체 또는 공용체 멤버
- ->
--, ++: 후위 연산자
- <-
--, ++: 전위 연산자
!: not
~: 보수
, +: 단항(부호)
&, *: 역참조, 참조
sizeof: 크기(바이트 단위)
- <-
(type): typecast
- ->
*, /. %: 곱
- ->
+, -: 합, 차
- ->
<<, >>: shift
- ->
>, =>, <, <=: 비교
- ->
==, !=: 등위
- ->
&: 비트연산자 and
- ->
^: 비트연산자 xor
- ->
|: 비트연산자 or
- ->
&&: 논리연산자 and
- ->
||: 논리연산자 or
- <-
?:: 조건연산자
- <-
=, +=, -=, /=, %=, <<=, >>=, &=, ^=, |=: 할당
- ->
,: 콤마
3.6.2 전위식
대부분의 컴파일러가 사용하는 수식
계산 시 왼쪽에서 오른쪽으로 스캔
연산자를 만날 때까지 스택에 피연산자 삽입
연산자를 만나면 스택에서 필요한 피연산자를 삭제 후 계산 결과를 삽입
* 입력받은 숫자가 ASCII 값이기 때문에 '0'을 빼서 원하는 값을 갖도록 한다. ex ) '1' - '0' = 1
** 호출되는 함수에서 case문을 사용 시 각 케이스에 return을 사용하면 break 불필요
3.6.3 중위식 -> 전위식
- 수식의 모든 계산에 괄호
- 연산자를 닫는 괄호로 이동
- 괄호 제거
스택을 이용한 수식 전환
괄호가 없는 식
피연산자는 즉시 출력
연산자를 만나면 top에 있는 연산자와 비교하여 우선순위가 낮을 때까지 pop한 후 push
수식의 끝에 도달했을 때 스택이 비어있지 않다면 모두 pop
괄호가 있는 식
위와 동일한 방식으로 진행하되 닫는 괄호가 나올 경우 여는 괄호까지의 연산자 pop
여는 괄호는
- 스택 내부에서의 우선순위(isp)는 가장 낮아야 하고 - 스택에 들어간 이후 다른 토큰이 스택에 들어갈 수 있기 때문
- 삽입 시 우선순위(icp)는 가장 높아야 한다. - 입력 시 반드시 스택에 들어가 위해
분석: O(n)
* 중위식 -> 후위식
- 입력된 문자열 뒤집기
- 뒤집어진 문자열을 전위식으로 정리
- 전위식 뒤집기
3.7 다중 스택과 큐
- m의 메모리에 n개의 스택을 사용하는 경우
공간을 n등분하여 boundary로 구분 (# of boundary = n+1)
- top[i] == boundary[i+1]: stackFull
- top[i] == boundary[i]: stackEmpty
- 다른 스택에 여유 공간이 있는데 꽉 찬 스택(i)에 삽입이 발생하는 경우
- 사용하지 않고, i < j < n을 만족하는 최소의 j를 찾아 i+1부터 j까지 오른쪽으로 한 스택씩 이동
- 1로 해결되지 않은 경우, 사용하지 않고, 0 <= j < i를 만족하는 최대의 i를 찾아 0부터 i까지 왼쪽으로 한 스택 씩 이동
- 2로 해결되지 않은 경우, stackFull
worst case: O(MEMORY_SIZE)
* 단어
- shortcomming 결점
- * This is not the case 사실이 아니다
- intriguing 흥미로운
- precedence 상위
- mnemonics 기억술
- auxiliary 보조적인
- empirically 경험적으로
- futile 쓸모없는
'독서(IT) > C 자료구조 원서' 카테고리의 다른 글
2장: 배열과 구조체 (0) | 2020.08.07 |
---|---|
1장: 기본 개념 (0) | 2020.03.17 |
Fundamentals of Data Structures in C 2/E (0) | 2020.03.10 |