Я хочу использовать структуру данных очереди в моей программе Objective-C. В C ++ я бы использовал очередь STL. Какая эквивалентная структура данных в Objective-C? Как мне нажимать / выталкивать предметы?
Я хочу использовать структуру данных очереди в моей программе Objective-C. В C ++ я бы использовал очередь STL. Какая эквивалентная структура данных в Objective-C? Как мне нажимать / выталкивать предметы?
Ответы:
Версия Бена - это стек, а не очередь, поэтому я немного ее изменил:
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 обязательно является лучшим решением, особенно если вы добавляете методы с категориями из-за хрупкости, которую они могут вызвать, если имена методов конфликтуют. Для быстрой и грязной очереди я бы использовал методы добавления и удаления в конце изменяемого массива. Однако, если вы планируете повторно использовать очередь или хотите, чтобы ваш код был более читабельным и очевидным, вам, вероятно, нужен выделенный класс очереди.
Какао не имеет встроенного, но есть и другие варианты, и вам также не нужно писать его с нуля. Для настоящей очереди, которая только добавляет и удаляет с концов, круговой буферный массив является чрезвычайно быстрой реализацией. Ознакомьтесь с CHDataStructures.framework , библиотекой / фреймворком в Objective-C, над которой я работал. Он имеет множество реализаций очередей, а также стеки, двухсторонние очереди, отсортированные наборы и т. Д. Для ваших целей CHCircularBufferQueue значительно быстрее (т.е. доказывается с помощью тестов) и более читабелен (по общему признанию), чем использование NSMutableArray.
Одним из больших преимуществ использования собственного класса Objective-C вместо класса C ++ STL является то, что он легко интегрируется с кодом Какао и намного лучше работает с кодированием / декодированием (сериализацией). Он также отлично работает со сборкой мусора и быстрым перечислением (оба присутствуют в 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 можно эффективно использовать для того же самого. Вы можете определить категорию для добавления методов pop / push для удобства, если хотите.
Да, используйте NSMutableArray. NSMutableArray фактически реализован как 2-3 дерева; вам обычно не нужно беспокоиться о характеристиках производительности при добавлении или удалении объектов из NSMutableArray по произвольным индексам.
Решения, использующие категорию 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 ++ (просто используйте .mm в качестве расширения вместо .m, чтобы использовать Objective C ++ вместо Objective C). Затем вы можете использовать STL или любой другой код C ++.
Одна из проблем использования очереди / вектора / списка STL с объектами Objective C заключается в том, что они обычно не поддерживают управление сохранением / освобождением / автоматическим освобождением памяти. Это легко обойти с помощью класса контейнера C ++ Smart Pointer, который сохраняет свой объект Objective C при создании и освобождает его при уничтожении. В зависимости от того, что вы помещаете в очередь STL, в этом часто нет необходимости.
-count
заранее, чтобы проверить, есть ли какие-либо объекты для удаления из очереди. На самом деле это вопрос предпочтений.