1. 우선 값 데이터 구조
JDK7의 PriorityQueue (우선 순위 큐)의 데이터 구조는 이진 힙입니다. 정확히 말하면 가장 작은 더미입니다.
이진 힙은 특수 힙으로 대략 완전한 이진 트리입니다. 바이너리 힙은 특성을 충족시킵니다. 모 노드의 키 값은 항상 하위 노드의 키 값과 고정 된 순서 관계를 유지하며 각 노드의 왼쪽 하위 트리 및 오른쪽 하위 트리는 이진 힙입니다.
최대 힙은 상위 노드의 키 값이 항상 하위 노드의 키 값보다 크거나 동일 할 때입니다. 최소 힙은 상위 노드의 키 값이 항상 하위 노드의 키 값보다 작거나 동일 할 때입니다.
다음 그림은 최대 힙입니다
PriorityQueue 팀 헤더는 주어진 순서에서 가장 작은 요소입니다.
PriorityQueue는 NULL 값을 허용하지 않으며 비교할 수없는 객체를 지원하지 않습니다. PriorityQueue는 비슷한 및 비교기 인터페이스를 사용하여 객체를 정렬해야하며, 그 요소는 정렬시 우선 순위에 따라 처리됩니다.
PriorityQueue의 크기는 생겨나지 않지만 초기 크기는 생성 될 때 지정할 수 있습니다. 대기열 요소를 추가 할 때 큐가 자동으로 확장됩니다.
PriorityQueue는 스레드 안전이 아니며 유사한 PriorityBlockingQueue는 스레드 안전입니다.
우리는 대기열이 최초의 첫 번째-아웃 모드를 따르지만 때로는 대기열의 우선 순위에 따라 객체를 처리해야합니다. 예를 들어, 매일 거래 시간 동안 주식 보고서를 생성하는 응용 프로그램이있어 많은 데이터를 처리해야하며 많은 처리 시간이 걸립니다. 클라이언트 가이 응용 프로그램에 요청을 보내면 실제로 큐가 들어갑니다. 우선 순위 고객을 먼저 처리 한 다음 일반 사용자와 거래해야합니다. 이 경우 Java의 우선 순위 (우선 순위 대기열)가 매우 도움이됩니다.
Priorityqueue는 우선 순위 힙을 기반으로 한 무한한 큐입니다. 이 우선 순위 대기열의 요소는 기본적으로 자연스럽게 정렬하거나 큐가 제공된 비교기에 의해 인스턴스화 될 때 정렬 할 수 있습니다.
우선 순위 대기열은 NULL 값을 허용하지 않으며 사용자 정의 클래스와 같은 비교할 수없는 객체를 지원하지 않습니다. 우선 순위 대기열은 객체를 정렬하기 위해 Java 비교 가능 및 비교기 인터페이스를 사용해야하며, 정렬시 우선 순위에 따라 요소가 처리됩니다.
우선 순위 큐의 헤더는 자연 분류 또는 비교기 분류를 기반으로하는 가장 작은 요소입니다. 여러 객체가 같은 종류의 객체를 사용하면 무작위로 객체를 가져갈 수 있습니다. 대기열을 얻으면 대기열의 헤더 객체를 반환합니다.
우선 순위 대기열의 크기는 제한되지 않지만 초기 크기는 생성 시간에 지정할 수 있습니다. 우선 순위 큐에 요소를 추가하면 큐 크기가 자동으로 증가합니다.
PriorityQueue는 스레드가 아닌 것이 아니므로 Java는 Java 다중 스레드 환경에 우선시 블록 (Blockingqueue 인터페이스 구현)을 제공합니다.
2. PriorityQueue 소스 코드 분석
회원:
priavte 과도 객체 [] 대기열; 개인 int size = 0;
1. PriorityQueue에 의해 작은 상단 힙을 구성하는 과정
여기서 우리는 PriorityQueue 생성자를 사용하여 컨테이너를 매개 변수 우선 큐 (collecntion <? extends e> example)로 전달합니다.
작은 상단 힙을 구성하는 과정은 대략 두 단계로 나뉩니다.
컨테이너 데이터를 복사하고 컨테이너 데이터가 null인지 확인하십시오.
private void initElementsFromCollection (collection <? extends e> c) {object [] a = c.toArray (); // c.toArray가 잘못 되돌아 오지 않으면 객체를 반환하지 않으면 복사하십시오. if (a.getClass ()! = Object []. class) a = arrays.copyof (a, a.length, object []. class); int len = a.length; if (len == 1 || this.comparator! = null) for (int i = 0; i <len; i ++) if (a [i] == null) 새 nullpointerexception (); this.queue = a; this.size = a.length;} 데이터가 작은 상단 힙의 구조를 충족하도록 조정하십시오.
첫째, 두 가지 조정 방법 : Siftup과 Siftdown
Siftdown : 초기화 요소가 주어지면 요소를 최소 힙의 구조적 특성을 충족하도록 조정해야합니다. 따라서 요소 X의 주요 값은 요소 X의 키 값이 어린이의 키 값보다 작거나 같거나 (즉, 왼쪽 및 오른쪽 노드 값보다 작음) 리프 노드에 떨어질 때까지 자식과 위에서 아래로 아동과 지속적으로 비교되고 교환됩니다.
예를 들어, 다음 다이어그램에 표시된 대로이 노드 9를 조정하십시오.
개인 void siftdown -comparable (int k, e x) {비교 가능한 <? Super E> key = (비교 가능 <? super e>) x; int 절반 = 크기 >>> 1; // size/2는 잎 노드에 도달하지 않는 한 (k <Half) {int child = (k << 1) + 1; // 왼쪽 자식 객체 C = 대기열 [child]; int right = child + 1; // 왼쪽과 오른쪽 어린이의 가장 작고 작은 어린이를 찾으십시오 (오른쪽 <size && ((비교 가능한 <? super e>) c) .compareto ((e) 대기열 [오른쪽])> 0) c = 대기열 [child = right]; if (key.compareto ((e) c) c) <= 0) break; 대기열 [k] = c; k = 아이; } 큐 [k] = 키;} SIFTUP : PRIORITYQUEUE 새 요소가 추가 될 때마다 새 요소를 꼬리에 삽입합니다. 따라서 하단 (잎)에서 위쪽으로 조정하는 것을 제외하고는 체로 조정 프로세스가 있어야합니다.
예를 들어, 다음 다이어그램에서 키 3으로 노드를 채우십시오.
개인 void siftupcomparable (int k, e x) {비교 가능한 <? Super E> key = (비교 가능 <? super e>) x; while (k> 0) {int parent = (k -1) >>> 1; // 상위 위시 객체 e = 대기열 [부모]; if (key.compareto ((e) e) e)> = 0) break; 대기열 [k] = e; k = 부모; } 큐 [k] = 키;}작은 상단 힙을 구축하는 전반적인 과정은 다음과 같습니다.
private void initfromCollection (collection <? extends e> c) {initElementsFromCollection (c); 무거운(); }그중에서도 Heapify는 Siftdown의 과정입니다.
2. 우선 값 용량 확장 프로세스
인스턴스 멤버에서 알 수 있듯이 PriorityQueue는 객체를 유지하므로 확장 방법은 주문 테이블 배열리스트와 유사합니다.
성장 방법의 소스 코드 만 여기에 나와 있습니다.
Private Void Grow (int mincapacity) {int OldCapacity = queue.length; // 작은 경우 이중 크기; 그렇지 않으면 50% int newCapacity = OldCapacity + ((OldCapacity <64)? (OldCapacity + 2) : (OldCapacity >> 1)); // 오버 플로우에 민감한 코드 if (newCapacity -max_array_size> 0) newCapacity = hugecapacity (mincapacity); 대기열 = arrays.copyof (큐, NewCapacity); }배열의 용량이 크지 않으면 매번 용량이 크지 않다는 것을 알 수 있습니다. 배열 용량이 64보다 크면 매번 더블이 확장됩니다.
3. 우선 값 응용 프로그램
EG1 :
가장 간단한 응용 프로그램은 다음과 같습니다. 동적 데이터에서 가장 큰 숫자를 찾으십시오.
아이디어는 크기 = k 인 작은 상단 더미를 유지하는 것입니다.
// 데이터는 동적 데이터입니다. // 힙은 동적 데이터를 유지합니다. // res는 K-most 값을 절약하는 데 사용됩니다. Public Boolean kthlargest (int data, int k, priorityqueue <integer> heap, int [] res) {if (heap.size () <k) {heap.offer (data); if (heap.size () == k) {res [0] = heap.peek (); 진실을 반환하십시오. } false를 반환합니다. } if (heap.peek () <data) {heap.poll (); Heap. Offer (데이터); } res [0] = heap.peek (); 진실을 반환하십시오. }
EG2 :
우리는 어떤 종류의 종류를 제공하지 않는 사용자 수업 고객이 있습니다. 우선 순위 대기열을 만들기 위해이를 사용하면 비교 객체를 제공해야합니다.
Customer.java
com.journalDev.collections 패키지; 공개 클래스 고객 {private int id; 개인 문자열 이름; 공개 고객 (int i, String n) {this.id = i; this.name = n; } public int getId () {return id; } public String getName () {return name; }} Java Random Numbers를 사용하여 임의의 사용자 객체를 생성합니다. 자연 분류의 경우 정수 객체를 사용하며 캡슐화 된 Java 객체이기도합니다.
다음은 PriorityQueue 사용 방법을 보여주는 최종 테스트 코드입니다.
PriorityQueueExample.java
com.journalDev.collections 패키지; import java.util.comparator; import java.util.priorityqueue; import java.util.queue; import java.util.random; 공개 클래스 우선권 queueexample {public static void main (String [] args) {// 우선 큐 자연 분류 예제 큐 <integer> integerpriorityqueue = new PriorityQueue <> (7); 랜덤 rand = 새로운 랜덤 (); for (int i = 0; i <7; i ++) {integerpriorityqueue.add (new Integer (rand.nextint (100)); } for (int i = 0; i <7; i ++) {integer in = integerpriorityqueue.poll (); System.out.println ( "처리 정수 :"+in); } // 우선 순위 대기열 사용 예제 큐 <customer> customerPriorityQueue = new PriorityQueue <> (7, idcomparator); AddDatatoqueue (CustomerPriorityQueue); PollDataFromqueue (CustomerPriorityQueue); } // 익명 비교기는 공개 정적 비교기 <customer> idcomparator = new Comporator <customer> () {@override public int compart (customer c1, customer c2) {return (int) (c1.getId () - c2.getId ()); }}; // 큐에 데이터를 추가하는 데 사용되는 범용 메소드 개인 정적 무효 AddDatatoqueue (Queue <customer> customerpriorityqueue) {random rand = new random (); for (int i = 0; i <7; i ++) {int id = rand.nextint (100); CustomerPriorityQueue.add (신규 고객 (id, "pankaj"+id)); }} // 대기열에서 데이터를 가져 오는 일반적인 방법 개인 정적 void polldatafromqueue (queue <customer> customerpriorityqueue) {while (true) {customer cust = customerpriorityque.poll (); if (cust == null) 브레이크; System.out.println ( "id ="+cust.getid ()로 고객 처리; }}}} 비교기 인터페이스를 구현하고 ID 기반 비교기를 구현하는 Java 익명 클래스를 사용합니다.
위의 테스트 프로그램을 실행하면 다음과 같은 출력을 얻습니다.
처리 정수 : 9 프로세싱 정수 : 16 프로세싱 정수 : 18 프로세싱 정수 : 25 프로세싱 정수 : 33Processing Integer : 75Processing Integer : ID를 사용한 6 개 프로세싱 고객을 가진 고객이있는 고객이있는 고객 고객을 가진 고객이있는 고객이 있습니다. ID = 96을 가진 ID = 82 프로세싱 고객
출력 결과에서, 가장 작은 요소가 큐 헤드에서 먼저 꺼내는 것을 분명히 알 수 있습니다. 비교기가 구현되지 않으면 CustomerPriorityQueue를 생성 할 때 ClassCastException이 발생합니다.
스레드 예외 "main"java.lang.classcastexception : com.journaldev.collections.customer는 java.util.priorityqueue.siftupcomparable (priorityqueue.java:633)에서 java.lang.comparable로 캐스트 할 수 없습니다. java.util.priorityqueue.offer (priorityqueue.java:329) at java.util.priorityqueue.add (priorityqueue.java:306) at com.journalDev.collections.priorityqueueexample.addatatoqueue (priorityqueueexample.java:45) at com.journaldev.collections.priorityqueueexample.main (priorityqueueexample.java:25)