*文中内容大多来源于《数据结构 --Java语言描述》(第二版) 刘小晶 杜选 主编
*此系列文章作为学习记录,若文中内容有误,请大家指出,谢谢

优先级队列

优先级队列是一种带有优先级的队列,它是一种比栈和队列更为专有的数据结构,与普通队列一样,优先级队列中数据元素按关键字的值有序排列。由于很多情况下,需要访问具有最小关键字值的数据元素(例如要寻找最便宜的方法或最短的路径去做某件事),因袭,约定关键字最小的数据元素(或者在某些实现中是关键字最大的数据元素)具有最高的优先级,并且总是排在队首。

接口描述:
public interface IQueue {
    public void clear();
    public boolean isEmpty();
    public int length();
    public Object peek();       //取队首元素并返回其值
    public void offer(Object x) throws Exception;       //入队操作
    public Object poll();       //出队操作
}
优先队列中结点data的类描述:
public class PriorityQData {
    public Object elem;         //结点的数据元素值
    public int priority;        //结点的优先数

    public PriorityQData(Object elem, int priority){
        this.elem = elem;
        this.priority = priority;
    }
}
实现IQueue接口的类描述:
import Book_U2.Node;
public class PriorityQueue implements IQueue {
    private Node front;             //队首的引用
    private Node rear;              //队尾的作用

    //优先队列类的构造函数
    public PriorityQueue(){
        front = rear = null;
    }

    //队列置空
    public void clear(){
        front = rear = null;
    }

    //队列判空
    public boolean isEmpty(){
        return front == null;
    }

    //求队列长度
    public int length(){
        Node p = front;
        int length = 0;             //队列的长度
        while(p != null){           //一直查找找到队尾
            p = p.next;
            ++length;               //长度增加1
        }
        return length;
    }

    //入队
    public void offer(Object x){
        PriorityQData pn = (PriorityQData)x;
        Node s = new Node(pn);      //构造一个新结点
        if (front == null)          //队列为空
            front = rear = s;       //修改队列的首尾结点
        else{
            Node p = front , q = front;
            while(p != null && pn.priority >= ((PriorityQData)p.data).priority){    //新结点的数据域值与队列结点的数据域值相比较
                q = p;
                p = p.next;
            }
            if (p == null){             //p为空,表示遍历到了队列尾部
                rear.next = s;          //将新结点加入到队尾
                rear = s;               //修改队尾指针
            }
            else if (p == front){       //p的优先级大于队首结点的优先级
                s.next = front;         //将新结点加入到队首
                front = s;              //修改队首指针
            }
            else {                      //新结点加入队列中部
                q.next = s;
                s.next = p;
            }
        }
    }

    //读取队首元素
    public Object peek(){
        if (front == null)              //队列为空
            return null;
        else                            //返回队首结点的数据域值
            return front.data;
    }

    //出队
    public Object poll(){
        if (front == null)              //队列为空
            return null;
        else{                           //返回队首结点的数据域值,并修改队首指针
            Node p = front;
            front = p.next;
            return p.data;
        }
    }

    //输出所有队列中的所有数据元素(从队首到队尾)
    public void display(){
        if (!isEmpty()){
            Node p = front;
            while(p != rear.next){      //从队首到队尾
                PriorityQData q = (PriorityQData)p.data;
                System.out.println(q.elem + " " + q.priority);
                p = p.next;
            }
        }
        else
            System.out.println("此队列为空");
    }
}
Node的描述:
/**
 * data是数据域,用来存放数据元素的值;next是指针域,用来存放后继结点的地址
 */
public class Node {
    public Object data;    //存放结点值
    public Node next;    //后继结点的引用

    //无参数时的构造函数
    public Node(){
        this(null,null);
    }

    //带一个参数时的构造函数
    public Node(Object data){
        this(data,null);
    }

    //带两个参数时的构造函数
    public Node(Object data,Node next){
        this.data = data;
        this.next = next;
    }
}

并附上一个简易实例

  • 设计一个程序模仿操作系统的进程管理问题。要求按进程服务优先级高的先服务、优先级相同的按先到先服务的原则进行管理。
  • 操作系统中每个进程的模仿数据由进程号和进程优先级两部分组成,进程号是每个不同进程的唯一标识,优先级通常是一个0到40的数值,规定0为优先级最高,40为优先级最低。下面为一组模拟数据:
    | 进程号 | 进程优先级 |
    |1 | 20|
    |2 | 40|
    |3 | 0|
    |4 | 10|
    |5 | 40|
程序代码
package Book_U3;

public class Example3_6 {
    public static void main(String[] args){
        PriorityQueue pm = new PriorityQueue();             //构造一个对象
        pm.offer(new PriorityQData(1, 20));  //插入优先级队列
        pm.offer(new PriorityQData(2, 30));
        pm.offer(new PriorityQData(3, 20));
        pm.offer(new PriorityQData(4, 20));
        pm.offer(new PriorityQData(5, 40));
        pm.offer(new PriorityQData(6, 10));
        System.out.println("进程服务的顺序:");
        System.out.println("进程ID进程优先级");
        while(!pm.isEmpty()){           //从队首到队尾,输出结点的数据域值和优先级
            PriorityQData p = (PriorityQData)pm.poll();     //移除队首结点,并返回其数据域值
            System.out.println(" " + p.elem + "\t" + p.priority); //输出
        }
    }
}