CPP使用单链表实现队列

队列

队列是一种操作受限的线性表,先进先出

数据处理尾端进入,从头部离开

数据的入队理解为线性表的尾插法,数据的出队理解为线性表的指定位置删除

在程序中,队列使用的是结构体,而非结构体指针,所以在初始化时也就不用为队列申请内存了

数据组成

使用单链表,双链表都行,这里我们使用单链表创建

在此程序里,链表作为基层单元被使用,并且这个单链表将有头结点.

#include 
#include 

typedef int ElemType;
typedef struct LinkNode
{
    ElemType data;
    LinkNode *next;
} LinkNode;

除此之外,我们还需要定义另外的结构体,用以表示较为活跃的头部和尾部

整体的逻辑是通过头尾的变化,来影响链表节点的增删,如果忽略操作先后的话,可以视为通过队列控制节点的增删

初始化

我们并未明显的将链表节点的内存申请定义出来,而是放在了初始化方法的内部,之后使用队列的头尾指针指向它,因为对外来说,我们统一使用队列来控制链表,所以不需要在外部定义链表,这个链表被我们严肃的封装在了队列里

void Init(Queue &Q)
{
    LinkNode *L = (LinkNode *)calloc(1, sizeof(LinkNode));
    Q.head = L;
    Q.tail = L;
}

入队

尾插法入队

此时队列的头尾已经保存了链表节点的地址,所以我们只需要使用队列作为形参即可,依旧可以实现对队列的操作

相当将队列的头尾指针拿到列明面上来,那么出入队也就是对头尾指针数据的操作

此时的入队是对尾节点的操作,在变更指向之前,需要先把链表续上.

void EnQueue(Queue &Q, ElemType data)
{
    /*创建节点,追加至尾部*/
    LinkNode *tempNode = (LinkNode *)calloc(1, sizeof(LinkNode));
    tempNode->data = data;

    Q.tail->next = tempNode; // 先把链表续上
    Q.tail = tempNode;
}

当我们使用calloc方法申请内存时,tempNode->next已经被设置为NULL

出队

头结点之后的第一个位置结点删除.

设计出队的返回值为布尔类型,并使用引用形参带回数据

我们使用的是带有头结点的链表,所以当两者相等的时候,即为第一位置的节点已经出队了,所以无可出队

队列的head指针永远指向的是头结点,而不是第一个节点,就像核酸窗口里面的检测人员不会变,会变的是外面排队的人,那么我们在处理删除的刚好是尾结点的时候,就要强制的让队列尾指针指向队列头结点来表示队列为空状态

不仅要考虑头结点,还有考虑尾结点,最后不要忘记释放内存

bool DeQueue(Queue &Q, ElemType &data)
{
    /*我们使用的是带有头结点的链表,所以当两者相等的时候,即为第一位置的节点已经出队了,所以无可出队*/
    if (Q.head == Q.tail)
    {
        return false;
    }
    LinkNode *tempNode = Q.head->next; // 临时节点指向第一位置节点
    data = tempNode->data;              // 拿到数据

    Q.tail->next = tempNode->next; // 这里是尾结点也没关系
    if (Q.tail == tempNode)        // 这里需要处理尾结点
    {
        Q.tail = Q.head;
    }

    free(tempNode);
    return true;
}

也就是说,我们一般对于定义为结构体的数据类型,不会使用指针,就像这里的引用,它已经完全的指向了从内存中申请来的链表空间的头和尾.我们只要在方法中进行对应的链表加工即可

可以将这个队列看做趁手的工具,用来操作数据,就像数组可以使用下标访问

将链表节点试做基本的结构类型,就像int,如此便可理解到一点套娃的门道.

代码

#include 
#include 

typedef int ElemType;
typedef struct LinkNode
{
    ElemType data;
    LinkNode *next;
} LinkNode;

typedef struct
{
    LinkNode *head, *tail;
} Queue;

void Init(Queue &Q)
{
    LinkNode *L = (LinkNode *)calloc(1, sizeof(LinkNode));
    Q.head = L;
    Q.tail = L;
}

void EnQueue(Queue &Q, ElemType data)
{
    /*创建节点,追加至尾部*/
    LinkNode *tempNode = (LinkNode *)calloc(1, sizeof(LinkNode));
    tempNode->data = data;

    Q.tail->next = tempNode; // 先把链表续上
    Q.tail = tempNode;
}

bool DeQueue(Queue &Q, ElemType &data)
{
    /*我们使用的是带有头结点的链表,所以当两者相等的时候,即为第一位置的节点已经出队了,所以无可出队*/
    if (Q.head == Q.tail)
    {
        return false;
    }
    LinkNode *tempNode = Q.head->next; // 临时节点指向第一位置节点
    data = tempNode->data;              // 拿到数据

    Q.head->next = tempNode->next; // 这里是尾结点也没关系
    if (Q.tail == tempNode)        // 这里需要处理尾结点
    {
        Q.tail = Q.head;
    }

    free(tempNode);
    return true;
}
int main()
{
    Queue Q;
    bool flag;
    ElemType element; // 存储出队元素
    Init(Q);
    // EnQueue(Q, 3);
    EnQueue(Q, 4);
    EnQueue(Q, 5);
    EnQueue(Q, 6);
    EnQueue(Q, 7);
    flag = DeQueue(Q, element);
    if (flag)
    {
        printf("dequeue success %d\n", element);
    }
    else
    {
        printf("dequeue fault\n");
    }
}

你可能感兴趣的:(链表,数据结构,c++)