2010-03-17 10 views
5

मान लीजिए मैं इस तरह के एक अगर/बाकी-अगर श्रृंखला:तो-और कुछ-अगर नक्शा बनाम

if(x.GetId() == 1) 
{ 
} 
else if(x.GetId() == 2) 
{ 
} 
// ... 50 more else if statements 

मैं क्या आश्चर्य है, अगर मैं एक नक्शे के रखने के लिए, यह किसी भी बेहतर प्रदर्शन करने के मामले में हो जाएगा? (मानते हुए कुंजी पूर्णांक हैं)

+1

क्या आपके पास पंक्ति में बयान होने पर गंभीरता से 50 है? मुझे लगता है कि एक 'लूप' क्रम में हो सकता है ... –

+0

आपको अपने बयान में जो कुछ करना है उसे जोड़ना चाहिए। वैसे, कोड मार्कअप के लिए, कोड का चयन करें और '010' बटन का उपयोग करें या कोड को 4 रिक्त स्थान से इंडेंट करें। –

+0

[स्पष्टता के लिए हटाया गया] –

उत्तर

5

आप एक स्विच का उपयोग क्यों नहीं करते?

swich(x.GetId()) 
{ 
    case 1: /* do work */ break; // From the most used case 
    case 2: /* do work */ break; 
    case ...: // To the less used case 
} 

संपादित करें:

स्विच के शीर्ष में सर्वाधिक उपयोग होने वाले मामले रखो (यह कुछ प्रदर्शन मुद्दा हो सकता है अगर x.GetId आम तौर पर बराबर 50 करने के लिए है)

+0

बस जानकारी के लिए: कुछ कंपाइलर्स मामलों के "घने" सेट को पहचानेंगे, यानी एक (अधिकतर) पूर्णांक का लगातार समूह, और अनुक्रमित कूद में स्विच को अनुकूलित करें। इस प्रकार, अक्सर मामलों को "हाथ अनुकूलन" अक्सर अनिवार्य है। –

2

switch सबसे अच्छा है मुझे लगता है कि

+1

AFAIK, स्विच स्टेटमेंट प्रदर्शन के संदर्भ में/अन्य के मुकाबले काफी बेहतर नहीं हैं, क्या मैं सही हूं? – perezvon

+2

कौन जानता है, आप इसे क्यों प्रोफ़ाइल नहीं देखते और देखते हैं? अनुमान में कोई योग्यता नहीं है। अगर आपने हमें बताया कि आप क्या कर रहे हैं (बड़ी तस्वीर), तो हम बेहतर सलाह दे सकते हैं। उस ने कहा, स्विच स्टेटमेंट बेहतर प्रदर्शन करते हैं, कुछ मामलों के मामले में, आईआईआरसी। – GManNickG

+1

@perezvon: नहीं 'स्विच' आम तौर पर एक कूद तालिका बनाता है यदि सीमाएं बड़ी नहीं हैं, ओ (1) प्रदर्शन दे रही हैं। – kennytm

0

बेहतर समाधान switch कथन होगा। यह आपको आपके कोड के अनुसार अब 25 गुना (औसतन) की बजाय, केवल एक बार x.GetId() के मान की जांच करने की अनुमति देगा।

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

10

मानचित्र (आमतौर पर) लाल-काले पेड़ का उपयोग करके कार्यान्वित किए जाते हैं जो ओ (लॉग एन) लुकअप देता है क्योंकि पेड़ लगातार संतुलन में रखा जाता है। यदि बयानों की आपकी रैखिक सूची ओ (एन) सबसे खराब मामला होगा। तो, हाँ लुकअप के लिए एक नक्शा काफी तेज होगा।

कई लोग एक स्विच स्टेटमेंट का उपयोग करने की सिफारिश कर रहे हैं, जो आपके वास्तविक विवरणों के आधार पर आपके लिए तेज़ नहीं हो सकता है। एक कंपाइलर कभी-कभी एक कूद तालिका का उपयोग कर स्विच को अनुकूलित कर सकता है जो ओ (1) होगा, लेकिन यह केवल उन मानों के लिए संभव है जो एक अनिर्धारित मानदंड हैं; इसलिए यह व्यवहार कुछ हद तक nondeterministic हो सकता है। हालांकि Optimizing C and C++ Code पर स्विच कथन अनुकूलित करने के कुछ सुझावों के साथ एक महान लेख है।

आप तकनीकी रूप से एक संतुलित पेड़ को मैन्युअल रूप से भी बना सकते हैं, यह स्थैतिक डेटा के लिए सबसे अच्छा काम करता है और मैं हाल ही में यह पता लगाने के लिए एक समारोह बना रहा था कि बाइट में कौन सा बिट सेट किया गया था (यह एक I पर एक एम्बेडेड एप्लिकेशन में उपयोग किया गया था।

unsigned char single_bit_index(unsigned char bit) { 
    // Hard-coded balanced tree lookup 
    if(bit > 0x08) 
     if(bit > 0x20) 
      if(bit == 0x40) 
       return 6; 
      else 
       return 7; 
     else 
      if(bit == 0x10) 
       return 4; 
      else 
       return 5; 
    else 
     if(bit > 0x02) 
      if(bit == 0x04) 
       return 2; 
      else 
       return 3; 
     else 
      if(bit == 0x01) 
       return 0; 
      else 
       return 1; 
} 

यह एक निरंतर जो मुझे देता है 8 मान से किसी के लिए 3 चरणों में देखने देता है:/हे पिन बाधा और त्वरित होने के लिए जब समय केवल 1 बिट बाइट में सेट किया जाता था) के 99% के लिए किया था बहुत दृढ़ संकल्प प्रदर्शन, एक रैखिक खोज - यादृच्छिक डेटा दिया गया - औसत 4 चरण लुकअप, 1 के सर्वोत्तम मामले और 8 चरणों के सबसे खराब मामले के साथ।

यह एक श्रेणी का एक अच्छा उदाहरण है कि एक कंपाइलर शायद एक कूद तालिका में ऑप्टिमाइज़ नहीं करेगा क्योंकि 8 मूल्य जो मैं खोज रहा हूं, अब तक अलग हैं: 1, 2, 4, 8, 16, 32, 64, और 128. इसे एक बहुत ही स्पैस 128 स्थिति तालिका बनाना होगा जिसमें लक्ष्य वाले 8 तत्व होंगे, जो कि एक टन RAM के साथ एक पीसी पर एक बड़ा सौदा नहीं हो सकता है, लेकिन माइक्रोकंट्रोलर पर यह हत्यारा होगा।

+1

भले ही कोई स्विच इसे टेबल नहीं बना सकता है, मुझे लगता है कि संकलक स्वचालित रूप से आपके लिए बाइनरी खोज में बदलने के लिए तुलना कर सकता है। – visitor

+0

मुख्य शब्द हो सकता है, बेशक कंपाइलर _can_ सभी प्रकार की चीजें करता है, लेकिन यदि यह मानक में नहीं है और/या आपका कंपाइलर मानक अनुरूप नहीं है तो आपको "कर सकते हैं" की नोडेटर्मेनिस्टिक प्रकृति के साथ रहना होगा , "शायद", या "मई"। एक बिल्ड जल्दी से चलाएगा, आप एक बदलाव करेंगे और आपका अगला निर्माण धीमा हो जाएगा, फिर आपको यह पता लगाना होगा कि क्यों अचानक आपका स्विच बीएसटी या कूद तालिका के बजाय समकक्ष/अन्य समकक्ष में परिवर्तित हो गया। एक मानचित्र-आधारित-कूद-तालिका अधिकतर मामलों में अधिक पठनीय, निर्धारक, एक्स्टेंसिबल और तेज होगी। – joshperry

0

उत्तर, जैसा कि अधिकांश प्रदर्शन संबंधी प्रश्नों के साथ है, शायद हो सकता है।

यदि आईडी भाग्यशाली सीमा में हैं, तो switch एक कूद-तालिका बन सकता है, जो सभी आईडी को निरंतर समय लुकअप प्रदान करता है। आप इससे अधिक बेहतर नहीं होंगे, फिर से डिजाइन करने से कम।वैकल्पिक रूप से, यदि आईडी लगातार हैं लेकिन आपको कंपाइलर से एक जंप-टेबल नहीं मिलती है, तो आप फ़ंक्शन पॉइंटर्स के साथ सरणी भरकर समस्या को मजबूर कर सकते हैं।

एक map बुरी से बुरी हालत किसी भी आईडी के लिए लघुगणक देखने प्रदान करता है, [यहाँ से, switch एक सामान्य if/else श्रृंखला को संदर्भित करता है], जबकि एक switch केवल रैखिक गारंटी ले सकते हैं। हालांकि, यदि आईडी यादृच्छिक नहीं हैं, तो उपयोग करके switch मामलों को सॉर्ट करने से यह सुनिश्चित हो सकता है कि सबसे खराब स्थिति परिदृश्य पर्याप्त दुर्लभ है कि इससे कोई फर्क नहीं पड़ता। जब आईडी लोड हो रहा है और उन्हें कार्यों के साथ जोड़

एक map कुछ प्रारंभिक भूमि के ऊपर उठाना होगा, और फिर एक समारोह सूचक आप एक आईडी का उपयोग हर बार फोन करने के एक भूमि के ऊपर उठाना। एक switch नियमित रूप से लिखते समय अतिरिक्त ओवरहेड लेता है, और संभावित रूप से महत्वपूर्ण ओवरहेड इसे डिबग करते समय।

रीडिज़ाइनिंग से आप सभी को एक साथ प्रश्न से बचने की अनुमति दे सकते हैं। इससे कोई फर्क नहीं पड़ता कि आप इसे कैसे कार्यान्वित करते हैं, यह मुसीबत की तरह गंध करता है। मैं मदद नहीं कर सकता लेकिन सोचता हूं कि इसे संभालने का एक बेहतर तरीका है।

0

यदि मेरे पास वास्तव में पचास संभावनाओं का संभावित स्विच था, तो मैं निश्चित रूप से कार्यों के लिए पॉइंटर्स के वेक्टर के बारे में सोचता।

#include <cstdio> 
#include <cstdlib> 
#include <ctime> 

const unsigned int Max = 4; 

void f1(); 
void f2(); 
void f3(); 
void f4(); 
void (*vp[Max])(); 

int main() 
{ 
    vp[ 0 ] = f1; 
    vp[ 1 ] = f2; 
    vp[ 2 ] = f3; 
    vp[ 3 ] = f4; 

    srand(std::time(NULL)); 
    vp[(rand() % Max)](); 
} 

void f1() 
{ 
    std::printf("Hello from f1!\n"); 
} 

void f2() 
{ 
    std::printf("Hello from f2!\n"); 
} 

void f3() 
{ 
    std::printf("Hello from f3!\n"); 
} 

void f4() 
{ 
    std::printf("Hello from f4!\n"); 
} 
+0

काफी अच्छा डिजाइन: मैं स्थिर रूप से फ़ंक्शन वेक्टर vp प्रारंभ कर दूंगा। – Phong

+0

किसी मामले में, आपको केस प्रबंधित करने की आवश्यकता हो सकती है (x.getID 0 और मैक्स के बीच नहीं है) इसे आवश्यकतानुसार अधिक मेमोरी की आवश्यकता होती है (उदाहरण: हम केवल x = 1-50 के लिए केस देखना चाहते हैं, और x = 100 ... या कोई अन्य पैटर्न। – Phong

+0

यदि आप किसी मानचित्र की तुलना कर रहे हैं, खाली रिक्त स्थान के साथ भी आप स्मृति को सहेज सकते हैं। फ़ंक्शन पॉइंटर्स के अतिरिक्त, यह कुंजी को स्टोर करता है और जो भी विविध डेटा को बनाए रखने के लिए आवश्यक है पेड़ [एक रंग और तीन पॉइंटर्स, शायद]। बहुत सारे चर। –

0

स्विच-केस से जुड़े कई सुझाव हैं। दक्षता के मामले में, यह बेहतर हो सकता है, वही हो सकता है। बदतर नहीं होगा।

लेकिन यदि आप आईडी पर आधारित मूल्य या नाम को बस सेट/वापस कर रहे हैं, तो हाँ। एक नक्शा बिल्कुल वही है जो आपको चाहिए। एसटीएल कंटेनरों को अनुकूलित किया गया है, और यदि आपको लगता है कि आप बेहतर अनुकूलित कर सकते हैं, तो आप या तो अविश्वसनीय रूप से स्मार्ट या चौंकाने वाली गूंगा हैं। क्योंकि यह आईडी की संख्या बढ़ जाती के रूप में और अधिक कुशल है

उदाहरण, एक एकल कॉल एक std :: नक्शा mymap कहा जाता है का उपयोग कर,

thisvar = mymap[x.getID()]; 

इन

if(x.getID() == ...){thisvar = ...;} 

के 50 की तुलना में बेहतर है। यदि आप रुचि रखते हैं, तो डेटा संरचनाओं पर एक अच्छा प्राइमर खोजें।

लेकिन जो मैं वास्तव में यहां देखता हूं वह रखरखाव/फिक्सिंग समय है। यदि आपको चर के नाम को बदलने की आवश्यकता है, या getID() या getName() का उपयोग करने से बदलना है, या किसी प्रकार का मामूली परिवर्तन करना है, तो आपको इसे अपने उदाहरण में फिफ्टी टाइम्स करना होगा। और जब भी आप आईडी जोड़ते हैं तो आपको एक नई लाइन की आवश्यकता होती है।

मानचित्र एक कोड में परिवर्तन को कम करता है कोई बात नहीं कि आपके पास कितनी आईडी हैं।

उसने कहा, यदि आप वास्तव में प्रत्येक आईडी के लिए अलग-अलग कार्रवाइयां कर रहे हैं, तो स्विच-केस बेहतर हो सकता है। कथन के बजाए स्विच-केस के साथ, आप प्रदर्शन और पठनीयता में सुधार कर सकते हैं। यहां देखें: Advantage of switch over if-else statement मैं पॉइंटर्स से फ़ंक्शंस से बचूंगा जबतक कि आप इस बात पर बहुत स्पष्ट नहीं हैं कि वे आपके कोड को कैसे सुधारेंगे, क्योंकि यदि आप 100% निश्चित नहीं हैं कि आप क्या कर रहे हैं, तो वाक्यविन्यास को गड़बड़ कर दिया जा सकता है, और यह किसी भी चीज के लिए अधिक है जो आप संभवतः एक मानचित्र का उपयोग करेंगे।

असल में, मुझे उस समस्या में रुचि होगी जो आप हल करने का प्रयास कर रहे हैं। आप मानचित्र या स्विच-केस के साथ बेहतर हो सकते हैं, लेकिन अगर आपको लगता है कि आप मानचित्र का उपयोग कर सकते हैं, तो यह बिल्कुल सही है कि आपको इसके बजाय क्या उपयोग करना चाहिए।

संबंधित मुद्दे