数据结构——队列

数据结构——队列

浅谈

在队列的形成过程中,可以利用线性链表的原理,来生成一个队列。
基于链表的队列,要动态创建和删除节点,效率较低,但是可以动态增长。
队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。由于链表由结构体间接而成,遍历也方便。 队列又称为先进先出(FIFO—first in first out)线性表。
第一个程序就是由单链表删减形成的链式队列

链式队列

创建队列

PNODE create_queue(void)
{
    int len;  //用来存放有效节点的个数
    int i;
    int val; //用来临时存放用户输入的结点的值

    //分配了一个不存放有效数据的头结点
    PNODE pHead = (PNODE)malloc(sizeof(Node));
    if (NULL == pHead)
    {
        printf("分配失败, 程序终止!\n");
        exit(-1);
    }
    PNODE pTail = pHead;
    pTail->pNext = NULL;

    printf("请输入您需要生成的队列节点的个数: len = ");
    scanf_s("%d", &len);

    for (i = 0; i < len; ++i)
    {
        printf("请输入第%d个节点的值: ", i + 1);
        scanf_s("%d", &val);

        PNODE pNew = (PNODE)malloc(sizeof(Node));
        if (NULL == pNew)
        {
            printf("分配失败, 程序终止!\n");
            exit(-1);
        }
        pNew->data = val;
        pTail->pNext = pNew;
        pNew->pNext = NULL;
        pTail = pNew;
    }

    return pHead;
}

遍历队列

void Travers(PNODE pHead)
{
    PNODE p = pHead->pNext;
    while (NULL != p)
    {
        printf("%d", p->data);
        p = p->pNext;
    }
    return;
}

判断为空

bool is_empty(PNODE pHead)
{
    if (NULL == pHead->pNext)
        return true;
    else
        return false;
}

队列长度

int length_queue(PNODE pHead)
{
    PNODE p = pHead->pNext;
    int len = 0;
    while (NULL != p)
    {
        len++;
        p = p->pNext;
    }    
    return len;
}

入队

bool InQueue(PNODE pHead, int val)
{
    PNODE p = pHead;
    while (NULL !=p->pNext)
    {
        p = p->pNext;
    }
    PNODE pNew = (PNODE)malloc(sizeof(Node));
    if (NULL == p)
    {
        printf("失败");
        exit(-1);
    }
    pNew->data = val;
    
    p->pNext = pNew;
    pNew->pNext = NULL;
    return true;
}

出队

bool OutQueue(PNODE pHead, int* val)
{
    PNODE q = pHead->pNext;
    *val = q->data;
    pHead->pNext = pHead->pNext->pNext;
    free(q);
    q = NULL;
    return true;
}

完整程序

# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>

typedef struct Node
{
    int data; //数据域
    struct Node* pNext; //指针域
} * PNODE; //NODE等价于struct Node    PNODE等价于struct Node *

//函数声明
PNODE create_queue(void);  //创建队列
void Travers(PNODE pHead);  //遍历队列
bool is_empty(PNODE pHead);  //判断队列是否为空
int length_queue(PNODE);  //求队列长度
bool InQueue(PNODE pHead, int pos, int val);  //入队
bool OutQueue(PNODE pHead, int pos, int* pVal);  //出队


PNODE create_queue(void)
{
    int len;  //用来存放有效节点的个数
    int i;
    int val; //用来临时存放用户输入的结点的值

    //分配了一个不存放有效数据的头结点
    PNODE pHead = (PNODE)malloc(sizeof(Node));
    if (NULL == pHead)
    {
        printf("分配失败, 程序终止!\n");
        exit(-1);
    }
    PNODE pTail = pHead;
    pTail->pNext = NULL;

    printf("请输入您需要生成的队列节点的个数: len = ");
    scanf_s("%d", &len);

    for (i = 0; i < len; ++i)
    {
        printf("请输入第%d个节点的值: ", i + 1);
        scanf_s("%d", &val);

        PNODE pNew = (PNODE)malloc(sizeof(Node));
        if (NULL == pNew)
        {
            printf("分配失败, 程序终止!\n");
            exit(-1);
        }
        pNew->data = val;
        pTail->pNext = pNew;
        pNew->pNext = NULL;
        pTail = pNew;
    }

    return pHead;
}

void Travers(PNODE pHead)
{
    PNODE p = pHead->pNext;
    while (NULL != p)
    {
        printf("%d", p->data);
        p = p->pNext;
    }
    return;
}
bool is_empty(PNODE pHead)
{
    if (NULL == pHead->pNext)
        return true;
    else
        return false;
}

int length_queue(PNODE pHead)
{
    PNODE p = pHead->pNext;
    int len = 0;
    while (NULL != p)
    {
        len++;
        p = p->pNext;
    }    
    return len;
}



bool InQueue(PNODE pHead, int val)
{
    PNODE p = pHead;
    while (NULL !=p->pNext)
    {
        p = p->pNext;
    }
    PNODE pNew = (PNODE)malloc(sizeof(Node));
    if (NULL == p)
    {
        printf("失败");
        exit(-1);
    }
    pNew->data = val;
    
    p->pNext = pNew;
    pNew->pNext = NULL;
    return true;
}
bool OutQueue(PNODE pHead, int* val)
{
    PNODE q = pHead->pNext;
    *val = q->data;
    pHead->pNext = pHead->pNext->pNext;
    free(q);
    q = NULL;
    return true;
}

int main(void)
{
    PNODE pHead = NULL;
    int val;
    pHead = create_queue();
    Travers(pHead);
    printf("\n");
    InQueue(pHead,1);
    InQueue(pHead,2);
    OutQueue(pHead, &val);
    OutQueue(pHead, &val);
    OutQueue(pHead, &val);
    Travers(pHead);

return 1;
}
View Code

循环队列

 为什么要有循环队列

为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列。
被掰弯的单链表就是循环链表

 

 由上图运行一下程序可自行体会,上边说的把链式队列掰弯其实不准确,准确的应该是把数组链表掰弯形成的循环队列,注意头结点的存在!!!!循环队列比链式队列相对更安全更简洁;

完整程序

# include <stdio.h>
# include <malloc.h>
#define l_queue  6    //所需队列长度
typedef struct Queue
{
    int* pBase;        //生成队列的大小
    int front;        //队尾
    int rear;        //队头
}QUEUE;

void init(QUEUE*);                    //初始化
bool in_queue(QUEUE*, int val);        //入队
void traverse_queue(QUEUE*);        //遍历队列
bool full_queue(QUEUE*);            //判断是否为满
bool out_queue(QUEUE*, int*);        //出队
bool emput_queue(QUEUE*);            //判断是否位空

int main(void)
{
    printf("                                   pQ->rear      pQ->pBase     pQ->front  \n");
    printf("                                    队头          队列大小        队尾    \n");
    printf("*******************\n");
    QUEUE Q;
    int val;

    init(&Q);
    in_queue(&Q, 10);
    printf("当前队列内容为:");
    traverse_queue(&Q);
    in_queue(&Q, 20);
    printf("当前队列内容为:");
    traverse_queue(&Q);
    in_queue(&Q, 30);
    printf("当前队列内容为:");
    traverse_queue(&Q);
    in_queue(&Q, 40);
    printf("当前队列内容为:");
    traverse_queue(&Q);
    in_queue(&Q, 50);
    printf("当前队列内容为:");
    traverse_queue(&Q);
    in_queue(&Q, 60);
    printf("当前队列内容为:");
    traverse_queue(&Q);
    in_queue(&Q, 70);
    printf("当前队列内容为:");
    traverse_queue(&Q);
    in_queue(&Q, 80);
    printf("当前队列内容为:");
    traverse_queue(&Q);

    if (out_queue(&Q, &val))
    {
        printf("当前队列内容为:");
    }
    else
    {
        printf("出队失败!\n");
    }
    traverse_queue(&Q);

    if (out_queue(&Q, &val))
    {
        printf("当前队列内容为:");
    }
    else
    {
        printf("出队失败!\n");
    }
    traverse_queue(&Q);
    if (out_queue(&Q, &val))
    {
        printf("当前队列内容为:");
    }
    else
    {
        printf("出队失败!\n");
    }
    traverse_queue(&Q);
    if (out_queue(&Q, &val))
    {
        printf("当前队列内容为:");
    }
    else
    {
        printf("出队失败!\n");
    }
    traverse_queue(&Q);
    if (out_queue(&Q, &val))
    {
        printf("当前队列内容为:");
    }
    else
    {
        printf("出队失败!\n");
    }
    traverse_queue(&Q);
    if (out_queue(&Q, &val))
    {
        printf("当前队列内容为:");
    }
    else
    {
        printf("出队失败!\n");
    }
    traverse_queue(&Q);
    return 0;
}

void init(QUEUE* pQ)
{
    pQ->pBase = (int*)malloc(sizeof(int) * l_queue);
    pQ->front = 0;
    pQ->rear = 0;
}

bool full_queue(QUEUE* pQ)
{
    if ((pQ->rear + 1) % l_queue == pQ->front)
        return true;
    else
        return false;
}

bool in_queue(QUEUE* pQ, int val)
{
    if (full_queue(pQ))
    {
        return false;
    }
    else
    {
        printf("                                      %d          %d         %d  \n", pQ->rear, pQ->pBase, pQ->front);
        pQ->pBase[pQ->rear] = val;
        pQ->rear = (pQ->rear + 1) % l_queue;
        printf("                                      %d          %d         %d  \n", pQ->rear, pQ->pBase, pQ->front);
        printf("*******************\n");
        return true;
    }
}

void traverse_queue(QUEUE* pQ)
{
    int i = pQ->front;

    while (i != pQ->rear)
    {
        printf("%d  ", pQ->pBase[i]); 
        i = (i + 1) % l_queue;
    }
    printf("\n");

    return;
}

bool emput_queue(QUEUE* pQ)
{
    if (pQ->front == pQ->rear)
        return true;
    else
        return false;
}

bool out_queue(QUEUE* pQ, int* pVal)
{
    if (emput_queue(pQ))
    {
        return false;
    }
    else
    {
        printf("                                      %d          %d         %d  \n", pQ->rear, pQ->pBase, pQ->front);
        pQ->front = (pQ->front + 1) % l_queue;
        printf("                                      %d          %d         %d  \n", pQ->rear, pQ->pBase, pQ->front);
        printf("*******************\n");
        return true;
    }
}
完整代码

定义声明

# include <stdio.h>
# include <malloc.h>
#define l_queue 6 //所需队列长度
typedef struct Queue
{
int* pBase; //生成队列的大小
int front; //队尾
int rear; //队头
}QUEUE;

void init(QUEUE*); //初始化
bool in_queue(QUEUE*, int val); //入队
void traverse_queue(QUEUE*); //遍历队列
bool full_queue(QUEUE*); //判断是否为满
bool out_queue(QUEUE*, int*); //出队
bool emput_queue(QUEUE*); //判断是否位空

创建一个队列

void init(QUEUE* pQ)
{
    pQ->pBase = (int*)malloc(sizeof(int) * l_queue);
    pQ->front = 0;
    pQ->rear = 0;
}

判断为空         当队列删除元素到head=rear的时候,我们认为队列空了。pQ->front == pQ->rear

判读为满         当队列添加元素到rear的下一个元素是head的时候,也就是转圈子要碰头了,我们就认为队列满了。pQ->rear + 1) % l_queue == pQ->front

 判断 空满

bool full_queue(QUEUE* pQ)
{
    if ((pQ->rear + 1) % l_queue == pQ->front)
        return true;
    else
        return false;
}

bool emput_queue(QUEUE* pQ)
{
    if (pQ->front == pQ->rear)
        return true;
    else
        return false;
}

遍历队列

void traverse_queue(QUEUE* pQ)
{
    int i = pQ->front;

    while (i != pQ->rear)
    {
        printf("%d  ", pQ->pBase[i]); 
        i = (i + 1) % l_queue;
    }
    printf("\n");

    return;
}

入队

bool in_queue(QUEUE* pQ, int val)
{
    if (full_queue(pQ))
    {
        return false;
    }
    else
    {        pQ->pBase[pQ->rear] = val;
        pQ->rear = (pQ->rear + 1) % l_queue;
        return true;
    }
}

出队

循环队列申请了一部分固定内存,内存即不出去,也也不进来,无需free();

bool out_queue(QUEUE* pQ, int* pVal)
{
    if (emput_queue(pQ))
    {
        return false;
    }
    else
    {
        pQ->front = (pQ->front + 1) % l_queue;
        return true;
    }
}

 

posted @ 2020-05-18 22:59  forup  阅读(282)  评论(0)    收藏  举报