概述
这几天查阅了一些关于优先队列的资料,记得我们用优先队列的时候也是在做那个哈弗曼编码的时候,计算每个字符出现的频率之后,再将出现次数越多的就放在靠近树根越近的位置,就在这里用到了优先队列,刚开始真的不懂优先队列是干嘛的,不晓得为什么要存在这么一个东西,搞得自己好茫然的,后来看了源代码什么的之后,才发现它是这么简单!
在这之前我们都了解了一些有关于队列的知识,优先级队列是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。优先队列也是要涉及到查找和排序的一类数据结构:
A、查找的方法有以下几种:
1、静态查找
2、动态查找
B、排序的方法有以下几种:
1、直接插入排序法
2、折半插入排序法
3、起泡排序法
4、快速排序法
5、简单选择排序法
6、基数排序法
7、堆排序法
8、归并排序法
这里再温习一下数据结构的知识吧!
数据结构的四种基本结构为:
集合 2、线性结构 3、树形结构 4、网状结构
数据的逻辑结构(有时就叫做数据结构):
线性结构(线性表等)、非线性结构(树、图等)
数据的物理结构(存储结构):
顺序存储结构、链式存储结构、索引存储结构、散列存储结构
完全二叉树的性质:
如将一棵有n个结点的完全二叉树自顶向下,同一层自左向右连续给结点编号0, 1, 2, …, n-1,则有以下关系:
1、若i = 0, 则 i 无双亲.
2、若i > 0, 则 i 的双亲为:(i -1)/2.?
3、若2*i+1 < n, 则 i 的左子女为 2*i+1,若2*i+2 < n, 则 i 的右子女为2*i+2.
4、若结点编号i为偶数,且i!=0,则左兄弟结点i-1.
5、若结点编号i为奇数,且i!=n-1,则右兄弟结点为i+1.
6、结点i 所在层次为:log2(i+1)+1
这里优先队列是用的堆排序法,算法主要运用在于插入和删除:
代码:
/**
* 添加数据
* @param e:要添加的数据对象
* @return:是否添加成功
*/
public boolean add(E e) {
return offer(e);
}
public boolean offer(E e) {
//不能放入空数据
if (e == null)
throw new NullPointerException();
//队列中的数据的个数
currentCount++;
//在装数据之前队列中数据的个数
int i = size;
//当容量不足的时候
if (i >= queue.length)
grow(i + 1);
size = i + 1;
//当队列中还没有元素的时候
if (i == 0)
queue[0] = e;
else
siftUp(i, e);
return true;
}
/**
* 将数据X添加进队列:要进行对比
* @param k:队列的在加入这个数据之前的长度
* @param x:数据对象
*/
private void siftUp(int k, E x) {
//有比较对象的队列的处理方法
if (comparator != null)
siftUpUsingComparator(k, x);
else
//没有比较对象的队列的处理方法
siftUpComparable(k, x);
}
//运用堆排序将数据插入到队列中
private void siftUpComparable(int k, E x) {
//则数据就应该实现Comparable接口
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
break;
queue[k] = (E)e;
k = parent;
}
queue[k] = key;
}
//运用堆排序将数据插入到队列中
private void siftUpUsingComparator(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = (E)e;
k = parent;
}
queue[k] = x;
}
/**
* 移除数据O
* @param o
* @return
*/
public boolean remove(Object o) {
int i = indexOf(o);
if (i == -1)
return false;
else {
removeAt(i);
return true;
}
}
/**
* 移除指定位置的数据
* @param i
* @return
*/
private E removeAt(int i) {
//断言设定
assert i >= 0 && i < size;
currentCount++;
int s = --size;
//移除最后一个元素
if (s == i)
queue[i] = null;
else {
E moved = (E) queue[s];
queue[s] = null;
siftDown(i, moved);
if (queue[i] == moved) {
siftUp(i, moved);
if (queue[i] != moved)
return moved;
}
}
return null;
}
/**
* 移除第K个位置的数据,将数据X加入到队尾
* @param k:要移除的数据在队列中的位置
* @param x:队列中最后一个数据
*/
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
//同样用最小堆将这个数据删除掉
private void siftDownComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>)x;
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
if (key.compareTo((E) c) <= 0)
break;
queue[k] = (E)c;
k = child;
}
queue[k] = (E)key;
}
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = (E)c;
k = child;
}
queue[k] = x;
}
这里用另外一种排序方式:折半插入排序
代码
/**
* 添加数据
* @param e:要添加的数据对象
* @return:是否添加成功
*/
public boolean add(E e) {
return offer(e);
}
public boolean offer(E e) {
//不能放入空数据
if (e == null)
throw new NullPointerException();
currentCount++;
int i = size;
//当容量不足的时候
if (i >= queue.length){
queue = Arrays.copyOf(queue, queue.length+1);
}
size = i + 1;
//当队列中还没有元素的时候
if (i == 0)
queue[0] = e;
else
siftUp(i, e);
return true;
}
/**
* 将数据X添加进队列:要进行对比
* @param k:队列的在加入这个数据之前的长度
* @param x:数据对象
*/
private void siftUp(int k, E x) {
//有比较对象的队列的处理方法
if (comparator != null)
siftUpUsingComparator(k, x);
else
//没有比较对象的队列的处理方法
siftUpComparable(k, x);
}
//运用堆排序将数据插入到队列中
private void siftUpComparable(int k, E x) {
//则数据就应该实现Comparable接口
Comparable<? super E> key = (Comparable<? super E>) x;
//得到中间位置的数据
int parent = (k - 1) >>> 1;
//用两个变量来记录数组前后对比是所需要的位置标记
int low=0,high=k-1;
while ((high-low)>1) {
Object e = queue[parent];
if (key.compareTo((E) e) >= 0){
//再跟后面的比较
low = parent;
parent = (low+high)>>>1;
}else{
//跟前面的比较
high = parent;
parent = (low+high)>>>1;
}
}
//将该数据与low=high位置的数据比较
Object e = queue[low];
if(key.compareTo((E) e) >= 0){
//将数据放在low的后面
for(int i=k;i>low+1;i--){
queue[i-1]=queue[i-2];
}
}else{
//在low位置之前将e放进数组
for(int i=k;i>low-1;i--){
queue[i-1]=queue[i-2];
}
}
}
//运用堆排序将数据插入到队列中
private void siftUpUsingComparator(int k, E x) {
//得到中间位置的数据
int parent = (k - 1) >>> 1;
//用两个变量来记录数组前后对比是所需要的位置标记
int low=0,high=k-1;
while (parent > 0) {
Object e = queue[parent];
if((high-low)<=1){
break;
}
if (comparator.compare(x, (E)e)>=0){
//再跟后面的比较
low = parent;
high = k-1;
parent = parent+(k-parent)>>>1;
}else{
//跟前面的比较
low = 0;
high = parent;
parent = (k-parent)>>>1;
}
}
//将该数据与low=high位置的数据比较
Object e = queue[low];
if(comparator.compare(x, (E)e)>=0){
//将数据放在low的后面
for(int i=k;i>low;i--){
queue[i-1]=queue[i-2];
}
}else{
//在low位置之前将e放进数组
for(int i=k;i>low-1;i--){
queue[i-1]=queue[i-2];
}
}
}
/**
* 移除数据O
* @param o
* @return
*/
public boolean remove(Object o) {
int i = indexOf(o);
if (i == -1)
return false;
else {
removeAt(i);
return true;
}
}
/**
* 移除指定位置的数据
* @param i
* @return
*/
private E removeAt(int i) {
//断言设定
assert i >= 0 && i < size;
currentCount++;
int s = --size;
//移除最后一个元素
if (s == i)
queue[i] = null;
else {
for(int j=i;j<s-1;j++){
queue[j]=queue[j+1];
}
}
return null;
}
之后我用系统的优先队列、我用堆排序的优先队列、折半插入排序的优先队列分别进行测试,结果如下:
用堆排序的都是用的100万数据进行测试的!
系统的测试结果:
插入的时间为-->248
我的测试结果:
插入的时间为-->252
折半插入排序法测试结果为:
插入的时间为-->31912(还只是10万数据啊!!!!)
不晓得这是偶然还是怎么的,就觉得这个结果怪怪的,因为按理论上来说,折半排序不可能这么慢的啊。。。但我测出来就是有问题呃。。。
最后附上一点点小知识:
Comparable与Comparator的区别与联系
左移与右移运算:可以用于寻找节点的根节点和左右孩子节点
>>右移运算:相当于除以2^n
<<左移运算:相当于乘以2^n
Comparator是一个比较器,是一种工具,它里面有两个方法:int compare(T o1,T2 o2);boolean equals(Object object);
Comparable里面有一个方法:int compareTo(T o);
它们都是接口,Comparable里面的那个方法只能比较实现了这个方法本身的类,但只要具有可比性的类都可以用实现了Comparator这个接口里面的方法进行比较!
Comparable 是一个对象本身就已经支持自比较所需要实现的接口;而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
最后
以上就是愤怒樱桃为你收集整理的数据结构之优先队列的全部内容,希望文章能够帮你解决数据结构之优先队列所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复