数据结构-3.6.队列的链式实现

队列可以理解为单链表的阉割版,相比单链表而言,队列只有在添加和删除元素上和单链表有区别


一.队列的链式实现:

1.图解:

2.代码:

cpp 复制代码
#include<stdio.h>
​
typedef struct LinkNode //链式队列结点 
{
    int data;
    struct LinkNode *next;
}LinkNode;
​
typedef struct //链式队列 
{
    LinkNode *front; //队头指针
    LinkNode *rear; //队尾指针 
}LinkQueue;
​
int main()
{
    return 0;
}

二.初始化队列:

1.带头结点:

a.图解:
b.代码:
cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
​
typedef struct LinkNode //链式队列结点 
{
    int data;
    struct LinkNode *next;
}LinkNode;
​
typedef struct //链式队列 
{
    LinkNode *front; //队头指针
    LinkNode *rear; //队尾指针 
}LinkQueue;
​
//初始化队列(带头结点)
void InitQueue(LinkQueue &Q)
{
    //初始化时,front和rear都指向头结点
    Q.front = Q.rear = (LinkNode *)malloc(sizeof(LinkNode));//malloc用于申请一个头结点 
    Q.front -> next=NULL; //头指针下一个元素为NULL,因为一开始什么都没有 
} 
​
//判断队列是否为空
bool IsEmpty(LinkQueue Q)
{
    if( Q.front==Q.rear ) //也可以这么判断:如果Q.front -> next==NULL,此时队列为空 
    {
        return true; //代表队列为空 
    }
    else
    {
        return false; //代表队列不为空 
    }
} 
​
int main()
{
    LinkQueue Q;//声明一个队列
    InitQueue(Q); //初始化队列
    //后续操作。。。 
    return 0;
}

2.不带头结点:

a.图解:
b.代码:
cpp 复制代码
#include<stdio.h>
​
typedef struct LinkNode //链式队列结点 
{
    int data;
    struct LinkNode *next;
}LinkNode;
​
typedef struct //链式队列 
{
    LinkNode *front; //队头指针
    LinkNode *rear; //队尾指针 
}LinkQueue;
​
//初始化队列(不带头结点)
void InitQueue(LinkQueue &Q)
{
    //初始化时,front和rear都指向NULL
    Q.front=NULL;
    Q.rear=NULL; 
}
​
//判断队列是否为空
bool IsEmpty(LinkQueue Q)
{
    if( Q.front==NULL ) //只需要看头指针是否等于NULL即可,也可以看Q.rear是否为NULL,是的话队列为空 
    {
        return true; //代表队列为空,头指针为NULL,代表没有头指针,自然队列为空 
    }
    else
    {
        return false; //代表队列不为空 
    }
}  
​
int main()
{
    LinkQueue Q;//声明一个队列
    InitQueue(Q); //初始化队列
    //后续操作。。。
    return 0;
}

三.入队操作:

1.带头结点:

a.图解:
b.代码:
cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
​
typedef struct LinkNode //链式队列结点 
{
    int data;
    struct LinkNode *next;
}LinkNode;
​
typedef struct //链式队列 
{
    LinkNode *front; //队头指针
    LinkNode *rear; //队尾指针 
}LinkQueue;
​
//初始化队列(带头结点)
void InitQueue(LinkQueue &Q)
{
    //初始化时,front和rear都指向头结点
    Q.front = Q.rear = (LinkNode *)malloc(sizeof(LinkNode));//malloc用于申请一个头结点 
    Q.front -> next=NULL; //头指针下一个元素为NULL,因为一开始什么都没有 
} 
​
//判断队列是否为空
bool IsEmpty(LinkQueue Q)
{
    if( Q.front==Q.rear ) //也可以这么判断:如果Q.front -> next==NULL,此时队列为空 
    {
        return true; //代表队列为空 
    }
    else
    {
        return false; //代表队列不为空 
    }
} 
​
//新元素入队(带头结点)
void EnQueue(LinkQueue &Q,int x)//只是让x入队,不改变x的值,所以无需&
{
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode)); //用malloc申请一个新结点用来存要入队的元素 
    s->data = x; //把新插入的元素x放入新结点中 
    s->next = NULL; //由于队列入队的操作是在表尾的位置进行,因此新插入的结点是队列的最后一个结点,后面就是NULL 
    Q.rear->next = s;
    /*由于一开始rear指针指向的是当前的表尾结点,而新插入的新结点应该连到表尾结点之后,
      所以要把rear指向的结点next指针域指向新结点s */
    Q.rear = s; //修改表尾指针指向新添加的元素,新添加的元素就是表尾元素 
} 
​
int main()
{
    LinkQueue Q;//声明一个队列
    InitQueue(Q); //初始化队列
    //后续操作。。。 
    return 0;
}

2.不带头结点:

a.图解:
b.代码:
cpp 复制代码
#include<stdio.h>
#include<stdlib.h> 
​
typedef struct LinkNode //链式队列结点 
{
    int data;
    struct LinkNode *next;
}LinkNode;
​
typedef struct //链式队列 
{
    LinkNode *front; //队头指针
    LinkNode *rear; //队尾指针 
}LinkQueue;
​
//初始化队列(不带头结点)
void InitQueue(LinkQueue &Q)
{
    //初始化时,front和rear都指向NULL
    Q.front=NULL;
    Q.rear=NULL; 
}
​
//判断队列是否为空
bool IsEmpty(LinkQueue Q)
{
    if( Q.front==NULL ) //只需要看头指针是否等于NULL即可,也可以看Q.rear是否为NULL,是的话队列为空 
    {
        return true; //代表队列为空,头指针为NULL,代表没有头指针,自然队列为空 
    }
    else
    {
        return false; //代表队列不为空 
    }
}  
​
//新元素入队(不带头结点)
void EnQueue(LinkQueue &Q,int x)
{
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));//用malloc申请一个新结点用来存要入队的元素 
    s->data = x;//把新插入的元素x放入新结点中
    s->next = NULL;//由于队列入队的操作是在表尾的位置进行,因此新插入的结点是队列的最后一个结点,后面就是NULL 
    if( Q.front==NULL ) //在空队列中插入第一个元素,插入第一个元素时Q.front为NULL,因为刚开始front和rear都指向NULL 
    { //如果队列为空,那么插入的元素就是队列第一个元素 
        //修改队头和队尾指针 
        Q.front = s;
        Q.rear = s;
    }
    else
    {
        Q.rear->next = s;//新结点插入到rear结点之后 
        Q.rear = s;//修改rear指针 
    }
} 
​
int main()
{
    LinkQueue Q;//声明一个队列
    InitQueue(Q); //初始化队列
    //后续操作。。。
    return 0;
}

四.出队操作:

1.带头结点:

a.图解:

不是最后一个元素出队:

最后一个元素出队:

b.代码:
cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
​
typedef struct LinkNode //链式队列结点 
{
    int data;
    struct LinkNode *next;
}LinkNode;
​
typedef struct //链式队列 
{
    LinkNode *front; //队头指针
    LinkNode *rear; //队尾指针 
}LinkQueue;
​
//初始化队列(带头结点)
void InitQueue(LinkQueue &Q)
{
    //初始化时,front和rear都指向头结点
    Q.front = Q.rear = (LinkNode *)malloc(sizeof(LinkNode));//malloc用于申请一个头结点 
    Q.front -> next=NULL; //头指针下一个元素为NULL,因为一开始什么都没有 
} 
​
//判断队列是否为空
bool IsEmpty(LinkQueue Q)
{
    if( Q.front==Q.rear ) //也可以这么判断:如果Q.front -> next==NULL,此时队列为空 
    {
        return true; //代表队列为空 
    }
    else
    {
        return false; //代表队列不为空 
    }
} 
​
//队头元素出队(带头结点)
bool DeQueue(LinkQueue &Q,int &x) //最终x会变为要删除的元素,所以需要& 
{
    if( Q.front==Q.rear )
    {
        return false;//空队,就无法出队即删除元素 
    }
    //此时队列不为空
    //Q.front为头结点 
    LinkNode *p = Q.front->next; //让p指针指向要删除的结点,对于带头结点的队列来说就是要删除头结点的后一个结点 
    x = p->data; //用变量x返回队头元素即要删除的元素 
    Q.front->next = p->next; //修改头结点的next指针
    if( Q.rear==p ) //此次是最后一个结点出队,最终就是空队列即Q.rear=Q.front 
    {
        Q.rear=Q.front; //修改rear指针 
    } 
    free(p); //释放结点空间
    return true; 
} 
​
int main()
{
    LinkQueue Q;//声明一个队列
    InitQueue(Q); //初始化队列
    //后续操作。。。 
    return 0;
}

2.不带头结点:

a.图解:
b.代码:
cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
​
typedef struct LinkNode //链式队列结点 
{
    int data;
    struct LinkNode *next;
}LinkNode;
​
typedef struct //链式队列 
{
    LinkNode *front; //队头指针
    LinkNode *rear; //队尾指针 
}LinkQueue;
​
//初始化队列(不带头结点)
void InitQueue(LinkQueue &Q)
{
    //初始化时,front和rear都指向NULL
    Q.front=NULL;
    Q.rear=NULL; 
}
​
//判断队列是否为空
bool IsEmpty(LinkQueue Q)
{
    if( Q.front==NULL ) //只需要看头指针是否等于NULL即可,也可以看Q.rear是否为NULL,是的话队列为空 
    {
        return true; //代表队列为空,头指针为NULL,代表没有头指针,自然队列为空 
    }
    else
    {
        return false; //代表队列不为空 
    }
}  
​
//队头元素出队(不带头结点)
bool DeQueue(LinkQueue &Q,int &x)
{
    if( Q.front==NULL )
    {
        return false; //空队 
    }
    LinkNode *p=Q.front; //p指向此次出队的结点即front指针指向的结点出队 
    x = p->data; //用变量x返回队头元素 
    Q.front = p->next; //由于没有头结点,所以每次有队头元素出队后都需要修改front指针的指向 
    if( Q.rear==p ) //此次是最后一个结点出队,最终就是空队列 
    {
        Q.front=NULL; //front指向NULL 
        Q.rear=NULL; //rear指向NULL  
    } 
    free(p); //释放结点空间 
    return true; 
} 
​
int main()
{
    LinkQueue Q;//声明一个队列
    InitQueue(Q); //初始化队列
    //后续操作。。。
    return 0;
}

五.队列满的条件:


六.统计队列的长度:

思路:

从队头结点开始依次往后遍历,统计总共有多少个结点,显然时间复杂度为O(n)。


七.总结:


相关推荐
xiaoshiguang314 分钟前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡15 分钟前
【C语言】判断回文
c语言·学习·算法
别NULL17 分钟前
机试题——疯长的草
数据结构·c++·算法
TT哇21 分钟前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
ZSYP-S2 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos2 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习2 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA2 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo2 小时前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
jackiendsc2 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法