컴퓨터/data science
알고리즘 기본기 다지기4.기초 데이터구조 (덱, 우선순위 큐)
김크리
2021. 8. 18. 22:59
덱(Deque)
양쪽 끝에서 삽입과 삭제가 모두 가능한 자료구조의 형태이다.
스택과 큐를 합친 형태로 볼 수 있다.

더보기
백준10866번. 덱
LinkedList를 사용하여 만들었습니다.
package deque; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.junit.jupiter.api.Test; /** * 정수를 저장하는 덱(Deque)를 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오. * * 명령은 총 여덟 가지이다. * * push_front X: 정수 X를 덱의 앞에 넣는다. * push_back X: 정수 X를 덱의 뒤에 넣는다. * pop_front: 덱의 가장 앞에 있는 수를 빼고, 그 수를 출력한다. 만약, 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다. * pop_back: 덱의 가장 뒤에 있는 수를 빼고, 그 수를 출력한다. 만약, 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다. * size: 덱에 들어있는 정수의 개수를 출력한다. * empty: 덱이 비어있으면 1을, 아니면 0을 출력한다. * front: 덱의 가장 앞에 있는 정수를 출력한다. 만약 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다. * back: 덱의 가장 뒤에 있는 정수를 출력한다. 만약 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다. */ public class Backjun10866 { @Test public void test() { dq = new LinkedList<Integer>(); execute("push_back 1"); execute("push_front 2"); execute("front"); execute("back"); execute("size"); execute("empty"); execute("pop_front"); execute("pop_back"); execute("pop_front"); execute("size"); execute("empty"); execute("pop_back"); execute("push_front 3"); execute("empty"); execute("front"); } private static List<Integer> dq; public static void main(String[] args) { int cnt = 0; dq = new LinkedList<Integer>(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); try { String str = br.readLine(); cnt = Integer.valueOf(str); //명령어 수만큼 큐에 대한 명령을 실행한다. for(int i=0;i<cnt ; i++) { execute(br.readLine()); } } catch (IOException e) { e.printStackTrace(); } } public static void execute(String str) { //공백으로 명령을 나눈다. String[] arr = str.split(" "); String command = arr[0]; int x = arr.length>1 ? Integer.valueOf(arr[1]):0; Deque deque = new Deque(dq); if(command.equals("push_back")) { deque.push_back(x); }else if(command.equals("push_front")) { deque.push_front(x); }else if(command.equals("front")) { System.out.println(deque.front()); }else if(command.equals("back")) { System.out.println(deque.back()); }else if(command.equals("size")) { System.out.println(deque.size()); }else if(command.equals("empty")) { System.out.println(deque.empty()); }else if(command.equals("pop_front")) { System.out.println(deque.pop_front()); }else if(command.equals("pop_back")) { System.out.println(deque.pop_back()); } } } class Deque { private List<Integer> deque; public Deque(List<Integer> d){ this.deque = d; } //정수 x를 덱 앞에 넣는다. public void push_front(int x) { deque.add(0, x); } //정수 x를 덱 뒤에 넣는다. public void push_back(int x) { deque.add(x); } //덱의 가장 앞에 있는 수를 뺀다. 없는 경우 -1을 출력한다. public int pop_front() { int v = -1; if(empty() == 1) { } else { v=front(); deque.remove(0); } return v; } //덱의 가장 뒤에 있는 수를 뺀다. 없는 경우 -1을 출력한다. public int pop_back() { int v = -1; if(empty() == 1) { } else { v=back(); deque.remove(size()-1); } return v; } public int size() { return deque.size(); } //덱이 비어있으면 1을, 아니면 0을 출력한다. public int empty() { if(size() == 0) { return 1; } else { return 0; } } public int front() { int v = -1; if(empty() == 1) { } else { v=deque.get(0); } return v; } public int back() { int v = -1; if(empty() == 1) { } else { v=deque.get(size()-1); } return v; } }
우선순위 큐(Priority Queue)
데이터 항목이 자유롭게 삽일 될 수 있는 저장소로서 삭제는 순서상 가장 작은 것이 삭제되는 데이터 구조를 말한다.
주요 메소드
insertItem(k, e) 키 k인 원소 e 를 큐에 삽입
element removeMin() 큐로부터 최소 키를 가진 원소를 삭제하여 반환
구현
우선순위 큐는 큐의 구현에 따라 순서가 없는 무순리스트, 순서가 있는 순서리스트로 구현할 수 있다.
무순리스트로 구현
우선순위 큐의 항목들을 리스트에 임의 순서로 저장한다.
삽입 O(1), 삭제/최소값 검색 O(n), 선택 정렬
순서리스트로 구현
우선순위 큐의 항목들을 리스트에 키 정렬 순서로 저장한다.
삽입 O(n), 삭제/최소값 검색 O(1), 삽입 정렬
더보기
백준 1715. 카드
package queue.priority; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.PriorityQueue; import org.junit.jupiter.api.Test; /** * 정렬된 두 묶음의 숫자 카드가 있다고 하자. * 각 묶음의 카드의 수를 A, B라 하면 보통 두 묶음을 합쳐서 하나로 만드는 데에는 A+B 번의 비교를 해야 한다. * 이를테면, 20장의 숫자 카드 묶음과 30장의 숫자 카드 묶음을 합치려면 50번의 비교가 필요하다. 매우 많은 숫자 카드 묶음이 책상 위에 놓여 있다. 이들을 두 묶음씩 골라 서로 합쳐나간다면, 고르는 순서에 따라서 비교 횟수가 매우 달라진다. 예를 들어 10장, 20장, 40장의 묶음이 있다면 10장과 20장을 합친 뒤, 합친 30장 묶음과 40장을 합친다면 (10 + 20) + (30 + 40) = 100번의 비교가 필요하다. 그러나 10장과 40장을 합친 뒤, 합친 50장 묶음과 20장을 합친다면 (10 + 40) + (50 + 20) = 120 번의 비교가 필요하므로 덜 효율적인 방법이다. N개의 숫자 카드 묶음의 각각의 크기가 주어질 때, 최소한 몇 번의 비교가 필요한지를 구하는 프로그램을 작성하시오. * */ public class Backjun1715 { private static int n=0; private static PriorityQueue<Integer> queue; @Test public void test() { n = 3; queue= new PriorityQueue<Integer>(); addCards(10); addCards(20); addCards(40); addCards(40); //10 + 20 = 30 //10 + 20 + 40 = 70 //10 + 20 + 40 + 40 = 110 //210 execute(); } public static void main(String[] args) { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); try { queue= new PriorityQueue<Integer>(); String str = br.readLine(); //N개 줄만큼 카드 묶음 노출 n = (Integer.valueOf(str)); for(int i=0;i<n ; i++) { //카드 묶음의 크기 addCards(Integer.valueOf(br.readLine())); } execute(); } catch (IOException e) { e.printStackTrace(); } } public static void addCards(int cards) { //순서 리스트 삽입 = 우선순위 큐(작은것 순서대로 삽입됨) queue.add(cards); } public static void execute() { int compare = 0; if(queue.size() > 1) { while(!queue.isEmpty()) { //순서 - 작은것부터 빼는 우선순위큐 int a = queue.poll(); int b = queue.poll(); compare += (a+b); if(queue.isEmpty()) { break; } queue.add(a+b); } } System.out.println(compare); } }
참조
알고리즘 국형준
https://ko.wikipedia.org/wiki/%EB%8D%B1_(%EC%9E%90%EB%A3%8C_%EA%B5%AC%EC%A1%B0)