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

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


一.队列的链式实现:

1.图解:

2.代码:

#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.代码:
#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.代码:
#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.代码:
#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.代码:
#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.代码:
#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.代码:
#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)。


七.总结:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值