数据--第23课 - 队列的优化实现

Posted free-1122

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据--第23课 - 队列的优化实现相关的知识,希望对你有一定的参考价值。

第23课 - 队列的优化实现

 

 

1. 顺序队列的瓶颈

顺序队列

线性表的第一个元素作为队头。

线性表的最后一个元素作为队尾。

入队的新元素是线性表的最后,时间复杂度为O(1)。

出队列时需要将后续的所有元素向前移动,时间复杂度是O(n)。

 

2. 顺序队列的优化方案

(1)定义front使其始终代表队头的下标。

出队列时对头元素返回,且front++

(2)定义rear使其始终代表队尾下一个元素的下标。

出队时将新的元素插入,且rear++

(3)没有必要只将下标为0的位置定义为队头。

(4)顺序队列的关键状态

初始状态:length == 0,front == 0,rear == 0;

空队列状态:length == 0,front == rea;
         满队列状态:length == capacity,front == rea;

(5)循环使用队列的空间

入列:rear = (rear + 1) % capacity;

出列:front = (front + 1) % capacity;

 

3. 程序

(1)LinkQueue2.0

main.c

#include <stdio.h>

#include <stdlib.h>

#include "LinkQueue.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[])

    LinkQueue* queue = LinkQueue_Create();

    int a[10] = 0;

    int i = 0;

    for(i=0; i<10; i++)

   

        a[i] = i + 1;     

        LinkQueue_Append(queue, a + i);

   

    printf("Header: %d\n", *(int*)LinkQueue_Header(queue));

    printf("Length: %d\n", LinkQueue_Length(queue));  

    LinkQueue_Clear(queue);  

    while( LinkQueue_Length(queue) > 0 )

   

        printf("Retrieve: %d\n", *(int*)LinkQueue_Retrieve(queue));

      

    LinkQueue_Destroy(queue);

        return 0;

LinkQueue.h

#ifndef _LINKQUEUE_H_

#define _LINKQUEUE_H_

typedef void LinkQueue;

LinkQueue* LinkQueue_Create();

void LinkQueue_Destroy(LinkQueue* queue);

void LinkQueue_Clear(LinkQueue* queue);

int LinkQueue_Append(LinkQueue* queue, void* item);

void* LinkQueue_Retrieve(LinkQueue* queue);

void* LinkQueue_Header(LinkQueue* queue);

int LinkQueue_Length(LinkQueue* queue);

#endif

LinkQueue.c

#include <malloc.h>

#include <stdio.h>

#include "LinkQueue.h"

typedef struct _tag_LinkQueueNode TLinkQueueNode;

struct _tag_LinkQueueNode

    TLinkQueueNode* next;

    void* item;

;

typedef struct _tag_LinkQueue

    TLinkQueueNode* front;

    TLinkQueueNode* rear;

    int length;

TLinkQueue;

LinkQueue* LinkQueue_Create() // O(1)

    TLinkQueue* ret = (TLinkQueue*)malloc(sizeof(TLinkQueue));

    if( ret != NULL )

   

        ret->front = NULL;

        ret->rear = NULL;

        ret->length = 0;

   

    return ret;

void LinkQueue_Destroy(LinkQueue* queue) // O(n)

    LinkQueue_Clear(queue);

    free(queue);

void LinkQueue_Clear(LinkQueue* queue) // O(n)

    while( LinkQueue_Length(queue) > 0 )

   

        LinkQueue_Retrieve(queue);

   

int LinkQueue_Append(LinkQueue* queue, void* item) // O(1)

    TLinkQueue* sQueue = (TLinkQueue*)queue;

    TLinkQueueNode* node = (TLinkQueueNode*)malloc(sizeof(TLinkQueueNode));

    int ret = (sQueue != NULL ) && (item != NULL) && (node != NULL);

    if( ret )

   

        node->item = item; 

        if( sQueue->length > 0 )

       

            sQueue->rear->next = node;

            sQueue->rear = node;

            node->next = NULL;

       

        else

       

            sQueue->front = node;

            sQueue->rear = node;

            node->next = NULL;

       

        sQueue->length++;

   

    if( !ret )

   

        free(node);

   

    return ret;

void* LinkQueue_Retrieve(LinkQueue* queue) // O(1)

    TLinkQueue* sQueue = (TLinkQueue*)queue;

    TLinkQueueNode* node = NULL;

    void* ret = NULL;

    if( (sQueue != NULL) && (sQueue->length > 0) )

   

        node = sQueue->front;   

        sQueue->front = node->next;     

        ret = node->item;     

        free(node);      

        sQueue->length--;    

        if( sQueue->length == 0 )

       

            sQueue->front = NULL;

            sQueue->rear = NULL;

       

     

    return ret;

void* LinkQueue_Header(LinkQueue* queue) // O(1)

    TLinkQueue* sQueue = (TLinkQueue*)queue;

    void* ret = NULL; 

    if( (sQueue != NULL) && (sQueue->length > 0) )

   

        ret = sQueue->front->item;

     

    return ret;

int LinkQueue_Length(LinkQueue* queue) // O(1)

    TLinkQueue* sQueue = (TLinkQueue*)queue;

    int ret = -1;   

    if( sQueue != NULL )

   

        ret = sQueue->length;

     

    return ret;

(2)SeqQueue2.0

main.c

#include <stdio.h>

#include <stdlib.h>

#include "SeqQueue.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[])

    SeqQueue* queue = SeqQueue_Create(6);

    int a[10] = 0;

    int i = 0;

    for(i=0; i<10; i++)

   

        a[i] = i + 1;    

        SeqQueue_Append(queue, a + i);

      

    printf("Header: %d\n", *(int*)SeqQueue_Header(queue));

    printf("Length: %d\n", SeqQueue_Length(queue));

    printf("Capacity: %d\n", SeqQueue_Capacity(queue));   

    while( SeqQueue_Length(queue) > 0 )

   

        printf("Retrieve: %d\n", *(int*)SeqQueue_Retrieve(queue));

      

    printf("\n"); 

    for(i=0; i<10; i++)

   

        a[i] = i + 1;       

        SeqQueue_Append(queue, a + i);

        printf("Retrieve: %d\n", *(int*)SeqQueue_Retrieve(queue));

      

    SeqQueue_Destroy(queue);  

         return 0;

SeqQueue.h

#ifndef _SEQQUEUE_H_

#define _SEQQUEUE_H_

typedef void SeqQueue;

SeqQueue* SeqQueue_Create(int capacity);

void SeqQueue_Destroy(SeqQueue* queue);

void SeqQueue_Clear(SeqQueue* queue);

int SeqQueue_Append(SeqQueue* queue, void* item);

void* SeqQueue_Retrieve(SeqQueue* queue);

void* SeqQueue_Header(SeqQueue* queue);

int SeqQueue_Length(SeqQueue* queue);

int SeqQueue_Capacity(SeqQueue* queue);

#endif

SeqQueue.c   

#include <stdio.h>

#include <malloc.h>

#include "SeqQueue.h"

typedef unsigned int TSeqQueueNode;

typedef struct _tag_SeqQueue

    int capacity;

    int length;

    int front;

    int rear;

    TSeqQueueNode* node;

TSeqQueue;

SeqQueue* SeqQueue_Create(int capacity) // O(1)

    TSeqQueue* ret = NULL;

    if( capacity >= 0 )

   

        ret = (TSeqQueue*)malloc(sizeof(TSeqQueue) + sizeof(TSeqQueueNode) * capacity);

   

    if( ret != NULL )

   

        ret->capacity = capacity;

        ret->length = 0;

        ret->front = 0;

        ret->rear = 0;

        ret->node = (TSeqQueueNode*)(ret + 1);

     

    return ret;

void SeqQueue_Destroy(SeqQueue* queue) // O(1)

    free(queue);

void SeqQueue_Clear(SeqQueue* queue) // O(1)

    TSeqQueue* sQueue = (TSeqQueue*)queue;  

    if( sQueue != NULL )

   

        sQueue->length = 0;

        sQueue->front = 0;

        sQueue->rear = 0;

   

int SeqQueue_Append(SeqQueue* queue, void* item) // O(1)

    TSeqQueue* sQueue = (TSeqQueue*)queue;

    int ret = (sQueue != NULL) && (item != NULL);

    ret = ret && (sQueue->length + 1 <= sQueue->capacity);

    if( ret )

   

        sQueue->node[sQueue->rear] = (TSeqQueueNode)item;     

        sQueue->rear = (sQueue->rear + 1) % sQueue->capacity; 

        sQueue->length++;

     

    return ret;

void* SeqQueue_Retrieve(SeqQueue* queue) // O(1)

    TSeqQueue* sQueue = (TSeqQueue*)queue;

    void* ret = SeqQueue_Header(queue);  

    if( ret != NULL )

   

        sQueue->front = (sQueue->front + 1) % sQueue->capacity;     

        sQueue->length--;

     

    return ret;

void* SeqQueue_Header(SeqQueue* queue) // O(1)

    TSeqQueue* sQueue = (TSeqQueue*)queue;

    void* ret = NULL;

    if( (sQueue != NULL) && (sQueue->length > 0) )

   

        ret = (void*)(sQueue->node[sQueue->front]);

    

    return ret;

int SeqQueue_Length(SeqQueue* queue) // O(1)

    TSeqQueue* sQueue = (TSeqQueue*)queue;

    int ret = -1;

    if( sQueue != NULL )

   

        ret = sQueue->length;

   

    return ret;

int SeqQueue_Capacity(SeqQueue* queue) // O(1)

    TSeqQueue* sQueue = (TSeqQueue*)queue;

         int ret = -1; 

    if( sQueue != NULL )

   

        ret = sQueue->capacity;

      

    return ret;

 

4. 链式队列的瓶颈

链式队列

线性表的第一个元素作为队头。

线性表的最后一个元素作为队尾。

入队的新元素实在线性表的最后,时间复杂度是O(n)。

出队的元素即链表的第一个元素,时间复杂度是O(1)。

 

5. 优化方案

(1)定义rear指针始终指向链表的最后一个元素,入队时将新的元素通过rear插入队尾,而且将rear指向新的元素。

(2)链式队列的关键状态

空队列状态:front == NULL, rear == NULL;

关键操作:

入队:

rear ->next = node;

rear = node;

node ->next =NULL;

出列:

front = front ->next;

 

6. 代码

 

小结:

(1)      优化的顺序队列循环利用顺序空间提高队列操作的效率。

(2)      优化的链式队列定义rear指针指向队尾元素提高出队操作的效率。

(3)      效率提高了,可实现的复杂性也提高了。

 

以上是关于数据--第23课 - 队列的优化实现的主要内容,如果未能解决你的问题,请参考以下文章

第28章 算法优化体验课 - 骑士周游问题

第23课 可变参数模板_Optional和Lazy类的实现

两个栈实现队列——优化版

第23课 优先选用make系列函数

第04课:自编码器在数据压缩中的应用实现

pyhton中的Queue(队列)