Objective-Cプログラムでキューデータ構造を使用したい。 C++では、STLキューを使用します。 Objective-Cの同等のデータ構造は何ですか?アイテムをプッシュ/ポップするにはどうすればよいですか?
Benのバージョンはキューではなくスタックなので、少し調整しました。
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メソッドと同じように呼び出します。
頑張ってコーディングしてください!
NSMutableArrayを使用することが必ずしもbestソリューションであるとは言いません。メソッド名が衝突します。 quick-n-dirtyキューの場合、メソッドを使用して、可変配列の最後に追加および削除します。ただし、キューを再利用する場合、またはコードをより読みやすく、自明にする場合は、おそらく専用のキュークラスが必要です。
Cocoaには組み込みのものはありませんが、他のオプションがあり、最初から作成する必要もありません。両端のみを追加および削除する真のキューの場合、循環バッファー配列は非常に高速な実装です。 CHDataStructures.framework 、私が取り組んできたObjective-Cのライブラリ/フレームワークをチェックしてください。スタック、デキュー、ソートされたセットなどだけでなく、キューのさまざまな実装があります。目的のために、 CHCircularBufferQueue は、 NSMutableArrayを使用します。
C++ STLクラスの代わりにネイティブのObjective-Cクラスを使用することの1つの大きな利点は、Cocoaコードとシームレスに統合され、エンコード/デコード(シリアル化)ではるかに優れた動作をすることです。また、ガベージコレクションと高速列挙(両方とも10.5以降に存在しますが、iPhoneには後者のみ)でも完全に動作し、Objective-CオブジェクトとC++オブジェクトとは何であるかを心配する必要はありません。
最後に、NSMutableArrayは標準のC配列よりも両端で追加および削除する場合に優れていますが、キューの最速のソリューションではありません。ほとんどのアプリケーションでは十分ですが、速度が必要な場合は、循環バッファー(または場合によってはキャッシュラインをホットに保つために最適化されたリンクリスト)でNSMutableArrayを簡単に切り捨てることができます。
私の知る限り、Objective-CはQueueデータ構造を提供していません。最善の策は、NSMutableArray
を作成してから[array lastObject]
、[array removeLastObject]
でアイテムを取得し、[array insertObject:o atIndex:0]
...
これを頻繁に行う場合は、Objective-Cカテゴリを作成して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
実際のキューコレクションクラスはありませんが、NSMutableArrayを使用して事実上同じことを行うことができます。 category を定義して、必要に応じて便利にpop/Pushメソッドを追加できます。
はい、NSMutableArrayを使用します。 NSMutableArrayは実際には 実装済み 2-3ツリーとして。通常、任意のインデックスでNSMutableArrayにオブジェクトを追加または削除するパフォーマンス特性を気にする必要はありません。
re:Wolfcow-以下はWolfcowのdequeueメソッドの修正された実装です
- (id)dequeue {
if ([self count] == 0) {
return nil;
}
id queueObject = [[[self objectAtIndex:0] retain] autorelease];
[self removeObjectAtIndex:0];
return queueObject;
}
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
これが私の実装であり、役立つことを願っています。
一種のミニマリストなので、ポップ時に新しいヘッドを保存し、古いヘッドを破棄して、ヘッドの追跡を維持する必要があります
@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
STLキューだけを使用できない特定の理由はありますか? Objective C++はC++のスーパーセットです(Objective Cの代わりにObjective C++を使用するには、.mの代わりに.mmを拡張子として使用します)。その後、STLまたはその他のC++コードを使用できます。
Objective CオブジェクトでSTLキュー/ベクター/リストなどを使用する場合の問題の1つは、メモリ管理の保持/解放/自動解放が通常サポートされないことです。これは、構築時にObjective Cオブジェクトを保持し、破棄時に解放するC++ Smart Pointerコンテナクラスで簡単に回避できます。 STLキューに入れる内容によっては、これは必要ないことがよくあります。
NSMutableArrayを使用します。