数据--第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)      效率提高了,可实现的复杂性也提高了。

猜你喜欢

转载自www.cnblogs.com/free-1122/p/11322848.html