큐는 데이터를 일시적으로 쌓아놓은 자료구조이다.
가장 먼저 넣은 데이터를 가장 먼저 꺼내는 선입선출인 점이 스택과 다름.
가장먼저 넣은 데티러르 가장 먼저 꺼내는 선입선출 구조로 되어있다.
큐의 예는 은행 창구에서 차례를 기다리는 대기열이나 마트에서 계산을 기다리는 대기열을 들 수 있다.
큐에 데이터를 넣는 작업을 인큐라 하고 데이터를 꺼내는 작업을 디큐라고 한다.
데이터를 꺼내는 쪽을 프런트(front)라 하고 데이터를 넣는 쪽을 리어(rear)라고 한다.
배열을 사용해 디큐를 하면서 모든 요소를 하나씩 앞쪽으로(shift) 옮기는 큐는
데이터를 꺼낼때 마다 O(n) 복잡도 이므로 이런 처리를 하면 효율이 떨어짐
1. 배열을 사용해 디큐를 하면서 모든 요소를 하나씩 앞쪽으로(shift) 옮기는 큐 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | package myTest1; import java.util.Scanner; public class IntAryQueue { private int max; // 큐 용량 private int num; // 현재 데이터 수 private int[] que; // 큐 본체 // 실행 시 예외 : 큐이 비어있음 public class EmptyIntAryQueueException extends RuntimeException{ public EmptyIntAryQueueException(){ } } // 실행 시 예외 : 큐이 가득 참 public class OverflowIntAryQueueException extends RuntimeException{ public OverflowIntAryQueueException(){ } } // 생성자 public IntAryQueue(int capacity){ num = 0; max = capacity; try{ que = new int[max]; // 큐 본체용 배열을 생성 }catch(OutOfMemoryError e){ // 생성할 수 없음 max = 0; } } // 큐에 데이터를 인큐하는 메서드 public int inQueue(int x) throws OverflowIntAryQueueException{ if(num >= max){ // 큐이 가득 참 throw new OverflowIntAryQueueException(); } return que[num++] = x; } // 큐의 맨 첫번째에 있는 데이터를 제거(디큐) 하고 그 값을 반환하는 메서드 public int deQueue() throws EmptyIntAryQueueException{ if(num <= 0){ throw new EmptyIntAryQueueException(); } int data = que[0]; for(int i=0; i<num-1; i++){ // 0 < 2 // 0 1 2 que[i] = que[i+1]; // que[0] = que[1] , que[1] = que[2], que[2] = que[3] } --num; return data; } // 큐의 가장 먼저 빠질 데이터를 몰래 엿보는 메서드(peek 메서드 ) public int peek() throws EmptyIntAryQueueException{ if(num <= 0){ throw new EmptyIntAryQueueException(); } return que[0]; } // 큐에서 x를 찾아 인덱스를 반환 public int indexOf(int x){ for(int i=num -1; i>=0; i--){ if(que[i] == x){ return i; } } return -1; } // 큐을 비움 public void clear(){ num = 0; } // 큐의 용량을 반환 public int capacity(){ return max; } // 큐에 쌓여있는 데이터 수를 반환 public int size(){ return num; } // 큐이 비어있는가? public boolean isEmpty(){ return num <= 0; } // 큐이 가득찼는가? public boolean isFull(){ return num >= max; } // 큐 안의 모든 데이터를 바닥 -> 꼭대기 순서로 출력 public void dump(){ if(num <= 0){ System.out.println("큐이 비어있습니다."); }else{ for(int i=0; i<num; i++){ System.out.print(que[i] + " "); } System.out.println(); } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); IntAryQueue queue = new IntAryQueue(64); // 최대 64개를 푸시할 수 있는 큐 while(true){ System.out.println("현재 데이터 수 : " + queue.size() + " / " + queue.capacity()); System.out.print("(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료 : "); int menu = scanner.nextInt(); if(menu == 0) break; int x; switch(menu){ case 1: System.out.print("데이터 : "); x = scanner.nextInt(); try{ queue.inQueue(x); }catch(IntAryQueue.OverflowIntAryQueueException e){ System.out.println("큐가 가득찼습니다."); } break; case 2: try{ x = queue.deQueue(); System.out.println("디큐한 데이터는 " + x + "입니다."); }catch(IntAryQueue.EmptyIntAryQueueException e){ System.out.println("큐가 비어있습니다."); } break; case 3: try{ x = queue.peek(); System.out.println("피크한 데이터는 " + x + "입니다."); }catch(IntAryQueue.EmptyIntAryQueueException e){ System.out.println("큐가 비어있습니다."); } break; case 4: queue.dump(); break; } } } } | cs |
결과
2. 링버퍼로 큐 만들기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | package myTest1; import java.util.Scanner; public class IntQueue { private int max; // 큐 용량 private int front; // 첫번째 요소 커서 private int rear; // 마지막 요소 커서 private int num; // 현재 데이터 수 private int[] que; // 큐 본체 // 실행 시 예외 : 큐이 비어있음 public class EmptyIntQueueException extends RuntimeException{ public EmptyIntQueueException(){ } } // 실행 시 예외 : 큐이 가득 참 public class OverflowIntQueueException extends RuntimeException{ public OverflowIntQueueException(){ } } // 생성자 public IntQueue(int capacity){ num = front = rear = 0; max = capacity; try{ que = new int[max]; // 큐 본체용 배열을 생성 }catch(OutOfMemoryError e){ // 생성할 수 없음 max = 0; } } // 큐에 데이터를 인큐하는 메서드 public int enque(int x) throws OverflowIntQueueException{ if(num >= max){ // 큐이 가득 참 throw new OverflowIntQueueException(); } // que[0] 10 que[1] 9 que[2] 8 // num = 3 que[rear++] = x; num++; if(rear == max){ rear = 0; } return x; } // 큐의 맨 첫번째에 있는 데이터를 제거(디큐) 하고 그 값을 반환하는 메서드 public int deque() throws EmptyIntQueueException{ if(num <= 0){ throw new EmptyIntQueueException(); // 큐가 비어있음. } // que[0] 10 que[1] 9 que[2] 8 // num = 3 // int x = 10, num = 2 , front = 1 int x = que[front++]; num--; if(front == max){ front = 0; } return x; } // 큐의 가장 먼저 빠질 데이터를 몰래 엿보는 메서드(peek 메서드 ) public int peek() throws EmptyIntQueueException{ if(num <= 0){ throw new EmptyIntQueueException(); } return que[front]; } // 큐에서 x를 찾아 인덱스를 반환 public int indexOf(int x){ for(int i=0; i<num; i++){ int idx = (i+front) % max; if(que[idx] == x){ // 검색 성공 return idx; } } return -1; // 검색 실패 } // 큐을 비움 public void clear(){ num = front = rear = 0; } // 큐의 용량을 반환 public int capacity(){ return max; } // 큐에 쌓여있는 데이터 수를 반환 public int size(){ return num; } // 큐이 비어있는가? public boolean isEmpty(){ return num <= 0; } // 큐이 가득찼는가? public boolean isFull(){ return num >= max; } // 큐 안의 모든 데이터를 프런트 -> 리어 순으로 출력 public void dump(){ // que[0] 10 que[1] 9 que[2] 8 // num = 3 // int x = 10, num = 2, front = 1 if(num <= 0){ System.out.println("큐이 비어있습니다."); }else{ // i=0 i<2 que[(0+1)%64 que[(1+1) // 2%64 for(int i=0; i<num; i++){ System.out.print(que[(i+front) % max] + " "); } System.out.println(); } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); IntQueue queue = new IntQueue(64); // 최대 64개를 푸시할 수 있는 큐 while(true){ System.out.println("현재 데이터 수 : " + queue.size() + " / " + queue.capacity()); System.out.print("(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료 : "); int menu = scanner.nextInt(); if(menu == 0) break; int x; switch(menu){ case 1: System.out.print("데이터 : "); x = scanner.nextInt(); try{ queue.enque(x); }catch(IntQueue.OverflowIntQueueException e){ System.out.println("큐가 가득찼습니다."); } break; case 2: try{ x = queue.deque(); System.out.println("디큐한 데이터는 " + x + "입니다."); }catch(IntQueue.OverflowIntQueueException e){ System.out.println("큐가 비어있습니다."); } break; case 3: try{ x = queue.peek(); System.out.println("피크한 데이터는 " + x + "입니다."); }catch(IntQueue.OverflowIntQueueException e){ System.out.println("큐가 비어있습니다."); } break; case 4: queue.dump(); break; } } } } | cs |
결과
3. 링 버퍼의 활용
링 버퍼는 오래된 데이터를 버리는 용도로 사용할 수 있다.
예를 들면 요소의 개수가 n인 배열에 계속 데이터가 입력되면
가장 최근에 들어온 데이터 n개만 저장하고 오래된 데이터는 버리는 용도이다.
배열의 길이는 10인데 정수입력이 12개가 들어온다면
정수 입력은 가장 최근에 입력한 10개의 데이터만 링 버퍼에 남아있다.
예전 데이터는 버리는 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package myTest1; import java.util.Scanner; public class LastElements { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); final int N = 10; int[] a = new int[N]; // 입력 받은 값을 저장 int cnt = 0; // 입력 받은 개수 int retry; // 다시 한 번? System.out.println("정수를 입력하세요."); do{ System.out.printf("%d번째 정수: ", cnt+1); a[cnt++ % N] = scanner.nextInt(); System.out.print("계속 할까요? (예. 1 / 아니오. 0) : "); retry = scanner.nextInt(); }while(retry == 1); int i = cnt - N; if(i <0) i = 0; for(;i<cnt;i++){ System.out.printf("%2d번째 정수=%d\n", i+1, a[i%N]); } } } | cs |
결과
소스코드 첨부
'전체 > 알고리즘' 카테고리의 다른 글
8퀸 문제, 가지뻗기, 분기한정법 사용 구현 (2) | 2018.10.07 |
---|---|
재귀를 사용한 팩토리얼, 최대공약수, 하노이탑 구현 (0) | 2018.10.07 |
스택 알고리즘 구현 (0) | 2018.10.03 |
이진검색 알고리즘 (구현 메소드 사용, Arrays.binarySearch 라이브러리 사용) (0) | 2018.10.03 |
선형 검색 while, for, 보초법 사용하여 구현하기 (검색 알고리즘) (0) | 2018.09.30 |