04 链式队列的实现

带头节点的链式队列:

  1. 初始化:rear和front指针都指向头节点
  2. 入队:向rear指向的节点后插入新节点,并让rear指针移动指向新的队尾节点
  3. 出队:front指针始终指向头节点,即删除头节点后一个节点;最后一个节点删除需要让rear指针和front指针同时指向头节点,即恢复初始化后的样子
  4. 队空判断:rear = front
  5. 最后一个元素判断:front->next = rear
    (C语言语法应该是 rear和front前面加上’.'运算符,以下都省略掉了)

不带头节点的链式队列:

  • 初始化:rear=front=NULL
  • 入队:第一个节点插入需要额外考虑(rear和front指针指向队头元素),之后节点插入和带头结点一样
  • 出队: 不同于带头节点,出队时需要让front指针后移,并free掉删除的那个节点;最后一个节点删除需要让front和rear指针都指向NULL
  • 队空判断:rear=front=NULL
  • 最后一个元素判断:front->next=NULL(或者是rear=front)

CODE

#include <stdio.h>
#include <stdlib.h>

// 2.2 链式队列
// 链式栈可以完全借用单链表结构,它是操作首先的单链表,及只能在头部位置进行操作。
// 对于链式队列,需要有两个指针,不管入队、出队,front指针不需要移动,在出队时,rear指针需要移动


// 结构体
// 链式队列在单链表的基础上加了rear和front指针,使用rear和front指针进行一系列操做
typedef struct LNode{
    int data;
    LNode *next;
}LNode,*LinkList;

typedef struct LinkQueue{
    LNode *front;
    LNode *rear;
};

// =================带头节点=================

// 初始化(带头节点)
// 在顺序存储队列中,我们让rear和front都为0, 在链式队列中,我们创建头节点,并让rear和front都指向这个头节点
bool initLinkQueue(LinkQueue &que){
    que.rear = que.front = (LNode*) malloc(sizeof (LNode));
    que.rear->next = NULL;
    return true;
}

// 入队操作(带头节点)
// 在顺序存储队列中,我们让往rear指向的位置塞入元素后右移(rear指向末尾元素后一个位置),然而在链式存储队列中rear指向最后一个元素
// 即对头节点进行尾插法,除此之外需要rear指针的移动
// (1) 给新元素分配一个空间,让newpt指向它
// (2) 对rear指向的节点使用尾插法,在插入元素后移动rear指针
bool enterQueue(LinkQueue &que, int num){
    LNode *newpt = (LNode*) malloc(sizeof (LNode));
    newpt->next = NULL;
    newpt->data = num;
    que.rear->next = newpt;
    que.rear = newpt;
    return true;
}

// 出队操作(带头节点)
// 在顺序存储队列,取出front指针指向的元素后front后移,这里对头节点后一个元素进行删除操作,和出栈一样,rear需要指向待删除的前一个节点
// (1) 判断是否为空,即判断rear和front是否指向同一个元素
// (2) 对节点进行删除,如果时最后一个元素的出队,让rear和front都指向头节点
bool leftQue(LinkQueue &que, int &a){
    if(que.front == que.rear){
        return false;
    }
    LNode *nod = que.front->next;
    a = nod->data;
    if (que.front->next == que.rear){
        que.rear = que.front;
    }
    que.front->next = nod->next;
    free(nod);
    return true;
}



// =================不带头节点=================

// 没有头节点,则rear和front都指向NULL
bool initLinkQue2(LinkQueue &que){
    que.rear = que.front = NULL;
    return true;
}

// 判空,与带头节点判空不一样
bool isEmpty(LinkQueue que){
    return que.rear == NULL;    // 或que.front=NULL
}

// 入队
// (1) 由于没有头节点,第一次入队需要新建一个头节点
// (2) 如果不为空,则和带头节点入队方法一样
bool enterQue2(LinkQueue &que, int num){
    LNode *newpt = (LNode*) malloc(sizeof (LNode));
    newpt->next = NULL;
    newpt->data = num;
    if (isEmpty(que)){
        que.rear = que.front = newpt;
        return true;
    }
    que.rear->next = newpt;
    que.rear = newpt;
    return true;
}

// 出队
// (1) 先判断队是否空
// (2) 由于没有头节点,对第一个节点进行删除,需要将front指针后移,并free掉之前的节点
// (3) 最后一个节点删除,需要将rear和front重新置为NULL,即初始化后的摸样

bool leftQue2(LinkQueue &que, int &a){
    if(isEmpty(que)){
        return false;
    }
    if(que.front->next == NULL){
        a = que.front->data;
        que.front = que.rear = NULL;
        return true;
    }
    a = que.front->data;
    LNode *pt = que.front;    // pt指向队头
    que.front = pt->next;     // front指针后移
    free(pt);
    return true;
}


int main() {
//    LinkQueue que;
//    initLinkQueue(que);
//    int a;
//    enterQueue(que,29);
//    enterQueue(que,18);
//    enterQueue(que,15);
//    leftQue(que,a);
//    printf("%d\t",a);
//    leftQue(que,a);
//    printf("%d\t",a);
//    leftQue(que,a);
//    printf("%d\n",a);

    int b;
    LinkQueue que2;
    initLinkQue2(que2);
    enterQue2(que2,29);
    enterQue2(que2,18);
    enterQue2(que2,15);
    leftQue2(que2,b);
    printf("%d\t",b);
    leftQue2(que2,b);
    printf("%d\t",b);
    leftQue2(que2,b);
    printf("%d\n",b);
    return 0;
}

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值