iOS 开发每天分享优质文章

数据结构与算法之队列(五)

2019-05-14  本文已影响105人  路飞_Luck
目录
  • 队列简介
  • 队列的接口设计
  • 用栈实现队列
  • 双端队列实现
  • 循环队列实现
  • 循环双端队列
一 简介

队列是一种特殊的线性表,只能在头尾两端进行操作

image.png
二 队列的接口设计

队列的内部实现是否可以直接使用之前学过的数据结构?

优先使用双向链表,因为队列主要是往头尾操作元素

核心代码如下

@implementation Queue {
    LinkedList *_linkList;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _linkList = [[LinkedList alloc] init];
    }
    return self;
}

/// 元素的数量
- (int)size {
    return _linkList.size;
}

/// 是否为空
- (BOOL)isEmpty {
    return [_linkList isEmpty];
}

/// 清空
- (void)clear {
    [_linkList clear];
}

/// 入队
- (void)enQueue:(id)element {
    [_linkList add:element];
}

/// 出队
- (id)deQueue {
    return [_linkList remove:0];
}

/// 获取队列的头元素
- (id)front {
    return [_linkList get:0];
}
/// queue test
- (void)queueTest {
    Queue *qu = [[Queue alloc] init];
    [qu enQueue:@(11)];
    [qu enQueue:@(22)];
    [qu enQueue:@(33)];
    [qu enQueue:@(44)];
    
    while (!qu.isEmpty) {
        NSLog(@"%@",[qu deQueue]);
    }
}

运行结果

队列.png
三 用栈实现队列
232. 用栈实现队列

思路:
准备两个栈:inStack,outStack

image.png

核心代码如下

@implementation QueueStack {
    Stack *_inStack;
    Stack *_outStack;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _inStack = [[Stack alloc] init];
        _outStack = [[Stack alloc] init];
    }
    return self;
}

/// 元素的数量
- (int)size {
    return _inStack.size + _outStack.size;
}

/// 是否为空
- (BOOL)isEmpty {
    return _inStack.isEmpty && _outStack.isEmpty;
}

/// 清空
- (void)clear {
    while (_inStack.top) {
        [_inStack pop];
    }
    while (_outStack.top) {
        [_outStack pop];
    }
}

/// 入队
- (void)enQueue:(id)element {
    [_inStack push:element];
}

/// 出队
- (id)deQueue {
    if (!_outStack.isEmpty) {
        return [_outStack pop];
    }
    while (_inStack.top) {  // 将inStack的元素全部压入outStack
        [_outStack push:[_inStack pop]];
    }
    // 再弹出outStack栈顶元素
    return [_outStack pop];
}

/// 获取队列的头元素
- (id)front {
    if (!_outStack.isEmpty) {
        return _outStack.top;
    }
    while (_inStack.top) {  // 将inStack的元素全部压入outStack
        [_outStack push:[_inStack pop]];
    }
    // 再弹出outStack栈顶元素
    return _outStack.top;
}

@end
// 用栈实现队列操作
- (void)queueStackTest {
    Queue *qu = [[Queue alloc] init];
    [qu enQueue:@(11)];
    [qu enQueue:@(22)];
    [qu deQueue];
    [qu enQueue:@(33)];
    [qu deQueue];
    
    while (!qu.isEmpty) {
        NSLog(@"%@",[qu deQueue]);
    }
}

运行结果

栈实现队列.png
四 双端队列(double ended queue - Deque)

双端队列是能在头尾两端添加删除的队列

接口设计

/// 元素的数量
- (int)size;

/// 是否为空
- (BOOL)isEmpty;

/// 清空
- (void)clear;

/// 从后面入队
- (void)enQueueRear:(id)element;

/// 从后面出队
- (id)deQueueRear;

/// 从前面入队
- (void)enQueueFront:(id)element;

/// 从前面出队
- (id)deQueueFront;

/// 获取队列的头元素
- (id)front;

/// 获取队列的尾元素
- (id)rear;
@implementation Deque {
    LinkedList *_linkList;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _linkList = [[LinkedList alloc] init];
    }
    return self;
}

/// 元素的数量
- (int)size {
    return _linkList.size;
}

/// 是否为空
- (BOOL)isEmpty {
    return _linkList.isEmpty;
}

/// 清空
- (void)clear {
    [_linkList clear];
}

/// 从后面入队
- (void)enQueueRear:(id)element {
    [_linkList add:element];
}

/// 从后面出队
- (id)deQueueRear {
    return [_linkList remove:_linkList.size - 1];
}

/// 从前面入队
- (void)enQueueFront:(id)element {
    [_linkList add:0 element:element];
}

/// 从前面出队
- (id)deQueueFront {
    return [_linkList remove:0];
}

/// 获取队列的头元素
- (id)front {
    return [_linkList get:0];
}

/// 获取队列的尾元素
- (id)rear {
    return [_linkList get:_linkList.size - 1];
}

@end
//  双端队列
- (void)deQueueTest {
    Deque *qu = [[Deque alloc] init];
    [qu enQueueFront:@(11)];
    [qu enQueueFront:@(22)];
    [qu enQueueRear:@(33)];
    [qu enQueueRear:@(44)];
    
    /**  尾 44 33 11 22 */
    while (!qu.isEmpty) {
        NSLog(@"%@",[qu deQueueRear]);
    }
}

运行结果如下:

双端队列.png

更多详细代码查看Deque

五 循环队列(Circle Queue)

用数组实现并且优化之后的队列称之为循环队列

循环队列.png

循环双端队列:可以进行两端添加,删除操作的循环队列

static int kDefaultCapacity = 10;   // 默认元素个数

@implementation CircleQueue {
    int _front;
    int _size;
    NSMutableArray *_elements;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _elements = [NSMutableArray array];
        for (int i = 0; i < kDefaultCapacity; i++) {
            [_elements addObject:@(-1)];
        }
    }
    return self;
}

/// 元素的数量
- (int)size {
    return _size;
}

/// 是否为空
- (BOOL)isEmpty {
    return _size == 0;
}

/// 清空
- (void)clear {
    [_elements removeAllObjects];
    _front = 0;
    _size = 0;
}

/// 入队
- (void)enQueue:(id)element {
    [self ensureCapacity:_size + 1];
    
    int index = [self getIndex:_size];
    _elements[index] = element;
    _size++;
}

/// 出队
- (id)deQueue {
    id frontElement = _elements[_front];
    _elements[_front] = @(-1);    // 头节点位置置空
    _front = [self getIndex:1];
    _size--;
    return frontElement;
}

/// 获取队列的头元素
- (id)front {
    return _elements[_front];
}

- (NSString *)description {
    NSMutableString *strM = [NSMutableString string];
    [strM appendString:[NSString stringWithFormat:@"capcacity = %lu,",(unsigned long)_elements.count]];
    [strM appendString:[NSString stringWithFormat:@"size = %d,",_size]];
    [strM appendString:[NSString stringWithFormat:@"front = %d,",_front]];
    [strM appendString:@", ["];
    
    for (int i = 0; i < _elements.count; i++) {
        if (i != 0) {
            [strM appendString:@","];
        }
        [strM appendFormat:@"%@",_elements[i]];
    }
    [strM appendString:@"]"];
    return strM.copy;
}

#pragma mark - private

- (int)getIndex:(int)index {
    // 因为一直在循环,所以需要取模
    index += _front;    // 先加上头位置索引
    
    // 返回正确插入位置索引
    return index - (index >= _elements.count ? _elements.count : 0);
}

/** 保证要有capacity的容量 */
- (void)ensureCapacity:(int)capacity {
    NSInteger oldCapactity = _elements.count;
    if (oldCapactity >= capacity) {
        return;
    }
    
    // 新容量为旧容量的1.5倍
    int newCapacity = oldCapactity + oldCapactity * 0.5;
    NSMutableArray *newElements = [NSMutableArray array];
    for (int i = 0; i < newCapacity; i++) {
        [newElements addObject:@(-1)];
    }
    // 恢复旧值
    for (int i = 0; i < _size; i++) {
        newElements[i] = _elements[i];
    }
    _elements = newElements;
    
    // 重置front
    _front = 0;
}

@end
// 循环队列测试
- (void)circleQueueTest {
    CircleQueue *queue = [[CircleQueue alloc] init];
    // 0 1 2 3 4 5 6 7 8 9
    for (int i = 0; i < 10; i++) {
        [queue enQueue:@(i)];
    }
    NSLog(@"%@",[queue description]);
    
    // null null null null null 5 6 7 8 9
    for (int i = 0; i < 5; i++) {
        [queue deQueue];
    }
    NSLog(@"%@",[queue description]);
    
    // 15 16 17 18 19 5 6 7 8 9
    for (int i = 15; i < 20; i++) {
        [queue enQueue:@(i)];
    }
    NSLog(@"%@",[queue description]);
    
    while (!queue.isEmpty) {
        NSLog(@"%@",queue.deQueue);
    }
    
    NSLog(@"%@",[queue description]);
}

运行结果如下:

image.png

注意几个方法的实现

/// 获取真正插入位置的索引
- (int)getIndex:(int)index;

/** 保证要有capacity的容量 */
- (void)ensureCapacity:(int)capacity;

更多详细代码查看CircleQueue

六 循环双端队列
static int kDefaultCapacity = 10;   // 默认元素个数

@implementation CircleDeque {
    int _front;
    int _size;
    NSMutableArray *_elements;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _elements = [NSMutableArray array];
        for (int i = 0; i < kDefaultCapacity; i++) {
            [_elements addObject:@(-1)];
        }
    }
    return self;
}

/// 元素的数量
- (int)size {
    return _size;
}

/// 是否为空
- (BOOL)isEmpty {
    return _size == 0;
}

/// 清空
- (void)clear {
    [_elements removeAllObjects];
    _front = 0;
    _size = 0;
}

/// 从后面入队
- (void)enQueueRear:(id)element {
    [self ensureCapacity:_size + 1];
    
    int index = [self getIndex:_size];
    _elements[index] = element;
    _size++;
}

/// 从后面出队
- (id)deQueueRear {
    int rearIndex = [self getIndex:_size - 1];
    id rearElement = _elements[rearIndex];
    _elements[rearIndex] = @(-1);    // 头节点位置置空
    _size--;
    return rearElement;
}

/// 从头部入队
- (void)enQueueFront:(id)element {
    [self ensureCapacity:_size + 1];
    
    _front = [self getIndex:-1];
    _elements[_front] = element;
    _size++;
}

/// 从头部出队
- (id)deQueueFront {
    id frontElement = _elements[_front];
    _elements[_front] = @(-1);    // 头节点位置置空
    _front = [self getIndex:1];
    _size--;
    return frontElement;
}

/// 获取队列的头元素
- (id)front {
    return _elements[_front];
}

/// 获取队列的尾元素
- (id)rear {
    int index = [self getIndex:_size - 1];
    return _elements[index];
}

- (NSString *)description {
    NSMutableString *strM = [NSMutableString string];
    [strM appendString:[NSString stringWithFormat:@"capcacity = %lu,",(unsigned long)_elements.count]];
    [strM appendString:[NSString stringWithFormat:@"size = %d,",_size]];
    [strM appendString:[NSString stringWithFormat:@"front = %d,",_front]];
    [strM appendString:@", ["];
    
    for (int i = 0; i < _elements.count; i++) {
        if (i != 0) {
            [strM appendString:@","];
        }
        [strM appendFormat:@"%@",_elements[i]];
    }
    [strM appendString:@"]"];
    return strM.copy;
}

#pragma mark - private

/// 获取真正插入位置的索引
- (int)getIndex:(int)index {
    // 因为一直在循环,所以需要取模
    index += _front;    // 先加上头位置索引
    if (index < 0) {
        return index + _elements.count;
    }
    
    // 返回正确插入位置索引
    return index - (index >= _elements.count ? _elements.count : 0);
}

/** 保证要有capacity的容量 */
- (void)ensureCapacity:(int)capacity {
    NSInteger oldCapactity = _elements.count;
    if (oldCapactity >= capacity) {
        return;
    }
    
    // 新容量为旧容量的1.5倍
    int newCapacity = oldCapactity + oldCapactity * 0.5;
    NSMutableArray *newElements = [NSMutableArray array];
    for (int i = 0; i < newCapacity; i++) {
        [newElements addObject:@(-1)];
    }
    // 恢复旧值
    for (int i = 0; i < _size; i++) {
        newElements[i] = _elements[i];
    }
    _elements = newElements;
    
    // 重置front
    _front = 0;
}
@end
// 双端循环队列测试
- (void)circleDequeTest {
    CircleDeque *queue = [[CircleDeque alloc] init];
    
    // 头5 4 3 2 1  100 101 102 103 104 105 106 8 7 6 尾
    
    // 头 8 7 6  5 4 3 2 1  100 101 102 103 104 105 106 107 108 109 null null 10 9 尾
    for (int i = 0; i < 10; i++) {
        [queue enQueueFront:@(i + 1)];
        [queue enQueueRear:@(i + 100)];
    }
    NSLog(@"%@",[queue description]);
    
    // 头 null 7 6  5 4 3 2 1  100 101 102 103 104 105 106 null null null null null null null 尾
    for (int i = 0; i < 3; i++) {
        [queue deQueueFront];
        [queue deQueueRear];
    }
    NSLog(@"%@",[queue description]);
    
    // 头 11 7 6  5 4 3 2 1  100 101 102 103 104 105 106 null null null null null null 12 尾
    [queue enQueueFront:@(11)];
    [queue enQueueFront:@(12)];
    NSLog(@"%@",[queue description]);
    
    while (!queue.isEmpty) {
        NSLog(@"%@",queue.deQueueFront);
    }
    
    NSLog(@"%@",[queue description]);
}

运行结果如下:

image.png

更多详细代码参考CircleDeque

七 %运算符优化

尽量避免使用 乘*除/模%浮点数运算,效率低下


本文会持续更新中,更多精彩内容敬请期待。


本文参考 MJ老师的 恋上数据结构与算法


本人技术水平有限,如有错误欢迎指正。
书写整理不易,您的打赏点赞是对我最大的支持和鼓励,欢迎点赞打赏。


项目连接链接 - 08_Queue

上一篇下一篇

猜你喜欢

热点阅读