数据结构-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)。


七.总结:


相关推荐
Zfox_16 分钟前
【Linux】进程信号全攻略(二)
linux·运维·c语言·c++
shymoy21 分钟前
Radix Sorts
数据结构·算法·排序算法
风影小子29 分钟前
注册登录学生管理系统小项目
算法
黑龙江亿林等保32 分钟前
深入探索哈尔滨二级等保下的负载均衡SLB及其核心算法
运维·算法·负载均衡
少年负剑去34 分钟前
第十五届蓝桥杯C/C++B组题解——数字接龙
c语言·c++·蓝桥杯
lucy1530275107934 分钟前
【青牛科技】GC5931:工业风扇驱动芯片的卓越替代者
人工智能·科技·单片机·嵌入式硬件·算法·机器学习
杜杜的man1 小时前
【go从零单排】迭代器(Iterators)
开发语言·算法·golang
小沈熬夜秃头中୧⍤⃝1 小时前
【贪心算法】No.1---贪心算法(1)
算法·贪心算法
木向2 小时前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越2 小时前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法