数据结构与算法三: 2)队列之动态队列(单链表实现) | 8月更文挑战

441 阅读4分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

关注我,以下内容持续更新

数据结构与算法(一):时间复杂度和空间复杂度

数据结构与算法(二):桟

数据结构与算法(三):队列

数据结构与算法(四):单链表

数据结构与算法(五):双向链表

数据结构与算法(六):哈希表

数据结构与算法(七):树

数据结构与算法(八):排序算法

数据结构与算法(九):经典算法面试题

动态队列的介绍

队列和栈一样是一种受限的线性表,队列它是“先进先出”的存储结构,栈是后进先出的数据结构。 栈是只能在同一位置增加或删减元素,队列只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,我们分别称之为队头和队尾。

队列分为动态队列和静态队列两种。动态队列用链表实现,动态队列易于实现。静态队列用数组实现,静态队列通常都必须是循环队列。用链表实现队列,分别在表头和表尾进行入队和出队,当然也可以链表头出队,链表尾入队,两种方式都可以保证先进先出的特性,链表不用考虑队列的最大容量,只需要考虑链表是否为空,而用数组实现队列需要判断队列是否为空和队列是否已满.

下面我们来看一下用单链表实现队列,本篇文章选择用表头入队和表尾出队的方式

动态队列的结构

初始化队列,返回一个空链表的头结点,用 length 记录队列的长度,入队时length+1,出队时 length-1;

  1. 判空:该方法会传入初始化返回的头结点header,如果header.next == NULL,则队列为空

  2. 入队:该方法会传入一个header和数据data,先初始化一个新节点new: LinkNode*new = [LinkNode new];new.data = data;,然后插入new:new.next = header.next; header.next = new;,并令 length++;

  3. 出队:该方法会传入初始化返回的头结点header,先判空,然后用 while 循环找出倒数第二个元素,如下:while (current.next.next != NULL) {current = current.next;},然后把倒数第二个节点的下一个节点置空,current.next = NULL;

  4. 查看队列的第一个元素:该方法会传入链表的头结点 header,先判空,如果不为空则返回header.next.data

  5. 输出队列的所有元素: 如果用 while 循环是逆序输出,如果想按插入顺序正序输出,有很多方案:

方案一:比如可以用数组实现,先用 while循环把每个元素加入到一个新数组,然后把数组逆序输出;

方案二:用while循环将元素逆序加入一个新的队列,然后将新队列逆序输出,逆序+逆序=正序

动态队列的完整代码

//LinkQueue.h 文件

@class LinkNode;

@interface LinkQueue : NSObject

/**队列的长度*/
@property (nonatomic,assign) int length;

-(LinkNode*)createQueue;

//队空
-(BOOL)isEmpty:(LinkNode*)header;

//入队
-(void)enqueue:(NSString*)data header:(LinkNode*)header;

//出队
-(NSString*)dequeue:(LinkNode*)header;

//查看头元素
-(NSString*)getFront:(LinkNode*)header;

//显示多有元素
-(void)showQueue:(LinkNode*)header;

@end


@interface LinkNode : NSObject

/**存放的真实数据,data可以是任意类型*/

@property (nonatomic,strong) NSString * data;

/**next 指针,指向下一个元素*/

@property (nonatomic,strong) LinkNode * next;

@end
//LinkQueue.m 文件

@implementation LinkQueue

//初始化,返回一个带有头结点的空链表
-(LinkNode*)createQueue{

    LinkNode*header = [LinkNode new];

    header.next = NULL;

    return header;

}
//队空

-(BOOL)isEmpty:(LinkNode*)header{

    return header.next == NULL;

}

//入队,链表头插入数据
-(void)enqueue:(NSString*)data header:(LinkNode*)header{

    LinkNode*new = [LinkNode new];

    new.data = data;

    new.next = header.next;

    header.next = new;

    self.length++;

}

//出队,链表尾删除数据

-(NSString*)dequeue:(LinkNode*)header{

    if ([self isEmpty:header]) {
        printf("队列为空 \n");
        return NULL;
    }

    LinkNode*current = header;
    while (current.next.next != NULL) {//找到倒数第二个结点
        current = current.next;
    }

    LinkNode*node = current.next;

    current.next = NULL;

    self.length--;

    return node.data;

}

//查看头元素

-(NSString*)getFront:(LinkNode*)header{

    if ([self isEmpty:header]) {

        printf("队列为空 \n");

        return NULL;

    }

    return header.next.data;

}

//顺序输出所有元素(借助数组)
-(void)showQueue:(LinkNode*)header{

    if ([self isEmpty:header]) {

        printf("队列为空 \n");

        return;

    }

    NSMutableArray<NSString*>*arr = [NSMutableArray array];

    LinkNode*current = header;

    while (current.next != NULL) {

        current = current.next;

        [arr addObject:current.data];

    }

    for (int i = (int)arr.count - 1; i>=0; i--) {

         printf("%s-->",arr[i].UTF8String);

    }

    printf("\n");

}

//顺序输出所有元素
//用while循环将元素逆序加入一个新的队列,然后将新队列逆序输出,逆序+逆序=正序

-(void)showQueue2:(LinkNode*)header{

    if ([self isEmpty:header]) {

        printf("队列为空 \n");

        return;

    }

    LinkQueue*queue = [LinkQueue new];

    LinkNode*header_new = [queue createQueue];

    

    LinkNode*current = header;

    while (current.next != NULL) {

        current = current.next;

        [queue enqueue:current.data header:header_new];

    }

    

    LinkNode*current_new = header_new;

    while (current_new.next != NULL) {

        current_new = current_new.next;

        printf("%s-->",current_new.data.UTF8String);

    }

    printf("\n");

}

//输出所有元素(这是逆序输出)
/*

-(void)showQueue3:(LinkNode*)header{

    if ([self isEmpty:header]) {

        printf("队列为空 \n");

        return;

    }

    LinkNode*current = header;

    while (current.next != NULL) {

        current = current.next;

        printf("%s-->",current.data.UTF8String);

    }

    printf("\n");

}

*/

@end

@implementation LinkNode
@end

// 测试队列是否正确

-(void)LinkQueueCase{

    LinkQueue*queue = [LinkQueue new];

    LinkNode*header = [queue createQueue];

    //打印队列
    [queue showQueue:header];

    
    //入队
    [queue enqueue:@"a" header:header];
    [queue enqueue:@"b" header:header];
   

    //打印队列
    [queue showQueue:header];


    //出队
    NSString*data1 = [queue dequeue:header];
    printf("出队:%s \n",data1.UTF8String);

    //打印队列
    [queue showQueue:header];

    //继续出队
    NSString*data2 = [queue dequeue:header];
    printf("出队:%s \n",data2.UTF8String);

    //继续出队
    NSString*data3 = [queue dequeue:header];
    printf("出队:%s \n",data3.UTF8String);


    //打印队列
    [queue showQueue:header];

}

上一篇 数据结构与算法三:1)队列之循环队列

关注我

如果觉得我写的不错,请点个赞 关注我 您的支持是我更文最大的动力!