Я хочу використовувати структуру даних черги у своїй програмі 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 - це обов'язково найкраще рішення, особливо якщо ви додаєте методи з категоріями, через крихкість, яку вони можуть спричинити, якщо назви методів стикаються. Для швидкої n-брудної черги я б використав методи додавання та видалення в кінці змінного масиву. Однак, якщо ви плануєте повторно використовувати чергу, або якщо ви хочете, щоб ваш код був більш читабельним і зрозумілим для себе, виділений клас черги - це, мабуть, те, що ви хочете.
У какао немає вбудованого, але є й інші варіанти, і вам також не потрібно писати його з нуля. Для справжньої черги, яка лише додає та видаляє з кінців, круговий буферний масив є надзвичайно швидкою реалізацією. Ознайомтеся з CHDataStructures.framework , бібліотекою / рамкою в Objective-C, над якою я працював. У ньому є різноманітна реалізація черг, а також стеки, деки, відсортовані набори тощо. Для ваших цілей CHCircularBufferQueue значно швидший (тобто доступний з орієнтирами) і більш читабельний (правда, суб'єктивний), ніж використання NSMutableArray.
Однією з головних переваг використання нативного класу Objective-C замість класу ST + C ++ є те, що він безперебійно інтегрується з кодом Какао і працює набагато краще з кодування / декодування (серіалізація). Він також чудово працює зі збиранням сміття та швидким перерахуванням (обидва присутні в 10.5+, але лише останні на iPhone), і вам не потрібно турбуватися про те, що є об'єктом Objective-C, а що - об'єктом C ++.
Нарешті, хоча NSMutableArray кращий, ніж стандартний масив C при додаванні та видаленні з будь-якого кінця, це також не найшвидше рішення для черги. Для більшості застосунків це задовільно, але якщо вам потрібна швидкість, круговий буфер (або в деяких випадках зв'язаний список, оптимізований для збереження гарячих ліній кеш-пам'яті), може легко пошкодити NSMutableArray.
Наскільки мені відомо, 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
Немає реального класу колекцій черг, але NSMutableArray можна використовувати для ефективного того ж самого. Ви можете визначити категорію, щоб додати поп / 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? Ціль C ++ - це супернабір C ++ (просто використовуйте .mm як розширення замість .m для використання Objective C ++ замість Objective C). Тоді ви можете використовувати STL або будь-який інший код C ++.
Одне з питань використання черги / вектору / списку STL тощо з об’єктами Objective C полягає в тому, що вони, як правило, не підтримують управління пам'яттю збереження / випуску / автовивільнення. Це легко обійти з контейнером класу контейнерів Smart + Point C ++, який зберігає об'єкт Objective C при його створенні та випускає при знищенні. Залежно від того, що ви ставите в чергу STL, це часто не є необхідним.
-count
заздалегідь зателефонувати, щоб перевірити, чи є якісь об’єкти для видалення. Це питання справді.