Я хочу использовать структуру данных очереди в моей программе 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заранее, чтобы проверить, есть ли какие-либо объекты для удаления из очереди. На самом деле это вопрос предпочтений.