队列结构

从数据的逻辑结构来看,队列是一种线性结构。如果从数据的存储结构来进一步划分,队列结构包括两类。
1. 顺序队列结构:即使用一组地址连续的内存单元依次保存队列中的数据。在程序中,可以定义一个指定大小的结构数组作为队列。
2. 链式队列结构:即使用链表形式保存队列中各元素的值。

从数据的运算角度来分析,队列结构是按照“先进先出”的原则处理结点数据的。在队列结构中,数据运算非常简单。一般队列结构的基本操作只有
1. 入队列:将一个元素添加到队尾(相当于到队列最后排队等候)
2. 出队列:将队头的元素取出,同时删除该元素,使后一个元素成为队头。

准备数据

class DATA{
    String name;
    int age;
}

/*
 * 顺序结构队列
 * sequential queue
 */
class SQType{
    static final int QUEUELEN = 15;
    DATA[] data = new DATA[QUEUELEN];       // 队列顺序结构数组
    int head;       // 队头
    int tail;       // 队尾
}

在上述代码中,定义了队列结构的最大长度QUEUELEN,队列结构数据元素的类DATA及队列结构的类SQType。在类SQType中,data为数据元素,head为队头的序号,tail为队尾的序号。当head=0时表示队列为空,当tail=QUEUELEN时表示队列已满。

初始化队列结构

顺序初始化操作步骤如下:
1. 按符号常量QUEUELEN指定的大小申请一片内存空间,用来保存队列中的数据。
2. 设置head=0和tail=0,表示一个空栈。

SQType SQTypeInit(){    // 队列初始化
    SQType q;
    if((q=new SQType())!=null){     // 申请内存
        q.head = 0;                                         
        q.tail = 0;
        return q;
    }else{
        return null;
    }
}

在上述代码中,首先使用new关键字申请内存,申请成功后设置队头和队尾,然后返回申请内存的首地址。如果申请失败,将返回null。

判断空队列

判断空队列即判断一个队列结构是否为空。如果是空队列,则表示该队列结构中没有数据。此时可以进行入队列,但不可以进行出队列。

int SQTypeIsEmpty(SQType q){    // 判断队列空
    int temp = 0;
    if(q.head == q.tail)
        temp = 1;
    return temp;
}

在上述代码中,输入参数q是一个指向操作的队列的引用。在程序中,根据队列head是否等于tail,判断队列是否为空。

判断满队列

判断满队列即判断一个队列结构是否为满。如果是满队列,则表示该队列结构中没有多余的空间来保存额外数据。此时不可以进行入队列操作,但是可以进行出队列操作。

int SQTypeIsFull(SQType q){     // 判断队列满
    int temp = 0;
    if(q.tail==QUEUELEN){
        temp=1;
    }
    return temp;
}

清空队列

void SQTypeClear(SQType q){     // 清空队列
    q.head = 0;
    q.tail = 0;
}

释放空间

void SQTypeFree(SQType q){      // 释放队列
    if(q != null){
        q = null;
    }
}

入队列

入队列是队列结构的基本操作,主要操作是将数据元素保存到队列结构。入队列的具体步骤如下:
1. 首先判断队列顶tail,如果tail等于QUEUELEN,则表示溢出,进行出错处理;否则执行以下操作。
2. 设置tail=tail+1(队列顶引用加1,指向入队列地址)
3. 将入队列元素保存到tail指向的位置。

int InSQType(SQType q, DATA data){      // 入队列
    if(q.tail==QUEUELEN){
        System.out.println("队列已满! 操作失败!\n");
        return 0;
    }
    q.data[q.tail++] = data;        // 顺序入队列,并将队尾指针+1
    return 1;
}

在上述代码中,输入参数q是一个指向操作的队列引用,输入参数data是需要入队列的数据元素。程序中首先判断队列是否溢出,如果溢出则不进行入队列操作,否则修改队列顶引用的值,再将元素入队列。

出队列

出队列是队列结构的基本操作,主要操作与入队列相反,其操作是从队列顶弹出一个数据元素。出队列操作的具体步骤如下:
1. 判断队列head,如果head等于tail,则表示为空队列,进行出错处理;否则,执行下面的步骤。
2. 从队列首部取出队头元素(实际是返回队头元素的引用)。
3. 设修改队头head的序号,使其指向后一个元素。

DATA OutSQType(SQType q){       // 出队列
    if(q.head==q.tail){
        System.out.println("队列已空! 操作失败!\n");
        return null;
    }else{
        return q.data[q.head++];    // 顺序出队列,并将队首指针+1
    }
}

在上述代码中,输入参数q是一个指向操作的队列的引用。该方法返回值是一个DATA类型的数据,返回值是指向该数据元素的引用。

读结点数据

读操作其实是读取队列头的数据。需要注意的是,读结点数据的操作和出队列操作不同。读结点数据的操作仅显示队列顶结点数据的内容,而出队列操作则将队列顶数据弹出,该数据不再存在。

DATA PeekSQType(SQType q){      //读结点数据
    if(SQTypeIsEmpty(q)==1){
        System.out.println("\n空队列");
        return null;
    }else{
        return q.data[q.head];
    }
}

上述代码中,输入参数q是一个指向操作的队列的引用。该方法的返回值同样是一个DATA类型的引用数据,返回值是指向数据元素的引用。

计算队列长度

计算队列长度即统计该队列中数据结点的个数。计算队列长度的方法比较简单,用队尾序号减去队头序号即可。

int SQTypeLen(SQType q){        // 计算队列长度
    int temp;
    temp=q.tail - q.head;
    return temp;
}

在上述代码中,输入参数q是一个指向操作的队列的引用。该方法的返回值便是队列的长度。

队列结构操作实例

package dataStructure.queue;

import java.util.Scanner;

class DATA{
    String name;
    int age;
}

/*
 * 顺序结构队列
 * sequential queue
 */
class SQType{
    static final int QUEUELEN = 15;
    DATA[] data = new DATA[QUEUELEN];   // 队列顺序结构数组
    int head;       // 队头
    int tail;       // 队尾

    SQType SQTypeInit(){        // 队列初始化
        SQType q;
        if((q=new SQType())!=null){     // 申请内存
            q.head = 0;                                         
            q.tail = 0;
            return q;
        }else{
            return null;
        }
    }

    int SQTypeIsEmpty(SQType q){    // 判断队列空
        int temp = 0;
        if(q.head == q.tail)
            temp = 1;
        return temp;
    }

    int SQTypeIsFull(SQType q){     // 判断队列满
        int temp = 0;
        if(q.tail==QUEUELEN){
            temp=1;
        }
        return temp;
    }

    void SQTypeClear(SQType q){     // 清空队列
        q.head = 0;
        q.tail = 0;
    }

    void SQTypeFree(SQType q){      // 释放队列
        if(q != null){
            q = null;
        }
    }

    int InSQType(SQType q, DATA data){      // 入队列
        if(q.tail==QUEUELEN){   
            System.out.println("队列已满! 操作失败!\n");
            return 0;
        }
        q.data[q.tail++] = data;        // 顺序入队列,并将队尾指针+1
        return 1;
    }

    DATA OutSQType(SQType q){       // 出队列
        if(q.head==q.tail){
            System.out.println("队列已空! 操作失败!\n");
            return null;
        }else{
            return q.data[q.head++];    // 顺序出队列,并将队首指针+1
        }
    }

    DATA PeekSQType(SQType q){          //读结点数据
        if(SQTypeIsEmpty(q)==1){
            System.out.println("\n空队列");
            return null;
        }else{
            return q.data[q.head];
        }
    }

    int SQTypeLen(SQType q){        // 计算队列长度
        int temp;
        temp=q.tail - q.head;
        return temp;
    }
}

/**
 * 测试用例
 * @author elon@elon33.com
 *
 */
public class Queue {

    public static void main(String[] args) {
        SQType st = new SQType();
        DATA data1;
        Scanner input = new Scanner(System.in);
        SQType stack = st.SQTypeInit();
        System.out.println("入队列操作:");
        System.out.println("输入姓名 年龄进行入队列操作,输入0 结束入队操作:");
        do{
            DATA data = new DATA();
            data.name=input.next();
            data.age=input.nextInt();
            if(data.name.equals("0")){
                break;
            }else{
                st.InSQType(stack, data);
            }
        }while(true);

        String temp = "1";
        System.out.println("出队列操作:按任意非0键进行出队列操作:");
        temp = input.next();
        while(!temp.equals("0")){
            data1 = st.OutSQType(stack);
            if(data1 == null){
                break;
            }
            System.out.println("出队列的数据是"+data1.name+","+data1.age);
            temp = input.next();
        }
        System.out.println("测试结束!");
        st.SQTypeFree(stack);                                                   // 释放队列占用的空间
    }
}