Tôi muốn sử dụng cấu trúc dữ liệu hàng đợi trong chương trình Objective-C của mình. Trong C ++, tôi sẽ sử dụng hàng đợi STL. Cấu trúc dữ liệu tương đương trong Objective-C là gì? Làm cách nào để đẩy / bật các mục?
Tôi muốn sử dụng cấu trúc dữ liệu hàng đợi trong chương trình Objective-C của mình. Trong C ++, tôi sẽ sử dụng hàng đợi STL. Cấu trúc dữ liệu tương đương trong Objective-C là gì? Làm cách nào để đẩy / bật các mục?
Câu trả lời:
Phiên bản của Ben là một ngăn xếp thay vì một hàng đợi, vì vậy tôi đã chỉnh sửa nó một chút:
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
Chỉ cần nhập tệp .h vào bất kỳ nơi nào bạn muốn sử dụng các phương thức mới của mình và gọi chúng như cách bạn thực hiện với bất kỳ phương thức NSMutableArray nào khác.
Chúc may mắn và Tiếp tục Mã hóa!
Tôi sẽ không nói rằng sử dụng NSMutableArray nhất thiết phải là giải pháp tốt nhất , đặc biệt nếu bạn đang thêm các phương thức với các danh mục, do tính dễ vỡ mà chúng có thể gây ra nếu các tên phương thức xung đột. Đối với một hàng đợi nhanh-n-dơ, tôi sẽ sử dụng các phương pháp để thêm và xóa ở cuối một mảng có thể thay đổi. Tuy nhiên, nếu bạn định sử dụng lại hàng đợi hoặc nếu bạn muốn mã của mình dễ đọc hơn và hiển thị rõ ràng hơn, một lớp hàng đợi chuyên dụng có thể là thứ bạn muốn.
Cocoa không được tích hợp sẵn, nhưng có những tùy chọn khác và bạn cũng không cần phải viết từ đầu. Đối với một hàng đợi thực sự chỉ thêm và bớt từ cuối, mảng đệm tròn là một cách triển khai cực kỳ nhanh chóng. Kiểm tra CHDataStructures.framework , một thư viện / khuôn khổ trong Objective-C mà tôi đang làm việc. Nó có nhiều cách triển khai hàng đợi, cũng như ngăn xếp, deques, tập hợp được sắp xếp, v.v. Đối với mục đích của bạn, CHCircularBufferQueue nhanh hơn đáng kể (nghĩa là có thể cung cấp với điểm chuẩn) và dễ đọc hơn (thừa nhận là chủ quan) so với việc sử dụng NSMutableArray.
Một lợi thế lớn của việc sử dụng lớp Objective-C gốc thay vì lớp C ++ STL là nó tích hợp liền mạch với mã Cocoa và hoạt động tốt hơn nhiều với mã hóa / giải mã (tuần tự hóa). Nó cũng hoạt động hoàn hảo với tính năng thu thập rác và liệt kê nhanh (cả hai đều có trong 10.5+, nhưng chỉ có trên iPhone) và bạn không phải lo lắng về đối tượng Objective-C và đối tượng C ++ là gì.
Cuối cùng, mặc dù NSMutableArray tốt hơn một mảng C tiêu chuẩn khi thêm và xóa từ hai đầu, nó cũng không phải là giải pháp nhanh nhất cho một hàng đợi. Đối với hầu hết các ứng dụng, điều đó là thỏa đáng, nhưng nếu bạn cần tốc độ, một bộ đệm tròn (hoặc trong một số trường hợp là danh sách liên kết được tối ưu hóa để giữ cho các dòng bộ nhớ cache luôn nóng) có thể dễ dàng gặp trục trặc NSMutableArray.
Theo như tôi biết, Objective-C không cung cấp cấu trúc dữ liệu hàng đợi. Đặt cược tốt nhất của bạn là tạo NSMutableArray
, sau đó sử dụng [array lastObject]
, [array removeLastObject]
để tìm nạp mục và [array insertObject:o atIndex:0]
...
Nếu bạn đang làm điều này nhiều, bạn có thể muốn tạo một danh mục Objective-C để mở rộng chức năng của NSMutableArray
lớp. Danh mục cho phép bạn thêm động các chức năng vào các lớp hiện có (ngay cả những lớp bạn không có nguồn) - bạn có thể tạo một hàng đợi như thế này:
(LƯU Ý: Mã này thực sự dành cho ngăn xếp, không phải hàng đợi. Xem nhận xét bên dưới)
@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
Không có lớp tập hợp hàng đợi thực sự, nhưng NSMutableArray có thể được sử dụng cho hiệu quả tương tự. Bạn có thể xác định một danh mục để thêm các phương thức pop / push nếu bạn muốn.
Có, sử dụng NSMutableArray. NSMutableArray thực sự được thực hiện dưới dạng cây 2-3; bạn thường không cần quan tâm đến các đặc điểm hiệu suất của việc thêm hoặc xóa các đối tượng khỏi NSMutableArray tại các chỉ mục tùy ý.
Các giải pháp sử dụng một danh mục trên NSMutableArray
không phải là hàng đợi đúng, bởi vìNSMutableArray
hiển thị các hoạt động là một tập hợp các hàng đợi. Ví dụ: bạn không được phép xóa một mục ở giữa hàng đợi (vì các giải pháp danh mục đó vẫn cho phép bạn làm). Tốt nhất là đóng gói chức năng, một nguyên tắc chính của thiết kế hướng đối tượng.
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
đây là cách thực hiện của tôi, hy vọng nó sẽ hữu ích.
Là một loại tối giản, vì vậy bạn phải theo dõi phần đầu bằng cách lưu phần đầu mới và loại bỏ phần đầu cũ
@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
Có lý do cụ thể nào khiến bạn không thể chỉ sử dụng hàng đợi STL không? Objective C ++ là một tập hợp siêu của C ++ (chỉ cần sử dụng .mm làm phần mở rộng thay vì .m để sử dụng Objective C ++ thay vì Objective C). Sau đó, bạn có thể sử dụng STL hoặc bất kỳ mã C ++ nào khác.
Một vấn đề khi sử dụng hàng đợi STL / vector / danh sách, v.v. với các đối tượng Objective C là chúng thường không hỗ trợ quản lý bộ nhớ giữ lại / phát hành / tự động khôi phục. Điều này có thể dễ dàng làm được với một lớp chứa C ++ Smart Pointer, lớp này giữ lại đối tượng Objective C của nó khi được xây dựng và giải phóng nó khi bị phá hủy. Tùy thuộc vào những gì bạn đang đặt trong hàng đợi STL, điều này thường không cần thiết.
-count
trước để kiểm tra xem có bất kỳ đối tượng nào cần hủy không. Đó là vấn đề sở thích, thực sự.