我想在Objective-C程序中使用队列数据结构。在C ++中,我使用STL队列。 Objective-C中的等效数据结构是什么?如何推送/弹出项目?
答案 0 :(得分:153)
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方法一样调用它们。
祝你好运并继续编码!
答案 1 :(得分:32)
我不会说使用NSMutableArray必然是最佳解决方案,特别是如果您要添加类别的方法,因为如果方法名称冲突,它们可能会导致脆弱性。对于快速n-dirty队列,我将使用这些方法在可变数组的末尾添加和删除。但是,如果您计划重用该队列,或者您希望您的代码更具可读性和不言而喻,那么可能就是您想要的专用队列类。
Cocoa没有内置的,但还有其他选项,你也不必从头开始编写。对于仅添加和删除末端的真实队列,循环缓冲区阵列是一种非常快速的实现。查看CHDataStructures.framework,这是我一直在研究的Objective-C中的库/框架。它有各种各样的队列实现,以及堆栈,deques,有序集等。为了您的目的,CHCircularBufferQueue比使用NSMutableArray明显更快(即可用基准测试证明)和更可读(公认的主观)
使用本机Objective-C类而不是C ++ STL类的一大优势是它可以与Cocoa代码无缝集成,并且在编码/解码(序列化)方面效果更好。它也可以完美地处理垃圾收集和快速枚举(两者都存在于10.5+中,但只有后者存在于iPhone上)并且您不必担心什么是Objective-C对象以及什么是C ++对象。
最后,虽然NSMutableArray在从任一端添加和删除时比标准C阵列更好,但它也不是队列中最快的解决方案。对于大多数应用程序来说,它是令人满意的,但是如果你需要速度,循环缓冲区(或者在某些情况下,优化链接列表以保持缓存行热)可以很容易地破坏NSMutableArray。
答案 2 :(得分:29)
据我所知,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
答案 3 :(得分:8)
没有真正的队列集合类,但NSMutableArray可以有效地用于相同的事情。如果需要,您可以定义category以添加pop / push方法。
答案 4 :(得分:7)
是的,使用NSMutableArray。 NSMutableArray实际上是implemented为2-3树;您通常不必关心在任意索引处添加或删除NSMutableArray中的对象的性能特征。
答案 5 :(得分:5)
re:Wolfcow - 这是Wolfcow的出列方法的更正实现
- (id)dequeue {
if ([self count] == 0) {
return nil;
}
id queueObject = [[[self objectAtIndex:0] retain] autorelease];
[self removeObjectAtIndex:0];
return queueObject;
}
答案 6 :(得分: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
答案 7 :(得分:3)
这是我的实施,希望它有所帮助。
有点简约,所以你必须通过将新头保存在pop并保留旧头来保持头部的轨迹
@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
答案 8 :(得分:2)
是否有一些特殊原因你不能只使用STL队列? Objective C ++是C ++的超集(只使用.mm作为扩展而不是.m来使用Objective C ++而不是Objective C)。然后,您可以使用STL或任何其他C ++代码。
对Objective C对象使用STL队列/向量/列表等的一个问题是它们通常不支持保留/释放/自动释放内存管理。这很容易解决C ++ Smart Pointer容器类,它在构造时保留Objective C对象并在销毁时释放它。根据您在STL队列中的内容,通常不需要这样做。
答案 9 :(得分:1)
使用NSMutableArray。