Objective-C 프로그램에서 큐 데이터 구조를 사용하고 싶습니다. C ++에서는 STL 큐를 사용합니다. Objective-C에서 동등한 데이터 구조는 무엇입니까? 항목을 푸시 / 팝은 어떻게합니까?
Objective-C 프로그램에서 큐 데이터 구조를 사용하고 싶습니다. C ++에서는 STL 큐를 사용합니다. Objective-C에서 동등한 데이터 구조는 무엇입니까? 항목을 푸시 / 팝은 어떻게합니까?
답변:
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 메서드처럼 호출하면됩니다.
행운을 빕니다. 코딩을 계속하세요!
나는 NSMutableArray를 사용하는 것이 반드시 최선의 해결책 이라고 말하지 않을 것입니다 . 특히 메서드 이름이 충돌 할 경우 발생할 수있는 취약성 때문에 범주가있는 메서드를 추가하는 경우 특히 그렇습니다. 빠르고 더러운 대기열의 경우 변경 가능한 배열의 끝에 추가하고 제거하는 메서드를 사용합니다. 그러나 큐를 재사용 할 계획이거나 코드를 더 읽기 쉽고 자명하게 만들고 싶다면 전용 큐 클래스를 사용하는 것이 좋습니다.
Cocoa에는 내장 된 옵션이 없지만 다른 옵션이 있으며 처음부터 작성할 필요가 없습니다. 끝에서 추가 및 제거 만하는 진정한 큐의 경우 원형 버퍼 배열은 매우 빠른 구현입니다. 제가 작업해온 Objective-C의 라이브러리 / 프레임 워크 인 CHDataStructures.framework를 확인하세요 . 스택, 데크, 정렬 된 세트 등의 다양한 큐 구현이 있습니다. 사용자의 목적을 위해 CHCircularBufferQueue 는 NSMutableArray를 사용하는 것보다 훨씬 빠르고 (즉, 벤치 마크로 입증 가능) 더 읽기 쉽고 (주관적 임) 더 읽기 쉽습니다 .
C ++ STL 클래스 대신 네이티브 Objective-C 클래스를 사용하는 한 가지 큰 장점은 Cocoa 코드와 원활하게 통합되고 인코딩 / 디코딩 (직렬화)에서 훨씬 더 잘 작동한다는 것입니다. 또한 가비지 수집 및 빠른 열거 (둘 다 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는 효과적으로 동일한 작업에 사용할 수 있습니다. 원하는 경우 편리하게 팝 / 푸시 메서드를 추가 하는 범주 를 정의 할 수 있습니다 .
예, 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 ++의 상위 집합입니다 (Objective C 대신 Objective C ++를 사용하려면 .m 대신 .mm을 확장자로 사용). 그런 다음 STL 또는 다른 C ++ 코드를 사용할 수 있습니다.
Objective C 개체와 함께 STL 큐 / 벡터 / 목록 등을 사용하는 한 가지 문제는 일반적으로 유지 / 해제 / 자동 해제 메모리 관리를 지원하지 않는다는 것입니다. 이는 생성시 Objective C 개체를 유지하고 파괴시 해제하는 C ++ 스마트 포인터 컨테이너 클래스로 쉽게 해결할 수 있습니다. STL 대기열에 넣는 내용에 따라 이것은 종종 필요하지 않습니다.
-count
대기열에서 제거 할 개체가 있는지 미리 전화를 걸어 확인할 수 있습니다 . 정말 선호도의 문제입니다.