2009-03-16 21 views
24

मेरे पास कुछ ऑब्जेक्ट की प्राथमिकता_क्यू है:एसटीएल प्राथमिकता_क्यू में एक कुशल प्राथमिकता अद्यतन कैसे करें?

typedef priority_queue<Object> Queue; 
Queue queue; 

समय-समय पर, ऑब्जेक्ट्स में से किसी एक की प्राथमिकता बदल सकती है - मुझे कतार में उस ऑब्जेक्ट की प्राथमिकता को एक कुशल तरीके से अपडेट करने में सक्षम होना चाहिए । वर्तमान में मैं इस विधि का उपयोग कर रहा हूं जो काम करता है लेकिन अक्षम लगता है:

Queue newQueue; 
while (!queue.empty()) 
{ 
    Object obj=queue.top(); 
    queue.pop(); 

    if (priorityHasChanged(obj)) 
    newQueue.push_back(Object(new_priority)); 
    else 
    newQueue.push_back(obj); 
} 

newQueue.swap(queue); // this only works because I actually subclassed the priority_queue 
       // class and exposed a swap method that swaps in the container 

मैंने इसे इस तरह कार्यान्वित किया क्योंकि मैं उस समय जल्दी में था और यह सबसे तेज़ चीज थी जो मैं कर सकता था कि मैं इसे सुनिश्चित कर सकता था ठीक काम करेगा। हालांकि इसके मुकाबले बेहतर तरीका होना चाहिए। वास्तव में जो मैं चाहता हूं वह एक तरीका है:

  • बदली हुई प्राथमिकता के साथ उदाहरण निकालें और नई प्राथमिकता मान
  • के साथ एक नया डालें बदली प्राथमिकता के साथ उदाहरण अद्यतन करें और फिर कतार को अद्यतन करें कि यह सही ढंग से क्रमबद्ध है

ऐसा करने का सबसे अच्छा तरीका क्या है?

उत्तर

7

मुझे लगता है कि आप मानक प्राथमिकता कतार के साथ भाग्य से बाहर हैं क्योंकि आप अंतर्निहित डेक/वेक्टर/सूची या जो कुछ भी प्राप्त नहीं कर सकते हैं। आपको अपना खुद का कार्यान्वयन करने की ज़रूरत है - यह मुश्किल नहीं है।

+4

यह सही नहीं है - मानक प्राथमिकता कतार कंटेनर को संरक्षित सदस्य 'c' के रूप में संग्रहीत करती है (देखें [संदर्भ] (http://en.cppreference.com/w/cpp/container/priority_queue))। आप प्राथमिकता कतार से प्राप्त कर सकते हैं और व्युत्पन्न कक्षा में कंटेनर तक पहुंच सकते हैं। –

+0

@ user283145 सुनिश्चित करें कि आप 'c' के साथ अंतर्निहित ढेर तक पहुंच प्राप्त कर सकते हैं, लेकिन चूंकि आप ओ (लॉग इन) में किसी कुंजी की अनुक्रमणिका नहीं पा रहे हैं, तो आप O (lgn) में प्राथमिकता अद्यतन नहीं कर सकते जो वास्तव में है दुर्भाग्यपूर्ण हिस्सा। –

0

आप replace_if पर एक उदाहरण here के साथ एक नज़र रखना चाहते हैं।

+1

क्षमा करें यह उपयोग करने योग्य नहीं है, प्राथमिकता_क्यू कक्षा में यादृच्छिक पहुंच (या किसी अन्य प्रकार के) इटरेटर नहीं हैं। http://www.cplusplus.com/reference/stl/priority_queue/ –

+1

बहुत सराहना की। मैं इससे कुछ सीखता हूं। – dubnde

4

एसटीएल (जो मुझे पता है) के साथ ऐसा करने का सबसे सरल तरीका प्रविष्टि को हटाना, इसकी प्राथमिकता अपडेट करना और फिर इसे पुन: सम्मिलित करना है। ऐसा करना std :: primary_queue का उपयोग करके काफी धीमा है, हालांकि आप std :: set के साथ एक ही चीज़ कर सकते हैं। दुर्भाग्य से आपको सेट में होने पर ऑब्जेक्ट की प्राथमिकता को बदलने के लिए सावधान रहना होगा।

मैंने एक mutd_priority_queue क्लास आधारित ग्लूइंग को एक std :: multimap (मूल्य मैपिंग के लिए प्राथमिकता के लिए) और एक std :: map (प्राथमिकता मैपिंग के मान के लिए) लागू किया है जो आपको आइटम्स को सम्मिलित करने/हटाने के साथ-साथ अपडेट करने की अनुमति देता है लॉगरिदमिक समय में मौजूदा मान। आप कोड प्राप्त कर सकते हैं और इसका उपयोग कैसे करें here

+1

आप एक एसएलएल प्राथमिकता कतार में एक यादृच्छिक स्थिति में एक प्रविष्टि को नहीं हटा सकते हैं - आप केवल शीर्ष तत्व तक पहुंच सकते हैं। –

+0

@ जेम्स: कोड के लिए धन्यवाद। यहां कुछ सुझाव दिए गए हैं: (1) mutable_priority_queue के लिए टेम्पलेट परिभाषा स्पष्ट रूप से (प्राथमिकता, कुंजी) है, हालांकि, सम्मिलन कथन (कुंजी, प्राथमिकता) है। ये लगातार होना चाहिए, अधिमानतः दोनों (कुंजी, प्राथमिकता) के साथ। इटेटरेटर को भी 'पहली' कुंजी होना चाहिए और 'दूसरा' प्राथमिकता होना चाहिए। (2) आपको वर्तमान प्राथमिकता प्राप्त करने के लिए एक प्राप्त प्राथमिकता (कॉन्स कुंजी) प्रदान करनी चाहिए। यह एल्गोरिदम के लिए एक आम आवश्यकता है जहां आपको प्राथमिकता को ऊपर या नीचे टक्कर देने के लिए शीर्ष पर आवश्यक वस्तु के लिए प्राथमिकता प्राप्त करने की आवश्यकता नहीं है। – stackoverflowuser2010

6

उपयुक्त डेटा संरचना को "फिबोनाची हीप" कहा जाता है। लेकिन आपको इसे स्वयं लागू करने की आवश्यकता है। सम्मिलित/अपडेट ओ (1) एक्स्ट्रेक्टमिन ओ (लॉगन)

32

मैं समस्या को हल करने के लिए 2 विकल्प सुझा सकता हूं, हालांकि न तो वास्तविक अपडेट करता है।

  1. priority_queue का उपयोग करें और हर बार जब आप इसे अपडेट करना चाहते हैं तो तत्व दबाएं। इस तथ्य को स्वीकार करें कि आपके पास कतार में बेकार प्रविष्टियां होंगी। शीर्ष मान को पॉप करते समय, जांचें कि इसमें अद्यतित मूल्य है या नहीं। यदि नहीं, तो इसे अनदेखा करें और अगला पॉप करें।

    इस तरह आप अद्यतन तत्व को हटाने में देरी करते हैं जब तक कि यह शीर्ष पर न आए। मैंने देखा कि इस दृष्टिकोण का उपयोग शीर्ष प्रोग्रामर द्वारा किया जा रहा है जिसे डिजस्ट्रा एल्गोरिदम को महसूस किया जा रहा है।

  2. set का उपयोग करें। यह भी क्रमबद्ध है ताकि आप लॉगरिदमिक समय में सबसे बड़ा तत्व निकालने में सक्षम हो। आप इसे फिर से डालने से पहले पुराने तत्व को हटाने में भी सक्षम हैं। तो अभी भी कोई अपडेट ऑपरेशन संभव नहीं है, लेकिन हटाने और पुन: सम्मिलन करने योग्य है।

ऐसा लगता है कि दोनों दृष्टिकोणों की जटिलता समान है।

+1

"मैंने देखा कि इस दृष्टिकोण का उपयोग शीर्ष प्रोग्रामर द्वारा किया जा रहा है जिसे डिजस्ट्रा एल्गोरिदम को महसूस किया जा रहा है।" अगर प्रोग्रामर ने इस तथ्य का जिक्र किया तो यह बहुत स्पष्ट हो गया होता। इंगित करने के लिए धन्यवाद! – sonofrage

+0

@sonofrage आप वास्तव में कैसे करते हैं "जांच करें कि इसमें अद्यतित मूल्य है" ??? – dimitris93

+0

आमतौर पर कतार में डेटा अनावश्यक है। तो आप किसी अन्य डेटा ऑब्जेक्ट में मान के साथ कतार से मूल्य की तुलना कर सकते हैं, शायद एक तालिका। यदि मूल्य अलग है, तो इसे त्याग दिया जाना चाहिए। – Jarekczek

0

दुर्भाग्यवश आप प्राथमिकता_क्यू में मूल्य अपडेट नहीं कर सकते हैं। primary_queue ऐसे इंटरफ़ेस की पेशकश नहीं करता है।

मुझे लगता है कि आप set का बेहतर उपयोग करेंगे क्योंकि जैरेककेज़ ने कहा या this solution (make_heap का उपयोग करके) का उपयोग करें।