队列的基本结构与基本操作函数

  与栈的结构相反,队列的结构具有一种“先入先出”的特点,最主要的原因仍然在于,队列只允许由一端插入元素而从另一端释放元素。这就与现实生活中的队列具有极其相似的特点,插入元素行为只在队尾端实现(即通过移动队尾指针可完成目的),而输出元素在队首端实现(移动队首指针可完成目的)。

  队列一般具有两种表示方法,包括顺序队列以及链队列,先由链队列开始,链队列顾名思义,是由链表表示的队列,需要有两个分别指示队首与队尾的指针 (头指针与尾指针)。同时,需要设置一个头结点,初始化将头指针与尾指针均指向头结点,这也作为链队列是否为空的判别依据。链队列的基本结构代码与示意图如下,链队列的单个节点用Qnode进行表示,而头指针与尾指针用新定义的结构体LinkQue来进行表示  队列结构的代码以及示意图如下:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
typedef struct Qnode
{
    int data;
    struct Qnode*next;
}Qnode,*Qptr;
typedef struct{
   Qptr head;
   Qptr tail;
}LinkQue;
链式队列示意图

 在明确了队列的结构后,首先需要定义队列的初始化操作,主要思路包括:1)新建一个空队列q,将队列的队首指针与队尾指针初始化指向同一个结点q(此处空队列与新建结点重名,在队列未插入新元素时两者均只是一个结点,换言之,是同一个事物) 2)将q队首指针所指结点(即队首元素)的后继元素指为空。具体代码以及示意图如下:

void Init(LinkQue q)
{
    q.head=(Qnode*)malloc(sizeof(Qnode));
    q.head=q.tail;
    q.head->next=NULL;
}
队列初始化

  由于在队列之中,插入节点的操作仅仅在队尾进行,需要完成的步骤只有新建结点,以及处理新节点与尾指针尾结点的关系。 队列的插入节点操作主要思路如下:1)新建一个节点p,p的数据域用int类型的变量e来赋值  2)p的后继结点赋值为NULL,同时将节点p作为尾指针tail所指的节点的后继(tail指针初始化指向头结点,这步操作意为将新节点p链接至头结点后) 3)将tail指针赋值为指针p。   代码以及示意图如下所示:

void Insert(LinkQue q,int e)
{
    Qptr p;
    p=(Qnode*)malloc(sizeof(Qnode));
    p->data=e;
    p->next=NULL;
    q.tail->next=p;
    q.tail=p;
}
队列在队尾插入节点

   

   删除结点操作与插入节点操作相反,如果队列不空,则删除队首的节点。主要思路如下:1)新建一个指针p,将指针p指向q的队首指针所指节点的后继节点 2)重新定义队首节点的后继结点,将该后继结点赋值为p的后继节点 3)进行条件判断,如果p指针与队列的尾部指针指向同一段内存 ,将队首指针与队尾指针指向同一段内存,即队列为空。4)释放p指针所指的节点内存

void Delete(LinkQue q,int e)
{
    Qptr p;
    p=q.head->next;
    e=p->data;
    q.head->next=p->next;
    if(q.tail==p)
    {
        q.tail=q.head;
    }
    free(p);
}
队首节点p出队

   在插入节点与删除结点操作完成后,需要了解销毁队列的操作,销毁队列就是不停地出队的重复。主要思路如下:1)通过while循环来控制队列指针的移动以及释放结点操作,当队列q的head指针指向的结点不为空时,将tail指针指向head指针的后继结点 2)释放head指针所指的结点的内存空间 3)将head指针赋值为tail指针的值,即head指针继续向后挪一位。具体代码如下:

void Destroy(LinkQue q)
{
    while(q.head!=NULL)
    {
        q.tail=q.head->next;
        free(q.head);
        q.head=q.tail;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_38846633/article/details/81363521