मैं उद्देश्य-सी में एक पंक्ति कैसे बनाऊं और उसका उपयोग करूं?


107

मैं अपने उद्देश्य-सी कार्यक्रम में एक कतार डेटा संरचना का उपयोग करना चाहता हूं। C ++ में मैं STL कतार का उपयोग करूँगा। ऑब्जेक्टिव-सी में समतुल्य डेटा संरचना क्या है? मैं पुश / पॉप आइटम कैसे करूं?

जवाबों:


153

बेन का संस्करण एक कतार के बजाय एक स्टैक है, इसलिए मैंने इसे थोड़ा ट्विक किया:

NSMutableArray + QueueAdditions.h

@interface NSMutableArray (QueueAdditions)
- (id) dequeue;
- (void) enqueue:(id)obj;
@end

NSMutableArray + QueueAdditions.m

@implementation NSMutableArray (QueueAdditions)
// Queues are first-in-first-out, so we remove objects from the head
- (id) dequeue {
    // if ([self count] == 0) return nil; // to avoid raising exception (Quinn)
    id headObject = [self objectAtIndex:0];
    if (headObject != nil) {
        [[headObject retain] autorelease]; // so it isn't dealloc'ed on remove
        [self removeObjectAtIndex:0];
    }
    return headObject;
}

// Add to the tail of the queue (no one likes it when people cut in line!)
- (void) enqueue:(id)anObject {
    [self addObject:anObject];
    //this method automatically adds to the end of the array
}
@end

जहाँ भी आप अपने नए तरीकों का उपयोग करना चाहते हैं, केवल .h फ़ाइल आयात करें, और उन्हें किसी अन्य NSMutableArray विधियों की तरह कॉल करें।

गुड लक और कोडिंग पर रहो!


1
मैंने एक टिप्पणी की-लाइन को उन लोगों के लिए dequeue की शुरुआत में जोड़ा, जो खाली कतार से हटने की कोशिश करते समय एक अपवाद को बढ़ाने के बजाय शून्य पर लौटना चाहते हैं। IMO, एक अपवाद को बढ़ाने के NSMutableArray व्यवहार के बाद कोको के साथ अधिक सुसंगत है। आखिरकार, आप यह -countजांचने के लिए पहले से कॉल कर सकते हैं कि क्या कोई वस्तुओं को नष्ट करना है। यह वास्तव में वरीयता की बात है।
क्विन टेलर

2
मैंने इस कोड को एक गितुब रेपो में जोड़ा है। बेझिझक फोर्क या मुझे बताएं कि क्या मैंने कुछ गलत किया है: github.com/esromneb/ios-queue-queject धन्यवाद !!!
portforwardpodcast

2
क्या मुझे कुछ याद आ रहा है, या क्या इस कार्यान्वयन में हे (एन) की जटिलता है? वह भयानक है। आप एक परिपत्र सरणी कार्यान्वयन के साथ बहुत बेहतर होंगे। यह क्रियान्वयन कार्य कर सकता है, लेकिन O (n) के विचार में पीड़ा है।
ThatGuy

11
जब आप किसी ऑब्जेक्ट को इंडेक्स 0 से हटाते हैं, तो वोल्फकैश जावा, ऐरे में प्रत्येक ऑब्जेक्ट को एक में बदल दिया जाता है। इसलिए, किसी एक आइटम को निकालने के लिए, यह O (n) है। संभवतः छोटी कतारों के लिए ठीक है, जो कि संभवतः मोबाइल अनुप्रयोगों में 99% समय है, लेकिन यह समय-गंभीर परिस्थितियों में बड़े डेटा सेटों के लिए एक भयानक समाधान होगा। फिर, ऐसा नहीं है कि आप सबसे अधिक उद्देश्य सी स्थितियों में पाएंगे।
थाट्यू

2
@ThatGuy थोड़ी देर से, लेकिन NSArray एक परिपत्र बफर के साथ कार्यान्वित किया जाता है, इसलिए रनटाइम थीटा (N) नहीं होगा।
hhanesand

33

मैं यह नहीं कहूंगा कि NSMutableArray का उपयोग करना सबसे अच्छा समाधान है, खासकर यदि आप श्रेणियों के साथ तरीकों को जोड़ रहे हैं, तो नाजुकता के कारण यदि वे विधि के नाम से टकराते हैं तो हो सकता है। एक त्वरित-एन-गंदी कतार के लिए, मैं एक परिवर्तनशील सरणी के अंत में जोड़ने और हटाने के तरीकों का उपयोग करूँगा। हालाँकि, यदि आप कतार का पुन: उपयोग करने की योजना बनाते हैं, या यदि आप चाहते हैं कि आपका कोड अधिक पठनीय और स्व-स्पष्ट हो, तो एक समर्पित कतार वर्ग संभवतः वही है जो आप चाहते हैं।

कोको में एक निर्मित नहीं है, लेकिन अन्य विकल्प भी हैं, और आपको स्क्रैच से एक भी लिखना नहीं है। एक सच्ची कतार के लिए जो केवल सिरों को जोड़ता है और हटाता है, एक परिपत्र बफर सरणी एक बहुत तेज़ कार्यान्वयन है। CHDataStructures.framework , ऑब्जेक्ट-सी में एक लाइब्रेरी / फ्रेमवर्क की जाँच करें जो मैं काम कर रहा हूं। इसमें कतारों के कार्यान्वयन के साथ-साथ स्टैक, डेक्स, सॉर्ट किए गए सेट आदि हैं। आपके उद्देश्यों के लिए, CHCircularBufferQueue , NSMutableArray का उपयोग करने की तुलना में काफी तेज (यानी बेंचमार्क के साथ सिद्ध) और अधिक पठनीय (भर्ती व्यक्ति) है।

C ++ STL वर्ग के बजाय एक मूल उद्देश्य-सी कक्षा का उपयोग करने का एक बड़ा फायदा यह है कि यह कोको कोड के साथ मूल रूप से एकीकृत होता है, और एनकोड / डिकोड (क्रमबद्धता) के साथ बहुत बेहतर काम करता है। यह पूरी तरह से कचरा संग्रह और तेजी से संचय (दोनों 10.5+ में मौजूद है, लेकिन केवल iPhone पर उत्तरार्द्ध) के साथ पूरी तरह से काम करता है और आपको इस बारे में चिंता करने की जरूरत नहीं है कि एक वस्तु-सी वस्तु क्या है और सी ++ वस्तु क्या है।

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


2
खुशी है कि किसी ने वास्तव में एक सच्चे कतार समाधान के साथ जवाब दिया
केसबश

सभी लिंक टूट गए हैं - मुझे वह ढांचा कहां से मिलेगा? मैंने इसके बारे में बहुत सारी अच्छी चीजें पढ़ी हैं, लेकिन वास्तविक कोड नहीं मिला!
आपे से बाहर

फ्रेमवर्क आशाजनक लगता है लेकिन एसवीएन के लिंक अभी भी टूटे हुए हैं। कहीं भी कोड प्राप्त करने का कोई मौका? संपादित करें: इसे mac.softpedia.com/progDownload/ से प्राप्त किया है, लेकिन मैं यह नहीं देख सकता कि क्या यह वर्तमान संस्करण है
Kay

डेव देलांग का गिट रेपो क्लोन इन दिनों रेपो के रूप में दिखाई देता है।
Regexident

29

जहाँ तक मुझे पता है, Objective-C एक क्यू डेटा संरचना प्रदान नहीं करता है। तुम्हारा सबसे अच्छा शर्त एक बनाने के लिए है NSMutableArray, और फिर उपयोग [array lastObject], [array removeLastObject]आइटम लाने के लिए, और [array insertObject:o atIndex:0]...

यदि आप ऐसा कर रहे हैं, तो आप NSMutableArrayकक्षा की कार्यक्षमता बढ़ाने के लिए एक उद्देश्य-सी श्रेणी बनाना चाहते हैं । श्रेणियां आपको मौजूदा कक्षाओं में गतिशील रूप से कार्य करने की अनुमति देती हैं (यहां तक ​​कि जिनके लिए आपके पास स्रोत नहीं है) - आप इस तरह से एक कतार बना सकते हैं:

(नोट: यह कोड वास्तव में एक स्टैक के लिए है, एक कतार के लिए नहीं। नीचे टिप्पणी देखें)

@interface NSMutableArray (QueueAdditions)

- (id)pop;
- (void)push:(id)obj;

@end

@implementation NSMutableArray (QueueAdditions)

- (id)pop
{
    // nil if [self count] == 0
    id lastObject = [[[self lastObject] retain] autorelease];
    if (lastObject)
        [self removeLastObject];
    return lastObject;
}

- (void)push:(id)obj
{
     [self addObject: obj];
}

@end

7
क्या आप जानते हैं कि आपने यहां एक स्टैक लागू किया है, न कि एक कतार?
जिम पल्स

आह - क्षमा करें! - नीचे वुल्फिंगकॉइन के संशोधनों को देखें।
बेन गोटोव

अगर आप "बेस्ट बेट" को "सरलतम विकल्प" से बदलते हैं तो मैं सहमत हो जाऊंगा। :-) डेटा संरचना शुद्धतावादी और प्रदर्शन पर्यवेक्षक एक सच्ची कतार पसंद करेंगे, लेकिन एक NSMutableArray आसानी से एक कतार के लिए खड़ा हो सकता है।
क्विन टेलर

3
+1 से बेन क्योंकि मैं एक स्टैक समाधान चाहता था, भले ही एक कतार के लिए कहा गया था :)
व्हाइटनीलैंड

दर्द के बारे में मैं बस यही सोच सकता हूं। आप किसी सरणी के प्रारंभ में एक ऑब्जेक्ट सम्मिलित कर रहे हैं, आपको हर बार डालने पर हर स्थान को 1 स्थान पर कॉपी करना होगा। इस मामले में एक लिंक्ड-लिस्ट बहुत बेहतर प्रदर्शन करेगी।
TheM00s3

8

कोई वास्तविक कतार संग्रह वर्ग नहीं है, लेकिन NSMutableArray का उपयोग प्रभावी रूप से एक ही चीज़ के लिए किया जा सकता है। यदि आप चाहें तो पॉप / पुश विधियों को सुविधा के रूप में जोड़ने के लिए एक श्रेणी को परिभाषित कर सकते हैं।


सच है, एक NSMutableArray एक सुंदर सभ्य कतार बनाता है, हालांकि सामने से हटाने से एक सरणी संरचना एक्सेल में कुछ नहीं है। फिर भी, छोटी कतारों के लिए, प्रदर्शन वैसे भी एक प्रमुख चिंता का विषय नहीं है। मेरे एक मित्र ने कुछ समय पहले इस विषय के बारे में ब्लॉग किया ... sg80bab.blogspot.com/2008/05/…
Quinn Taylor

7

हां, NSMutableArray का उपयोग करें। NSMutableArray वास्तव में 2-3 पेड़ के रूप में लागू किया गया है; आपको आम तौर पर मनमाने सूचकांकों में NSMutableArray से वस्तुओं को जोड़ने या हटाने की प्रदर्शन विशेषताओं के साथ खुद को चिंता करने की आवश्यकता नहीं है।


1
NSArray (और NSMutableArray विस्तार द्वारा) एक वर्ग क्लस्टर है, जिसका अर्थ है कि इसमें कई निजी कार्यान्वयन हैं जो पर्दे के पीछे परस्पर उपयोग किए जा सकते हैं। आप जो प्राप्त करते हैं वह आमतौर पर तत्वों की संख्या पर निर्भर करता है। इसके अलावा, Apple किसी भी समय किसी भी कार्यान्वयन के विवरण को बदलने के लिए स्वतंत्र है। हालाँकि, आप सही हैं कि यह आमतौर पर एक मानक सरणी की तुलना में अधिक लचीला है।
क्विन टेलर

5

पुन: वोल्फगैंगकॉन्ग - यहां वुल्फेंको के डीक्यू पद्धति का एक सही कार्यान्वयन है

- (id)dequeue {
    if ([self count] == 0) {
        return nil;
    }
    id queueObject = [[[self objectAtIndex:0] retain] autorelease];
    [self removeObjectAtIndex:0];
    return queueObject;
}

4

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

StdQueue.h

#import <Foundation/Foundation.h>

@interface StdQueue : NSObject

@property(nonatomic, readonly) BOOL empty;
@property(nonatomic, readonly) NSUInteger size;
@property(nonatomic, readonly) id front;
@property(nonatomic, readonly) id back;

- (void)enqueue:(id)object;
- (id)dequeue;

@end

StdQueue.m

#import "StdQueue.h"

@interface StdQueue ()

@property(nonatomic, strong) NSMutableArray* storage;

@end

@implementation StdQueue

#pragma mark NSObject

- (id)init
{
    if (self = [super init]) {
        _storage = [NSMutableArray array];
    }
    return self;
}

#pragma mark StdQueue

- (BOOL)empty
{
    return self.storage.count == 0;
}

- (NSUInteger)size
{
    return self.storage.count;
}

- (id)front
{
    return self.storage.firstObject;
}

- (id)back
{
    return self.storage.lastObject;
}

- (void)enqueue:(id)object
{
    [self.storage addObject:object];
}

- (id)dequeue
{
    id firstObject = nil;
    if (!self.empty) {
        firstObject  = self.storage.firstObject;
        [self.storage removeObjectAtIndex:0];
    }
    return firstObject;
}

@end

कोई यह तर्क दे सकता है कि कुछ तकनीकों (यानी केवीसी) के साथ आंतरिक भंडारण सरणी को सीधे एक्सेस और हेरफेर किया जा सकता है, लेकिन एक श्रेणी का उपयोग करने से बेहतर है।
vikingosegundo

3

यह मेरा कार्यान्वयन है, आशा है कि यह मदद करेगा।

एक प्रकार का अतिसूक्ष्म है, इसलिए आपको नए सिर को पॉप पर सहेजकर और पुराने सिर को त्यागकर सिर का ट्रैक रखना होगा

@interface Queue : NSObject {
    id _data;
    Queue *tail;
}

-(id) initWithData:(id) data;
-(id) getData;

-(Queue*) pop;
-(void) push:(id) data;

@end

#import "Queue.h"

@implementation Queue

-(id) initWithData:(id) data {
    if (self=[super init]) {
        _data = data;
        [_data retain];
    }
    return self;
}
-(id) getData {
    return _data;
}

-(Queue*) pop {
    return tail;
}
-(void) push:(id) data{
    if (tail) {
        [tail push:data];
    } else {
        tail = [[Queue alloc]initWithData:data];
    }
}

-(void) dealloc {
    if (_data) {
        [_data release];
    }
    [super release];
}

@end

2

क्या कोई विशेष कारण है कि आप एसटीएल कतार का उपयोग नहीं कर सकते हैं? ऑब्जेक्टिव C ++, C ++ का एक सुपरसेट है (केवल उपयोग करें। ऑब्जेक्टिव C के बजाय ऑब्जेक्टिव C ++ का उपयोग करने के लिए .m के बजाय एक्सटेंशन के रूप में उपयोग करें)। फिर आप एसटीएल या किसी अन्य C ++ कोड का उपयोग कर सकते हैं।

उद्देश्य सी वस्तुओं के साथ एसटीएल कतार / वेक्टर / सूची आदि का उपयोग करने का एक मुद्दा यह है कि वे आम तौर पर बनाए रखने / जारी करने / ऑटोरेलिज़ मेमोरी प्रबंधन का समर्थन नहीं करते हैं। यह आसानी से C ++ स्मार्ट पॉइंटर कंटेनर क्लास के साथ काम किया जाता है, जो निर्माण के समय अपनी ऑब्जेक्टिव C ऑब्जेक्ट को बनाए रखता है और नष्ट होने पर उसे छोड़ देता है। आप एसटीएल कतार में क्या डाल रहे हैं, इसके आधार पर यह अक्सर आवश्यक नहीं होता है।


1
यह वास्तव में एक अच्छा विचार नहीं लगता ... सिर्फ इसलिए कि आप कुछ कर सकते हैं इसका मतलब यह नहीं है कि आपको चाहिए। एक कतार वर्ग के लिए पूरे एसटीएल और सी ++ पारिस्थितिकी तंत्र में खींच निश्चित रूप से ओवरकिल है।
एक्सट्रोपिक-इंजन

3
दरअसल, जब से यह पोस्ट किया गया था, यह एक बेहतर विचार बन गया है। ऑब्जेक्टिव C ++ / ARC का मतलब है कि आप STL कंटेनरों को ऑब्जेक्टिव C ऑब्जेक्ट पॉइंटर्स के साथ इस्तेमाल कर सकते हैं और यह सब काम करता है। एआरसी आपके लिए C ++ संरचनाओं के भीतर स्वचालित रूप से मेमोरी प्रबंधन का ख्याल रखता है। मैं आम तौर पर यह भी तर्क दूंगा कि C ++, बहुत बेहतर C होने के नाते, Objective-C ++ को सामान्य ऑब्जेक्टिव C की तुलना में सामान्य रूप में बेहतर विकल्प बनाता है (उदाहरण के लिए enum वर्ग जैसी चीजें देना)। और मुझे बहुत संदेह है कि एसटीएल / सी ++ जोड़ने से किसी भी वास्तविक विश्व ऐप के आकार पर कोई ध्यान देने योग्य प्रभाव पड़ता है।
पीटर एन लुईस

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