若用户无法估计所用队列的长度,则宜采用链队列

链式队列表示:如图

队列的链式表示和实现_结点

 

 

Q.front 指向头结点

Q.rear 指向尾结点

链队列的类型定义:

#define MAXQSIZE 100 //最大队列长度
typedef struct Qnode{
    // 数据域
    QElemType data;
    // 指针域
    // 栈是stack,所以是SNode
    // 队列是 Queue,所以是QNode
    // 所指向结点仍然是 Qnode 这种类型
    stuct Qnode *next;
}QNode, *QuenPtr;

 

 

typedef struct{
    // 队头指针
    QueuePtr front;

    // 队尾指针
    QueuePtr rear;

// 链式队列
} LinkQueue;

 

 

链队列运算指针的变化状况

① 空队列时,头指针尾指针都指向一个结点,如图:

队列的链式表示和实现_出队_02

 

 

② 元素 x 入队列,Q.rear 只能指向队尾

队列的链式表示和实现_数据_03

 

 

再有元素入队,如下图

队列的链式表示和实现_结点_04

 

 

 

③ 要出队时,只能出 x ,不能直接出 y

队列的链式表示和实现_链队列_05

 

 

 

------------------------------------------------------------------------------------------------------------------------------------------------

 

链队列的操作——链队列初始化

直接在内存当中找到一个头结点,然后首尾指针都指向头结点

#define MAXQSIZE 100 //最大队列长度
typedef struct Qnode{
    // 数据域
    QElemType data;
    // 指针域
    // 栈是stack,所以是SNode
    // 队列是 Queue,所以是QNode
    // 所指向结点仍然是 Qnode 这种类型
    stuct Qnode *next;
}QNode, *QuenPtr;


typedef struct{
    // 队头指针
    QueuePtr front;

    // 队尾指针
    QueuePtr rear;

// 链式队列
} LinkQueue;


Status InitQueue(LinkQueue &Q){

    Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));

    // 加一个内存溢出判断,防止出问题
    if(!Q.front){
        exit(OVERFLOW);
    }
    // next 域置空
    Q.front->next = NULL;
}

 

 

 

链队列的操作——销毁栈队列

销毁栈队列就是从队头结点开始,依次释放所有结点

Status DestroyQueue(LinkQueue &Q){
    while(Q.front){
        p = Q.front -> next;
        free(Q.front);
        Q.front = p;
        return OK; } }

 

或者使用如下代码:

Status DestroyQueue(LinkQueue &Q){
    Q.rear = Q.front -> next;
    free(Q.front);
    Q.front = Q.rear;
    return OK;
}

 

 

链队列的操作——将元素 e 入队

队列的链式表示和实现_头结点_06

链队列入队,只能在队尾入,也就是从 an 后入队

#define MAXQSIZE 100 //最大队列长度
typedef struct Qnode{
    // 数据域
    QElemType data;
    // 指针域
    // 栈是stack,所以是SNode
    // 队列是 Queue,所以是QNode
    // 所指向结点仍然是 Qnode 这种类型
    stuct Qnode *next;
}QNode, *QuenPtr;


typedef struct{
    // 队头指针
    QueuePtr front;

    // 队尾指针
    QueuePtr rear;

// 链式队列
} LinkQueue;

Status EnQueue(LinkQueue &Q, QElemType e){
    // 开辟一个内存空间
    p = (QueuePtr)malloc(sizeof(QNode));

    // 如果分配不成功,则直接退出
    if(!p){
        exit(OVERFLOW);
    }

    // 将 e 存入 p所指结点 的数据域,且将 P所指结点 
    p -> data = e;
    p -> next = NULL;

    // 尾指针所指结点的指针域修改,使其接上新添加的结点
    Q.rear -> next = p;

    // 修改尾指针所指向结点
    Q.rear = p;

    return OK;
}

 

 

链队列的操作——链队列出队

链队列的出队是从队头出队的,因此要删掉头结点后面的那个结点

队列的链式表示和实现_数据_07

 

直接修改前驱的指针域,就可以完成。最后再释放掉

① new 一个指针p,使 指针p 指向头结点后边那个结点

    p = Q.fornt -> next;

② 修改 Q.front -> next ,使其原本指向出队结点的指针域指向出队结点后边那个结点

    Q.front -> next = p -> next;

③ 释放掉指针P

    用 C++ 就是 delete p;

    用 C 就是 free(p);

④ 假如需要知道出队的元素是啥,就让 e 存放并返回:

    e = p -> data;

具体代码如下:

#define MAXQSIZE 100 //最大队列长度
typedef struct Qnode{
    // 数据域
    QElemType data;
    // 指针域
    // 栈是stack,所以是SNode
    // 队列是 Queue,所以是QNode
    // 所指向结点仍然是 Qnode 这种类型
    stuct Qnode *next;
}QNode, *QuenPtr;


typedef struct{
    // 队头指针
    QueuePtr front;

    // 队尾指针
    QueuePtr rear;

// 链式队列
} LinkQueue;

Status DeQueue(LinkQueue &Q, QElemType &e){
    
    // 判空
    if(Q.front == Q.rear){
        return ERROR;
    }

    p = Q.front -> next;
    e = p -> data;
    Q.front -> next = p -> next;
    
    // 如果删除后,p 指针向后移动一个,下一个元素正好就是尾结点
    // 那么就不仅要修改头结点的指针,也要修改尾指针
    if(Q.rear == p){
        Q.rear = Q.front;
    }

    delete p;
    return OK;
}

 

 

链队列的操作——求链队列的队头元素

#define MAXQSIZE 100 //最大队列长度
typedef struct Qnode{
    // 数据域
    QElemType data;
    // 指针域
    // 栈是stack,所以是SNode
    // 队列是 Queue,所以是QNode
    // 所指向结点仍然是 Qnode 这种类型
    stuct Qnode *next;
}QNode, *QuenPtr;


typedef struct{
    // 队头指针
    QueuePtr front;

    // 队尾指针
    QueuePtr rear;

// 链式队列
} LinkQueue;

// 求链队列的队头元素
Status GetHead(LinkQueue Q, QElemType &e){
    if(Q.front == Q.rear){
        return ERRORl;
    }
    e = Q.front -> next -> data;
    return OK;
}