队列基础编程

队列的分类

  队列一般分为三种:顺序队列、循环队列、链式队列

  其中顺序队列和循环队列按照存储方式又可以分为动态和静态,链式队列是动态的。动态表示队列元素采用动态内存分配,静态表示队列元素采用数组的方式分配。

 

顺序队列

  顺序队列存在”假溢出“现象:即队头由于出队操作,还有剩余空间,但队尾指针已达到数组的末尾,如果继续插入元素,队尾指针就会越出数组的上界,而造成“溢出”,这种溢出不是因为存储空间不够而产生的溢出,这种溢出不是因为存储空间不够而产生的溢出,像这种有存储空间而不能插入元素的操作称为“假溢出“。

  由于存在顺序队列存在”假溢出“现象,因此一般使用顺序队列。

 

循环队列

关于判断队满和队空

  当循环队列为空或为满时,队尾和队头指针都指向同一个元素,可以通过下面几种方式判断队列空或队列满:

  (1)、牺牲一个队列元素用来识别队列满和队列空

  (2)、通过计数器来判断队列满和队列空

  (3)、通过一个读写标志来判断队列满和队列空

 

静态循环队列

  采用静态循环队列来展示三种队列满和队列空的判断方法,举例如下:

#include 
#include 
#include <string.h>
#include 
#define queue_max_length 5

#if 1    //牺牲一个队列元素用来识别队列满和队列空
typedef struct queue_srt
{
    int front;
    int rear;
    int queue_data[queue_max_length];
} queue_srt;


int queue_init(queue_srt *q_srt)
{
    q_srt->front = q_srt->rear = 0;
    memset(q_srt->queue_data, 0, sizeof(q_srt->queue_data));
    printf("queue init success\n");
    return 0;
}

int queue_read(queue_srt *q_srt, int *value)
{
    //判断队列是否为空
    if (q_srt->front == q_srt->rear)
    {    
        printf("the queue is empty\n");
        return 1;
    }
    *value = q_srt->queue_data[q_srt->front];
    q_srt->front = (q_srt->front + 1) % queue_max_length;
    return 0;
}

int queue_write(queue_srt *q_srt, int value)
{
    //牺牲一个队列元素用来判断队列满
    if (((q_srt->rear + 1)%queue_max_length) == q_srt->front)
    {    
        printf("the queue is full\n");
        return 1;
    }
    q_srt->queue_data[q_srt->rear] = value;
    q_srt->rear = (q_srt->rear + 1) % queue_max_length;
    return 0;
}

int queue_length(queue_srt *q_srt)
{
    //计算队列长度
    int length = (q_srt->rear - q_srt->front + queue_max_length) % queue_max_length;
    return length;
}
#endif 

#if 0    //通过计数器来判断队列满和队列空
typedef struct queue_srt
{
    int front;
    int rear;
    int queue_data[queue_max_length];
    int cnt;      //计数器,用来记录队列长度
} queue_srt;

int queue_init(queue_srt *q_srt)
{
    q_srt->front = q_srt->rear = 0;
    q_srt->cnt = 0;
    memset(q_srt->queue_data, 0, sizeof(q_srt->queue_data));
    printf("queue init success\n");
    return 0;
}

int queue_read(queue_srt *q_srt, int *value)
{
    //通过判断计数器来识别队列是否已经空
    if (q_srt->cnt == 0)
    {
        printf("the queue is empty\n");
        return 1;
    }
    *value = q_srt->queue_data[q_srt->front];
    q_srt->front = (q_srt->front + 1) % queue_max_length;
    q_srt->cnt--;//读完数据,计数器减1
    return 0;
}

int queue_write(queue_srt *q_srt, int value)
{
    //通过判断计数器来识别队列是否已经满
    if (q_srt->cnt == queue_max_length)
    {
        printf("the queue is full\n");
        return 1;
    }
    q_srt->queue_data[q_srt->rear] = value;
    q_srt->rear = (q_srt->rear + 1) % queue_max_length;
    q_srt->cnt++; //写完数据,计数器加1
    return 0;
}

int queue_length(queue_srt *q_srt)
{
    //通过计数器获取队列长度
    int length = q_srt->cnt;
    return length;
}
#endif

#if 0    //通过一个读写标志来判断队列满和队列空
typedef struct queue_srt
{
    int front;
    int rear;
    int queue_data[queue_max_length];
    char rw_flag; //读写标志  w:表示写完队列  r:表示读完队列
} queue_srt;

int queue_init(queue_srt *q_srt)
{
    q_srt->front = q_srt->rear = 0;
    q_srt->rw_flag = 'r'; //初始为 r ,表示队列为空
    memset(q_srt->queue_data, 0, sizeof(q_srt->queue_data));
    printf("queue init success\n");
    return 0;
}

int queue_read(queue_srt *q_srt, int *value)
{
    //通过读写标志判断队列是否为空
    if ((q_srt->front == q_srt->rear) && (q_srt->rw_flag == 'r'))
    {    
        printf("the queue is empty\n");
        return 1;
    }
    *value = q_srt->queue_data[q_srt->front];
    q_srt->front = (q_srt->front + 1) % queue_max_length;
    q_srt->rw_flag = 'r'; //读完队列,读写标志设置r
    return 0;
}

int queue_write(queue_srt *q_srt, int value)
{
    //通过读写标志判断队列是否为空
    if ((q_srt->front == q_srt->rear) && (q_srt->rw_flag == 'w'))
    {    
        printf("the queue is full\n");
        return 1;
    }
    q_srt->queue_data[q_srt->rear] = value;
    q_srt->rear = (q_srt->rear + 1) % queue_max_length;
    q_srt->rw_flag = 'w'; //写完队列,读写标志设置w
    return 0;
}

int queue_length(queue_srt *q_srt)
{
    int length = 0;       
    if ((q_srt->front == q_srt->rear) && (q_srt->rw_flag == 'w')) //通过读写标志判断是否队满
    {
        length = queue_max_length;
    }
    else 
    {
        length = (q_srt->rear - q_srt->front + queue_max_length) % queue_max_length;
    }
    return length;
}
#endif 

int main(void)
{
    int action = 0;
    int value = 0;
    queue_srt testqueue;
    queue_init(&testqueue);
    while (1)
    {
        printf("1:write 2:read 3:get length\n");
        printf("enter action:");
        scanf("%d", &action);
        switch(action)
        {
            case 1:
                printf("write queue to data:");
                scanf("%d", &value);
                queue_write(&testqueue, value);
                break;
            case 2:
                if (1 == queue_read(&testqueue, &value))
                    continue;
                printf("read data from queue: %d\n", value);
                break;
            case 3:
                value = queue_length(&testqueue);
                printf("the length of queue is: %d\n", value);
                break;
            default:
                printf("no such action\n");
        }
    }
    return 0;
}

 

 

 动态循环队列

  下面展示一个动态循环队列,队列元素采用动态内存分配,举例如下:

#include 
#include 
#include <string.h>
#include 
#define queue_max_length 5
typedef struct queue_srt
{
    int *front;        //指向队列头
    int *rear;        //指向队列尾
    int *queue_data;  //指向队列动态内存
    int *end;        //指向队列存储空间之后
} queue_srt;


int queue_init(queue_srt *q_srt)
{
    q_srt->queue_data = (int *) (malloc)(sizeof(int) * queue_max_length);
    if (NULL == q_srt)
    {
        printf("malloc mem failed,queue init failed\n");
        return 1;
    }
    q_srt->front = q_srt->rear = q_srt->queue_data; //指向队列首部
    q_srt->end = q_srt->queue_data + queue_max_length; //指向队列存储空间之后
    printf("queue init success\n");
    return 0;
}

int queue_read(queue_srt *q_srt, int *value)
{
    if (q_srt->front == q_srt->rear) //判断队列是否为空
    {    
        printf("the queue is empty\n");
        return 1;
    }
    *value = *(q_srt->front);
    if ((q_srt->front + 1) >= q_srt->end) //判断队头指针是否到队列尾
    {
        q_srt->front = q_srt->queue_data;
    }
    else
    {
        q_srt->front = q_srt->front + 1;
    }
    return 0;
}

int queue_write(queue_srt *q_srt, int value)
{
    //牺牲一个队列元素用来识别队列满
    int *q_tmp = (q_srt->rear + 1 >= q_srt->end)? (q_srt->queue_data) : (q_srt->rear + 1);
    if (q_tmp == q_srt->front)
    {    
        printf("the queue is full\n");
        return 1;
    }
    *(q_srt->rear) = value;
    q_srt->rear = q_tmp;
    return 0;
}

int queue_length(queue_srt *q_srt)
{
    int length = 0;
    length = (q_srt->rear - q_srt->front + queue_max_length) % queue_max_length;return length; //获取队列长度
}

int main(void)
{
    int action = 0;
    int value = 0;
    queue_srt testqueue;
    queue_init(&testqueue);
    while (1)
    {
        printf("1:write 2:read 3:get length\n");
        printf("enter action:");
        scanf("%d", &action);
        switch(action)
        {
            case 1:
                printf("write queue to data:");
                scanf("%d", &value);
                queue_write(&testqueue, value);
                break;
            case 2:
                if (1 == queue_read(&testqueue, &value))
                    continue;
                printf("read data from queue: %d\n", value);
                break;
            case 3:
                value = queue_length(&testqueue);
                printf("the length of queue is: %d\n", value);
                break;
            default:
                printf("no such action\n");
        }
    }
    free(testqueue.queue_data);
    return 0;
}

 

链式队列

  链式队列主要有两个特点:1、队列是动态的,即队列元素采用动态内存分配  2、队列采用链表的逻辑来组织,因此队列的长度没有限制,这是跟循环队列最大的差别

  编写一个带头结点的链式队列,举例如下:

#include 
#include 
typedef struct LKNODE
{
    int data;                //保存节点数据
    struct LKNODE *next;    //指向下一个节点
} LKNODE;

typedef struct LINKQUEUE    //队列结构体,采用头尾指针构建链式队列
{
    
    LKNODE *front; //头指针,指向队列头结点
    LKNODE *rear;  //尾指针,指向队列尾节点
}LINKQUEUE;

//初始化链式队列
int InitLinkQueue(LINKQUEUE *lkqueue)
{
    
    LKNODE *head = (LKNODE*) malloc(sizeof(LKNODE)); //创建头结点
    if (NULL == head)
    {
        printf("creat head node failed,init linkqueue failed\n");
        return 1;
    }
    head->next = NULL; //这里要head节点的next设置为NULL,避免头尾指针的next指向未知
    //头尾指针指向头结点
    lkqueue->front = lkqueue->rear = head;
    return 0;
}

//节点入队
int WriteLinkQueue(LINKQUEUE *lkqueue, int value)
{
    //创建新节点
    LKNODE *newnode = (LKNODE *)malloc(sizeof(LKNODE));
    if (NULL == newnode)
    {
        printf("creat newnode failed,write queue failed\n");
        return 1;
    }
    newnode->data = value;
    newnode->next = NULL; //这里要指向空,避免队列为空后,头结点的next指针指向未知
    
    //尾指针连接新节点
    lkqueue->rear->next = newnode;
    
    //尾指针指向新节点
    lkqueue->rear = newnode;
    return 0;
}

//节点出队
int ReadLinkQueue(LINKQUEUE *lkqueue, int *value)
{
    //LKNODE *temp = NULL;
    LKNODE *readnode = NULL;
    //判断队列是否为空队列
    if (lkqueue->front == lkqueue->rear)
    {
        printf("link queue is empty\n");
        return 1;
    }
    //获取读取节点值
    readnode = lkqueue->front->next;
    *value = readnode->data;
//头结点连接读取节点的下一个节点 lkqueue->front->next = readnode->next; //如果readnode是最后一个节点,则头结点的next会指向NULL //判断读取的节点是不是最后一个节点,防止释放读取节点后尾指针指向空 if (readnode == lkqueue->rear) { lkqueue->rear = lkqueue->front; //队列为空,尾指针指向头结点 } //释放读取节点 free(readnode); return 0; } //获取队列长度 int GetLinkQueueLen(LINKQUEUE *lkqueue) { int length = NULL; LKNODE *temp = NULL; //创建临时节点,因为头尾指针的位置不能动 temp = lkqueue->front->next; //获取头结点的下一个节点 if (NULL == temp) //判断队列是否为空 { length = 0; } else { while(temp != lkqueue->rear) //判断是不是读到尾节点 { length++; temp = temp->next; } length++; //加上最后一个节点 } return length; } //清空队列 void ClearLinkQueue(LINKQUEUE *lkqueue) { int value; int ret; while(1) { //读取队列元素,释放动态内存,防止内存泄漏 ret = ReadLinkQueue(lkqueue, &value); if (1 == ret) //判断队列是否读完 { printf("clear the link queue success\n"); break; } } } //销毁队列 void DestroyLinkQueue(LINKQUEUE *lkqueue) { //先清空队列,释放队列的动态内存 ClearLinkQueue(lkqueue); //释放头结点的动态内存 free(lkqueue->front); //头尾指针指向空 lkqueue->front = lkqueue->rear = NULL; printf("destroy the link queue success\n"); } //遍历队列 void TraverseLinkQueue(LINKQUEUE *lkqueue) { int value; int ret = 0; int num = 0; LKNODE *temp = lkqueue->front->next; while(1) { if (NULL != temp) //判断队列是否为空 { num++; printf("%d node data is:%d\n", num, temp->data); temp = temp->next; } else { printf("traverse link queue success\n"); break; } } } int main() { int action = 0; int value = 0; int ret = 0; LINKQUEUE testlkqueue = {NULL, NULL}; InitLinkQueue(&testlkqueue); //初始化链式队列 while(1) { printf("**********\n1 write 2 read 3 getlength 4 Traverse 5 Clear link queue 6 destroy link queue\n**********\n"); printf("enter action:"); scanf("%d", &action); switch(action) { case 1: printf("enter the value:"); scanf("%d", &value); WriteLinkQueue(&testlkqueue, value); break; case 2: ret = ReadLinkQueue(&testlkqueue, &value); if (1 != ret) { printf("the readnode data is:%d\n", value); } break; case 3: ret = GetLinkQueueLen(&testlkqueue); printf("the length of link queue is:%d\n", ret); break; case 4: TraverseLinkQueue(&testlkqueue); break; case 5: ClearLinkQueue(&testlkqueue); break; case 6: DestroyLinkQueue(&testlkqueue); return 0; break; default: break; } } return 0; }

 

你可能感兴趣的:(队列基础编程)