मैं प्रायोरिटी क्यू का उपयोग कैसे करूँ?


374

मैं कैसे प्राप्त करूं PriorityQueue पर सॉर्ट करने के जो मैं चाहता हूं कि मैं उस पर सॉर्ट करूं?

इसके अलावा, क्या तरीकों offerऔर addतरीकों में अंतर है ?

जवाबों:


449

कंस्ट्रक्टर ओवरलोड का उपयोग करें जो ए Comparator<? super E> comparator एक तुलनित्र में गुजरता और पास होता है जो आपके सॉर्ट क्रम के लिए उपयुक्त तरीके से तुलना करता है। यदि आप इस बात का उदाहरण देते हैं कि आप कैसे छांटना चाहते हैं, तो यदि आप निश्चित नहीं हैं तो हम तुलनित्र को लागू करने के लिए कुछ नमूना कोड प्रदान कर सकते हैं। (हालांकि यह बहुत सीधा है।)

जैसा कि कहीं offerऔर कहा गया है: और addबस अलग-अलग इंटरफ़ेस विधि कार्यान्वयन हैं। JDK स्रोत में मुझे addकॉल मिला है offer। हालांकि addऔर offerहै संभवतः के लिए क्षमता के लिए सामान्य कारण में अलग व्यवहार offerसंकेत मिलता है कि मूल्य आकार सीमाओं के कारण नहीं जोड़ा जा सकता, इस अंतर में अप्रासंगिक है PriorityQueueजो असीमित है।

यहां स्ट्रिंग लेंथ द्वारा छंटनी प्राथमिकता कतार का एक उदाहरण दिया गया है:

// Test.java
import java.util.Comparator;
import java.util.PriorityQueue;

public class Test {
    public static void main(String[] args) {
        Comparator<String> comparator = new StringLengthComparator();
        PriorityQueue<String> queue = new PriorityQueue<String>(10, comparator);
        queue.add("short");
        queue.add("very long indeed");
        queue.add("medium");
        while (queue.size() != 0) {
            System.out.println(queue.remove());
        }
    }
}

// StringLengthComparator.java
import java.util.Comparator;

public class StringLengthComparator implements Comparator<String> {
    @Override
    public int compare(String x, String y) {
        // Assume neither string is null. Real code should
        // probably be more robust
        // You could also just return x.length() - y.length(),
        // which would be more efficient.
        if (x.length() < y.length()) {
            return -1;
        }
        if (x.length() > y.length()) {
            return 1;
        }
        return 0;
    }
}

यहाँ उत्पादन है:

कम

मध्यम

वास्तव में बहुत लंबा है


7
हम्म ... बस देखा ... प्राथमिकता queue.comparator () "इस संग्रह को ऑर्डर करने के लिए उपयोग किए जाने वाले तुलनित्र को लौटाता है, या यदि यह संग्रह अपने तत्वों के प्राकृतिक क्रम (तुलनीय का उपयोग करके) के अनुसार क्रमबद्ध है।" क्या इसका मतलब है कि मैं अपनी कक्षा में भी तुलनात्मक रूप से लागू कर सकता हूं?
शविश

7
आप कर सकते हैं, हाँ। मैं ऐसा तब तक नहीं करूंगा जब तक कि आपकी कक्षा के लिए एक ही प्राकृतिक प्रकार का आदेश न हो। अगर वहाँ है, यह सही बात है :)
जॉन स्कीट

8
क्या compareसिर्फ कार्यान्वयन नहीं होना चाहिए return x.length() - y.length()? (अवॉड्र्स ब्रांच प्रेडिक्शन)
फ्रेंकी

7
@ फ्रैंकी: यह हो सकता है, हां - हालांकि मैं कहूंगा कि इसे समझना थोड़ा कठिन है, और जवाब का उद्देश्य यह दर्शाता है कि यह कैसे काम करता है। मैं हालांकि एक टिप्पणी जोड़ देंगे।
जॉन स्कीट

2
@ कर्ल: मुझे नहीं लगता कि यह बहुत ज्यादा मायने रखता है, जब तक आप मतभेदों से अवगत हैं। मुझे लगता है कि यदि आप add()जोड़ने के संचालन के लिए उपयोग कर रहे हैं , तो remove()समझदार लगता है; अगर मैं उपयोग कर offer()रहा था तो मैं शायद उपयोग करूंगा poll()... लेकिन यह सिर्फ एक व्यक्तिगत प्राथमिकता है।
जॉन स्कीट

68

जावा 8 समाधान

हम जावा 8. का उपयोग कर सकते हैं lambda expressionया method referenceशुरू कर सकते हैं । यदि हमारे पास कुछ प्राथमिकताएँ हैं, जिन्हें प्राथमिकता कतार (क्षमता 5) में संग्रहीत किया जाता है, तो हम इनलाइन तुलनित्र प्रदान कर सकते हैं (स्ट्रिंग की लंबाई के आधार पर):

लंबोदर अभिव्यक्ति का उपयोग करना

PriorityQueue<String> pq=
                    new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());

विधि संदर्भ का उपयोग करना

PriorityQueue<String> pq=
                new PriorityQueue<String>(5, Comparator.comparing(String::length));

फिर हम उनमें से किसी का भी उपयोग कर सकते हैं:

public static void main(String[] args) {
        PriorityQueue<String> pq=
                new PriorityQueue<String>(5, (a,b) -> a.length() - b.length());
       // or pq = new PriorityQueue<String>(5, Comparator.comparing(String::length));
        pq.add("Apple");
        pq.add("PineApple");
        pq.add("Custard Apple");
        while (pq.size() != 0)
        {
            System.out.println(pq.remove());
        }
    }

यह प्रिंट करेगा:

Apple
PineApple
Custard Apple

आदेश को उलटने के लिए (इसे अधिकतम-प्राथमिकता कतार में बदलने के लिए) बस क्रम इनलाइन तुलनित्र को बदल दें या निम्नानुसार उपयोग करें reversed:

PriorityQueue<String> pq = new PriorityQueue<String>(5, 
                             Comparator.comparing(String::length).reversed());

हम भी उपयोग कर सकते हैं Collections.reverseOrder:

PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5, 
                Collections.reverseOrder(Comparator.comparing(String::length))

इसलिए हम देख सकते हैं कि Collections.reverseOrderतुलनित्र लेने के लिए अतिभारित है जो कस्टम ऑब्जेक्ट्स के लिए उपयोगी हो सकता है। reversedवास्तव में उपयोग करता है Collections.reverseOrder:

default Comparator<T> reversed() {
    return Collections.reverseOrder(this);
}

ऑफ़र () बनाम ऐड ()

डॉक्टर के अनुसार

यदि संभव हो तो प्रस्ताव विधि एक तत्व सम्मिलित करती है, अन्यथा झूठे वापस लौटती है। यह Collection.add विधि से भिन्न है, जो केवल अनियंत्रित अपवाद को फेंककर एक तत्व को जोड़ने में विफल हो सकता है। ऑफ़र विधि को उपयोग के लिए डिज़ाइन किया गया है जब विफलता सामान्य घटना के बजाय सामान्य है, उदाहरण के लिए, निश्चित-क्षमता (या "बंधे") कतारों में।

क्षमता-प्रतिबंधित कतार का उपयोग करते समय, ऑफ़र () आम तौर पर जोड़ने के लिए बेहतर होता है (), जो केवल एक अपवाद फेंककर एक तत्व सम्मिलित करने में विफल हो सकता है। और प्रायोरिटी क्यू एक प्राथमिकता वाले ढेर पर आधारित एक अनबाउंड प्राथमिकता कतार है।


मैं मान रहा हूं कि 5कतार की शुरुआती क्षमता को दर्शाता है?
नील

1
@ नील, मैंने अभी इसका जवाब स्पष्ट किया है :)
akhil_mittal

1
जावा का 8 वां संस्करण सबसे अच्छी बात थी जो कभी भी भाषा के साथ हुआ
गेब्रियलबी

1
बहुत स्पष्ट व्याख्या के साथ स्पष्ट उदाहरण।
विश्व रत्न

24

बस कंस्ट्रक्टर केComparator लिए उपयुक्त पास :

PriorityQueue(int initialCapacity, Comparator<? super E> comparator)

के बीच एकमात्र अंतर है offerऔर addवे जिस इंटरफ़ेस से संबंधित हैं। offerसे संबंधित है Queue<E>, जबकि addमूल रूप से Collection<E>इंटरफ़ेस में देखा जाता है। इसके अलावा दोनों विधियां बिल्कुल समान हैं - निर्दिष्ट तत्व को प्राथमिकता कतार में डालें।


7
विशेष रूप से, जोड़ () एक अपवाद को फेंकता है यदि क्षमता प्रतिबंध आइटम को कतार में जोड़े जाने से रोकते हैं जबकि रिटर्न झूठी देते हैं। चूंकि प्रायोरिटीज में अधिकतम क्षमता नहीं है, इसलिए अंतर मूक है।
जेम्स

ऐड () और ऑफर () .. और ऐड () के बीच बहुत स्पष्ट अंतर है, वैसे भी इसे लागू करने की जरूरत थी!
व्हाइटहाट

19

से कतार एपीआई :

यदि संभव हो तो प्रस्ताव विधि एक तत्व सम्मिलित करती है, अन्यथा झूठे वापस लौटती है। यह Collection.add विधि से भिन्न है, जो केवल अनियंत्रित अपवाद को फेंककर एक तत्व को जोड़ने में विफल हो सकता है। ऑफ़र विधि को उपयोग के लिए डिज़ाइन किया गया है जब विफलता सामान्य घटना के बजाय सामान्य है, उदाहरण के लिए, निश्चित-क्षमता (या "बंधे") कतारों में।


12

कोई अलग नहीं, जैसा कि घोषणा में है:

public boolean add(E e) {
    return offer(e);
}

6

बस add()बनाम offer()प्रश्न का उत्तर देने के लिए (चूंकि दूसरा पूरी तरह से उत्तर दिया गया है, और यह नहीं हो सकता है):

इंटरफ़ेस कतार पर JavaDoc के अनुसार , "ऑफ़र विधि यदि संभव हो तो एक तत्व सम्मिलित करता है, अन्यथा गलत तरीके से लौटता है। यह Collection.add विधि से भिन्न होता है, जो केवल अनियंत्रित अपवाद को फेंककर एक तत्व को जोड़ने में विफल हो सकता है। ऑफ़र विधि के लिए डिज़ाइन किया गया है। जब असफलता एक सामान्य घटना है, तो असाधारण घटना के बजाय, उदाहरण के लिए, निश्चित-क्षमता (या "बाध्य") कतारों में उपयोग करें। "

इसका मतलब है कि यदि आप तत्व जोड़ सकते हैं (जो कि प्रायोरिटी क्यू में होना चाहिए), तो वे ठीक उसी तरह काम करते हैं। लेकिन अगर आप तत्व नहीं जोड़ सकते हैं, offer()तो आपको एक अच्छा और सुंदर falseरिटर्न देगा, जबकि add()एक गंदा अनियंत्रित अपवाद फेंकता है जिसे आप अपने कोड में नहीं चाहते हैं। यदि जोड़ने में विफलता का अर्थ है कि कोड इरादा के अनुसार काम कर रहा है और / या यह कुछ ऐसा है जिसे आप सामान्य रूप से जांचेंगे, उपयोग करें offer()। यदि जोड़ने में विफलता का मतलब है कि कुछ टूट गया है, तो संग्रह इंटरफ़ेस के विनिर्देशों केadd() अनुसार फेंके गए अपवाद को संभालें ।

वे दोनों इस तरह से कतार इंटरफ़ेस पर अनुबंध को पूरा करने के लिए कार्यान्वित किए जाते हैं जो निर्दिष्ट करता है कि offer()एक false( क्षमता-प्रतिबंधित कतार में पसंद की गई विधि) को वापस करने में विफल रहता है और संग्रह इंटरफ़ेस पर अनुबंध को बनाए रखना भी निर्दिष्ट करता है add()जो अपवाद को फेंककर हमेशा विफल रहता है

वैसे भी, आशा है कि प्रश्न के कम से कम उस हिस्से को स्पष्ट करता है।


6

यहां, हम उपयोगकर्ता परिभाषित तुलनित्र को परिभाषित कर सकते हैं:

नीचे कोड:

 import java.util.*;
 import java.util.Collections;
 import java.util.Comparator; 


 class Checker implements Comparator<String>
 {
    public int compare(String str1, String str2)
    {
        if (str1.length() < str2.length()) return -1;
        else                               return 1;
    }
 }


class Main
{  
   public static void main(String args[])
    {  
      PriorityQueue<String> queue=new PriorityQueue<String>(5, new Checker());  
      queue.add("india");  
      queue.add("bangladesh");  
      queue.add("pakistan");  

      while (queue.size() != 0)
      {
         System.out.printf("%s\n",queue.remove());
      }
   }  
}  

आउटपुट:

   india                                               
   pakistan                                         
   bangladesh

प्रस्ताव और जोड़ने के तरीकों के बीच अंतर: लिंक


1
क्या होगा अगर वे समान हैं।
nycynik

4

इसे पास करो a Comparator। के स्थान पर अपने इच्छित प्रकार को भरेंT

लैम्ब्डा (जावा 8+) का उपयोग करना:

int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });

अनाम कक्षा का उपयोग करते हुए क्लासिक तरीका:

int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {

    @Override
    public int compare(T e1, T e2) {
        return e1.compareTo(e2);
    }

});

रिवर्स ऑर्डर में सॉर्ट करने के लिए, बस e1, e2 स्वैप करें।


3

मैं प्रिंट ऑर्डर के बारे में भी सोच रहा था। इस मामले पर विचार करें, उदाहरण के लिए:

प्राथमिकता कतार के लिए:

PriorityQueue<String> pq3 = new PriorityQueue<String>();

यह कोड:

pq3.offer("a");
pq3.offer("A");

से अलग प्रिंट कर सकते हैं:

String[] sa = {"a", "A"}; 
for(String s : sa)   
   pq3.offer(s);

मुझे एक अन्य मंच पर एक चर्चा से जवाब मिला , जहां एक उपयोगकर्ता ने कहा, "प्रस्ताव () / जोड़ें () विधियां केवल कतार में तत्व सम्मिलित करती हैं। यदि आप एक पूर्वानुमान आदेश चाहते हैं तो आपको तिरछी नज़र / पोल का उपयोग करना चाहिए जो सिर को लौटाता है। कतार से


3

उपयोग करने के विकल्प के रूप में Comparator, आप वह वर्ग भी रख सकते हैं जिसका आप अपने PriorityQueue कार्यान्वयनComparable में उपयोग कर रहे हैं (और इसी compareToविधि को ओवरराइड करते हैं )।

ध्यान दें कि आम तौर पर केवल Comparableइसके बजाय इसका उपयोग करना सबसे अच्छा है Comparatorयदि ऑर्डर करना वस्तु का सहज आदेश है - यदि, उदाहरण के लिए, आपके पास Personआयु के अनुसार वस्तुओं को सॉर्ट करने के लिए उपयोग मामला है , तो संभवतः Comparatorइसके बजाय इसका उपयोग करना सबसे अच्छा है ।

import java.lang.Comparable;
import java.util.PriorityQueue;

class Test
{
    public static void main(String[] args)
    {
        PriorityQueue<MyClass> queue = new PriorityQueue<MyClass>();
        queue.add(new MyClass(2, "short"));
        queue.add(new MyClass(2, "very long indeed"));
        queue.add(new MyClass(1, "medium"));
        queue.add(new MyClass(1, "very long indeed"));
        queue.add(new MyClass(2, "medium"));
        queue.add(new MyClass(1, "short"));
        while (queue.size() != 0)
            System.out.println(queue.remove());
    }
}
class MyClass implements Comparable<MyClass>
{
    int sortFirst;
    String sortByLength;

    public MyClass(int sortFirst, String sortByLength)
    {
        this.sortFirst = sortFirst;
        this.sortByLength = sortByLength;
    }

    @Override
    public int compareTo(MyClass other)
    {
        if (sortFirst != other.sortFirst)
            return Integer.compare(sortFirst, other.sortFirst);
        else
            return Integer.compare(sortByLength.length(), other.sortByLength.length());
    }

    public String toString()
    {
        return sortFirst + ", " + sortByLength;
    }
}

आउटपुट:

1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed

1

प्राथमिकता कतार में प्रत्येक तत्व को कुछ प्राथमिकता दी गई है, सर्वोच्च प्राथमिकता वाला तत्व कतार के शीर्ष पर दिखाई देता है। अब, यह आप पर निर्भर करता है कि आप प्रत्येक तत्वों को किस प्रकार प्राथमिकता देना चाहते हैं। यदि आप नहीं करते हैं, तो जावा इसे डिफ़ॉल्ट रूप से करेगा। कम से कम मूल्य वाले तत्व को सर्वोच्च प्राथमिकता दी जाती है और इस तरह पहले कतार से हटा दिया जाता है। यदि समान सर्वोच्च प्राथमिकता वाले कई तत्व हैं, तो टाई मनमाने ढंग से टूट जाती है। आप कंस्ट्रक्टर में तुलनित्र का उपयोग करके एक आदेश भी निर्दिष्ट कर सकते हैं PriorityQueue(initialCapacity, comparator)

उदाहरण कोड:

PriorityQueue<String> queue1 = new PriorityQueue<>();
queue1.offer("Oklahoma");
queue1.offer("Indiana");
queue1.offer("Georgia");
queue1.offer("Texas");
System.out.println("Priority queue using Comparable:");
while (queue1.size() > 0) {
    System.out.print(queue1.remove() + " ");
}
PriorityQueue<String> queue2 = new PriorityQueue(4, Collections.reverseOrder());
queue2.offer("Oklahoma");
queue2.offer("Indiana");
queue2.offer("Georgia");
queue2.offer("Texas");
System.out.println("\nPriority queue using Comparator:");
while (queue2.size() > 0) {
    System.out.print(queue2.remove() + " ");
}

आउटपुट:

Priority queue using Comparable:
Georgia Indiana Oklahoma Texas 
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia 

और, आप कस्टम तुलनित्र को भी परिभाषित कर सकते हैं:

import java.util.Comparator;

public class StringLengthComparator implements Comparator<String>
{
    @Override
    public int compare(String x, String y)
    {
        //Your Own Logic
    }
}

1

यहाँ सरल उदाहरण है जिसे आप प्रारंभिक शिक्षा के लिए उपयोग कर सकते हैं:

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;

public class PQExample {

    public static void main(String[] args) {
        //PriorityQueue with Comparator
        Queue<Customer> cpq = new PriorityQueue<>(7, idComp);
        addToQueue(cpq);
        pollFromQueue(cpq);
    }

    public static Comparator<Customer> idComp = new Comparator<Customer>(){

        @Override
        public int compare(Customer o1, Customer o2) {
            return (int) (o1.getId() - o2.getId());
        }

    };

    //utility method to add random data to Queue
    private static void addToQueue(Queue<Customer> cq){
        Random rand = new Random();
        for(int i=0;i<7;i++){
            int id = rand.nextInt(100);
            cq.add(new Customer(id, "KV"+id));
        }
    }


    private static void pollFromQueue(Queue<Customer> cq){
        while(true){
            Customer c = cq.poll();
            if(c == null) break;
            System.out.println("Customer Polled : "+c.getId() + " "+ c.getName());
        }
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.