队列

1 队列的特点

    先进先出或者说后进后出

2 基于顺序表实现队列的相关操作

2.1 头文件seqqueue.h

//头文件只被编译一次
#pragma once
//宏定义一个标识符,用于打印函数名
#define HEADER printf("============%s==========\n",__FUNCTION__);
//重定义队列元素的数据类型,以便用户修改
typedef char SeqQueueType;
//定义队列的结构体
typedef struct SeqQueue
{
    //存放队列数据元素的位置
    SeqQueueType* data;
    //定义一个变量,用于表示初始化的最大长度
    size_t capacity;
    //定义两个无符号整型用于标记队列的有效元素范围,有效范围规定为[head,tail)
    size_t head;
    size_t tail;
    //定义一个无符号整型用于标记队列是否已满
    size_t size;
}SeqQueue;
//函数声明
//1.初始化SeqQueueInit
void SeqQueueInit(SeqQueue* queue);
//2.销毁SeqQueueDestroy
void SeqQueueDestroy(SeqQueue* queue);
//3.打印SeqQueuePrintChar
void SeqQueuePintChar(SeqQueue* queue,char* msg);
//4.入队列SeqQueuePush
void SeqQueuePush(SeqQueue* queue,SeqQueueType value);
//5.扩容SeqQueueReset
void SeqQueueReset(SeqQueue* queue);
//6.出队列SeqQueuePop
void SeqQueuePop(SeqQueue* queue);
//7.取队首元素SeqQueueFront
int SeqQueueFront(SeqQueue* queue,SeqQueueType* value);

2.2 初始化

//思路:开辟空间、初始队列的有效元素size为0,有效范围也为0,故head=0,tail=0

void SeqQueueInit(SeqQueue* queue)
{
    //非法输入
    if(queue==NULL)
        return;
    //初始化开辟空间的大小
    queue->capacity=100;
    //开辟空间
    queue->data=(SeqQueueType*)malloc((queue->capacity)*sizeof(SeqQueueType));
    //初始化size
    queue->size=0;
    //初始化head、tail
    queue->head=0;
    queue->tail=0;
}

2.3 销毁

//思路:将开辟的空间释放并将初始开辟的空间大小capacity置为0以及队列的有效元素size置为0,有效范围也置为为0,故head=0,tail=0

void SeqQueueDestroy(SeqQueue* queue)
{
    //非法输入
    if(queue==NULL)
        return;
    //释放空间
    free(queue->data);
    //将初始开辟空间大小置为0
    queue->capacity=0;
    //将队列的有效元素个数size置为0
    queue->size=0;
    //将队列的有效范围置为0,即head=0、tail=0
    queue->head=0;
    queue->tail=0;

2.4 入队列

//思路:将有效元素个数size加1并将tail后移一位

//tail后移时有两种情况:1.tail<SeqQueueMaxSize时直接tail++ 2.tail>=SeqQueueMaxSize时,将tail=0

void SeqQueuePush(SeqQueue* queue,SeqQueueType value)
{
    //非法输入
    if(queue==NULL)
        return;
    //判断队列是否已满
    if(queue->size>=queue->capacity)
    {
        //扩容
        SeqQueueReset(queue);
    }
    //正常入队列
    queue->data[queue->tail]=value;
    queue->tail++;
    //判断tail是否超出SeqQueueMaxSize的范围
    if(queue->tail>queue->capacity)
    {
        queue->tail=0;
    }
    //有效元素个数size++
    queue->size++;

}

//扩容

//思路:1.新开辟一块更大的空间 2.将原有的数据进行搬运 3.释放之前的内存空间

void SeqQueueReset(SeqQueue* queue)
{
    //非法输入
    if(queue==NULL)
        return;
    //有效元素个数size小于SeqQueueMaxSize时
    if(queue->size<queue->capacity)
        return;
    //新开辟空间
    queue->capacity=2*(queue->capacity)+1;
    SeqQueueType* new_data=(SeqQueueType*)malloc((queue->capacity)*sizeof(SeqQueueType));
    //将原有数据进行搬运
    if(queue->head<queue->tail)
    {
        size_t i=0;
        size_t j=0;
        for(i=queue->head;i!=queue->tail;i++)
        {
            new_data[j]=queue->data[i];
            j++;
        }
    }
    else
    {
        size_t i=queue->head;
        size_t j=0;
        for(i=queue->head;i<queue->capacity;i++)
        {
            new_data[j]=queue->data[i];
            j++;
        }
        for(i=0;i<queue->tail;i++)
        {
            new_data[j]=queue->data[i];
            j++;
        }
    }
    //释放原有内存空间
    free(queue->data);
    queue->data=new_data;
}

2.5 出队列

//思路:将表示有效元素范围的head后移一位,即将head加1,并将有效元素个数size进行减1

void SeqQueuePop(SeqQueue* queue)
{
    //非法输入
    if(queue==NULL)
        return;
    //判断队列是否为空
    if(queue->size==0)
        return;
    //对head加1
    queue->head++;
    //判断对head加1后head是否是合法范围
    if(queue->head>=queue->capacity)
        queue->head=0;
    //对有效元素个数size进行减1
    queue->size--;
}

2.6 取队首元素

//思路:队首元素即queue->data[queue->head]所表示的元素

//需要返回两个有效信息:1.取队首元素是否成功,用返回值传出 2.队首元素的值,用输出参数传出

int SeqQueueFront(SeqQueue* queue,SeqQueueType* value)
{
    //非法输入
    if(queue==NULL||value==NULL)
        return 0;
    //判断队列是否为空
    if(queue->size==0)
        return 0;
    //进行读取队首元素
    *value=queue->data[queue->head];
    return 1;
}

2.7 测试代码是否正确

为了测试代码的方便需要写打印栈中元素的函数

void SeqQueuePrintChar(SeqQueue* queue,char* msg)
{
    //先打印一行字符串
    printf("%s\n",msg);
    //非法输入
    if(queue==NULL||msg==NULL)
        return;
    //空队列
    if(queue->size==0)
        return;
    if(queue->head<queue->tail)
    {
        size_t i=0;
        for(i=queue->head;i!=queue->tail;i++)
        {
            printf("%c ",queue->data[i]);
        }
    }
    else
    {
        size_t i=queue->head;
        for(i=queue->head;i<queue->capacity;i++)
        {
            printf("%c ",queue->data[i]);
        }
        for(i=0;i<queue->tail;i++)
        {
            printf("%c ",queue->data[i]);
        }
    }
    printf("\n");

}

//1.测试SeqQueuePush

void Test_SeqQueuePush()
{
    HEADER;
    SeqQueue queue;
    SeqQueueInit(&queue);
    SeqQueuePush(&queue,'a');
    SeqQueuePush(&queue,'b');
    SeqQueuePush(&queue,'c');
    SeqQueuePrintChar(&queue,"入队列'a''b''c'");

}

//2.测试SeqQueuePop

void Test_SeqQueuePop()
{
    HEADER;
    SeqQueue queue;
    SeqQueueInit(&queue);
    SeqQueuePush(&queue,'a');
    SeqQueuePush(&queue,'b');
    SeqQueuePush(&queue,'c');
    SeqQueuePop(&queue);
    SeqQueuePrintChar(&queue,"出队列一次");
    SeqQueuePop(&queue);
    SeqQueuePrintChar(&queue,"出队列两次");
    SeqQueuePop(&queue);
    SeqQueuePop(&queue);
    SeqQueuePrintChar(&queue,"尝试对空队列出队列");

}

//3.测试SeqQueueFront

void Test_SeqQueueFront()
{
    HEADER;
    SeqQueue queue;
    SeqQueueType value;
    SeqQueueInit(&queue);
    SeqQueuePush(&queue,'a');
    SeqQueuePush(&queue,'b');
    SeqQueuePush(&queue,'c');
    int ret=SeqQueueFront(&queue,&value);
    printf("expected 1,actual %d\n",ret);
    printf("expected a,actual %c\n",value);
    SeqQueuePop(&queue);
    ret=SeqQueueFront(&queue,&value);
    printf("expected 1,actual %d\n",ret);
    printf("expected b,actual %c\n",value);
    SeqQueuePop(&queue);
    SeqQueuePop(&queue);
    ret=SeqQueueFront(&queue,&value);
    printf("expected 0,actual %d\n",ret);
}

/*================主函数===============*/
int main()
{
    Test_SeqQueuePush();
    Test_SeqQueuePop();
    Test_SeqQueueFront();
    return 0;
}

3 基于链表实现队列的相关操作

3.1 头文件linkqueue.h

//头文件只被编译一次
#pragma once
//宏定义标识符,用于打印函数名
#define HEADER printf("==============%s============\n",__FUNCTION__);
//为了方便用户修改元素数据类型
typedef char LinkType;
//队列节点的结构体
typedef struct LinkQueue
{
    LinkType data;
    struct LinkQueue* next;
}LinkQueue;

3.2 初始化

//思路:将头指针置为NULL时,初始化成功

void LinkQueueInit(LinkQueue** pqueue)
{
    //非法输入
    if(pqueue==NULL)
        return;
    //修改头指针的指向为NULL
    (*pqueue)=NULL;
}

3.3 销毁

//思路:对队列进行遍历去销毁每一个节点

void LinkQueueDestroy(LinkQueue** pqueue)
{
    //非法输入
    if(pqueue==NULL)
        return;
    //空队列时
    if((*pqueue)==NULL)
        return;
    //遍历释放每一个节点
    LinkQueue* cur=*pqueue;
    while(cur!=NULL)
    {
        LinkQueue* next=cur->next;
        free(cur);
        cur=next;
    }
}

3.4 入队列

//思路:利用尾插法进行入队列操作

void LinkQueuePush(LinkQueue** pqueue,LinkType value)
{
    //非法输入
    if(pqueue==NULL)
        return;
    //创建新节点
    LinkQueue* new_node=(LinkQueue*)malloc(sizeof(LinkQueue));
    new_node->data=value;
    new_node->next=NULL;
    //空队列时
    if(*pqueue==NULL)
    {
        *pqueue=new_node;
        return;
    }
    //非空队列时,找队列的最后一个节点
    LinkQueue* cur=*pqueue;
    while(cur->next!=NULL)
    {
        cur=cur->next;
    }
    cur->next=new_node;
}

3.5 出队列

//思路:利用头删法实现出队列

void LinkQueuePop(LinkQueue** pqueue)
{
    //非法输入
    if(pqueue==NULL)
        return;
    //空链表时
    if(*pqueue==NULL)
        return;
    //找到要删除的节点
    LinkQueue* to_delete=*pqueue;
    *pqueue=to_delete->next;
    //释放要删除的节点
    free(to_delete);
}

3.6 取队首元素

//思路:两种情况:1.空队列直接返回 2.取queue所指向位置的元素 

//返回两个有效信息:1.执行是否成功,用返回值 2.队首元素的值,用输出参数带出

int LinkQueueFront(LinkQueue* queue,LinkType* value)
{
    //非法输入
    if(value==NULL)
        return 0;  //返回0表示执行失败
    //空队列
    if(queue==NULL)
        return 0;
    *value=queue->data;
    //返回1表示执行成功
    return 1;
}

3.7 测试代码是否正确

为了测试代码的方便需要写打印栈中元素的函数

void LinkQueuePrintChar(LinkQueue* queue,char* msg)
{
    //非法输入
    if(msg==NULL)
        return;
    //打印一行字符
    printf("%s\n",msg);
    //空队列
    if(queue==NULL)
        return;
    //遍历队列打印
    LinkQueue* cur=queue;
    for(;cur!=NULL;cur=cur->next)
    {
        printf("[%c] ",cur->data);
    }
    printf("\n");

}

//1.测试初始化、销毁、以及空队列的打印

void Test()
{
    LinkQueue* queue;
    LinkQueueInit(&queue);
    printf("%p\n",queue);
    LinkQueueDestroy(&queue);
    printf("%p\n",queue);
    LinkQueuePrintChar(queue,"对空队列打印");

}

//2.测试LinkQueuePush

void Test_LinkQueuePush()
{
    HEADER;
    LinkQueue* queue;
    LinkQueueInit(&queue);
    LinkQueuePush(&queue,'a');
    LinkQueuePush(&queue,'b');
    LinkQueuePush(&queue,'c');
    LinkQueuePrintChar(queue,"入队列'a''b''c'");

}

//3.测试LinkQueuePop

void Test_LinkQueuePop()
{
    HEADER;
    LinkQueue* queue;
    LinkQueueInit(&queue);
    LinkQueuePush(&queue,'a');
    LinkQueuePush(&queue,'b');
    LinkQueuePush(&queue,'c');
    LinkQueuePop(&queue);
    LinkQueuePrintChar(queue,"出队列一次");
    LinkQueuePop(&queue);
    LinkQueuePrintChar(queue,"出队列两次");
    LinkQueuePop(&queue);
    LinkQueuePop(&queue);
    LinkQueuePrintChar(queue,"尝试对空队列出队");

}

//4.测试LinkQueueFront

void Test_LinkQueueFront()
{
    HEADER;
    LinkQueue* queue;
    LinkType value;
    LinkQueueInit(&queue);
    LinkQueuePush(&queue,'a');
    LinkQueuePush(&queue,'b');
    LinkQueuePush(&queue,'c');
    int ret=LinkQueueFront(queue,&value);
    printf("expected 1,actual %d\n",ret);
    printf("expected a,actual %c\n",value);
    LinkQueuePop(&queue);
    ret=LinkQueueFront(queue,&value);
    printf("expected 1,actual %d\n",ret);
    printf("expected b,actual %c\n",value);
    LinkQueuePop(&queue);
    LinkQueuePop(&queue);
    ret=LinkQueueFront(queue,&value);
    printf("expected 0,actual %d\n",ret);

}

/*=============主函数============*/

int main()
{
    Test();
    Test_LinkQueuePush();
    Test_LinkQueuePop();
    Test_LinkQueueFront();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值