Я хочу использовать структуру данных очереди в моей программе Objective-C. В С++ я бы использовал очередь STL. Какова эквивалентная структура данных в Objective-C? Как я могу нажимать/постить элементы?
Как создать и использовать очередь в Objective-C?
Ответ 1
Версия 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.
Удачи и продолжайте кодирование!
Ответ 2
Я бы не сказал, что использование NSMutableArray обязательно является лучшим решением, особенно если вы добавляете методы с категориями из-за хрупкости, которую они могут вызвать, если сталкиваются имена методов. Для быстрой n-грязной очереди я бы использовал методы для добавления и удаления в конце изменяемого массива. Однако, если вы планируете повторно использовать очередь, или если вы хотите, чтобы ваш код был более читабельным и само собой разумеющимся, выделенный класс очереди, вероятно, вы хотите.
Cocoa не имеет встроенного, но есть и другие варианты, и вам не нужно писать один с нуля. Для истинной очереди, которая только добавляет и удаляет из концов, круглый буферный массив является чрезвычайно быстрой реализацией. Проверьте CHDataStructures.framework, библиотеку/фреймворк в Objective-C, над которой я работаю. Он имеет множество реализаций очередей, а также стеки, декорации, сортированные наборы и т.д. Для ваших целей CHCircularBufferQueue выполняется значительно быстрее (т.е. доказуемый с помощью тестов) и более читаемым (по общему признанию субъективным), чем использование NSMutableArray.
Одним из больших преимуществ использования собственного класса Objective-C вместо класса С++ STL является то, что он легко интегрируется с кодом Cocoa и работает намного лучше с кодированием/декодированием (сериализация). Он также отлично работает с сборкой мусора и быстрым перечислением (оба присутствуют в 10.5+, но только последние на iPhone), и вам не нужно беспокоиться о том, что представляет собой объект Objective-C и что такое объект С++.
Наконец, хотя NSMutableArray лучше, чем стандартный массив C при добавлении и удалении с любого конца, это также не самое быстрое решение для очереди. Для большинства приложений это удовлетворительно, но если вам нужна скорость, круговой буфер (или, в некоторых случаях, связанный список, оптимизированный для сохранения горячих линий кэша), может легко запустить NSMutableArray.
Ответ 3
Насколько я знаю, Objective-C не предоставляет структуру данных очереди. Лучше всего создать 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
Ответ 4
Нет никакого реального набора коллекций очередей, но NSMutableArray можно использовать для эффективного использования того же самого. Вы можете определить категорию, чтобы добавить методы pop/push в удобное для вас время.
Ответ 5
Да, используйте NSMutableArray. NSMutableArray фактически реализован как 2-3 дерева; вам обычно не нужно заботиться о характеристиках производительности добавления или удаления объектов из NSMutableArray при произвольных индексах.
Ответ 6
re: Wolfcow - Вот исправленная реализация метода Wolfque dequeue
- (id)dequeue {
if ([self count] == 0) {
return nil;
}
id queueObject = [[[self objectAtIndex:0] retain] autorelease];
[self removeObjectAtIndex:0];
return queueObject;
}
Ответ 7
Это моя реализация, надеюсь, что это поможет.
Является минимальным, поэтому вы должны следить за головой, сохраняя новую голову в поп и отбрасывая старую голову.
@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
Решения, которые используют категорию на 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
Ответ 9
Используйте NSMutableArray.
Ответ 10
Есть ли какая-то конкретная причина, по которой вы не можете просто использовать очередь STL? Objective С++ - это надмножество С++ (просто используйте .mm как расширение вместо .m, чтобы использовать Objective С++ вместо Objective C). Затем вы можете использовать STL или любой другой код на С++.
Одной из проблем использования очереди STL/вектора/списка и т.д. с объектами Objective C является то, что они обычно не поддерживают управление памятью/выпуском/автономной памятью. Это легко обрабатывается с помощью класса контейнера С++ Smart Pointer, который сохраняет объект Objective C при его создании и освобождает его при его уничтожении. В зависимости от того, что вы помещаете в очередь STL, это часто не требуется.