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


七.总结:


相关推荐
向阳@向远方18 分钟前
第二章 简单程序设计
开发语言·c++·算法
JeffersonZU29 分钟前
Linux/Unix进程概念及基本操作(PID、内存布局、虚拟内存、环境变量、fork、exit、wait、exec、system)
linux·c语言·unix·gnu
github_czy1 小时前
RRF (Reciprocal Rank Fusion) 排序算法详解
算法·排序算法
许愿与你永世安宁2 小时前
力扣343 整数拆分
数据结构·算法·leetcode
爱coding的橙子2 小时前
每日算法刷题Day42 7.5:leetcode前缀和3道题,用时2h
算法·leetcode·职场和发展
ruanjiananquan992 小时前
c,c++语言的栈内存、堆内存及任意读写内存
java·c语言·c++
满分观察网友z2 小时前
从一次手滑,我洞悉了用户输入的所有可能性(3330. 找到初始输入字符串 I)
算法
持梦远方2 小时前
C 语言基础入门:基本数据类型与运算符详解
c语言·开发语言·c++
YuTaoShao3 小时前
【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
java·算法·leetcode·矩阵
Heartoxx3 小时前
c语言-指针(数组)练习2
c语言·数据结构·算法