`
bearsorry
  • 浏览: 93575 次
  • 性别: Icon_minigender_2
  • 来自: 湖南
社区版块
存档分类
最新评论

数据结构之优先队列

阅读更多

    这几天查阅了一些关于优先队列的资料,记得我们用优先队列的时候也是在做那个哈弗曼编码的时候,计算每个字符出现的频率之后,再将出现次数越多的就放在靠近树根越近的位置,就在这里用到了优先队列,刚开始真的不懂优先队列是干嘛的,不晓得为什么要存在这么一个东西,搞得自己好茫然的,后来看了源代码什么的之后,才发现它是这么简单!
    在这之前我们都了解了一些有关于队列的知识,优先级队列是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。优先队列也是要涉及到查找和排序的一类数据结构:
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 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。

 

2
2
分享到:
评论

相关推荐

    数据结构优先队列

    数据结构优先队列,是一个简易版优先队列,输入数据及权值可以对其进行插入,删除等操作。

    JavaScript数据结构之优先队列与循环队列实例详解

    本文实例讲述了JavaScript数据结构之优先队列与循环队列。分享给大家供大家参考,具体如下: 优先队列 实现一个优先队列:设置优先级,然后在正确的位置添加元素。 我们这里实现的是最小优先队列,优先级的值小...

    数据结构(优先队列)

    对数据结构中优先队列的设计,这个仅是参考。

    数据结构 栈和队列PPT

    7. 特殊类型的队列:优先队列(Priority Queue),用于处理具有优先级的元素,如最小堆实现。 8. 双端队列(Deque,Double-ended Queue):支持在两端进行插入和删除操作,常用于实现滑动窗口最大值等算法。 在学习...

    C语言数据结构优先队列实现

    在C语言中实现优先队列,通常会选择使用堆数据结构,因为它可以保证插入、删除和查找操作的时间复杂度为O(logn),其中n是队列中的元素数量。堆是一种近似完全二叉树的结构,可以分为大顶堆和小顶堆。小顶堆的性质是...

    数据结构课程设计优先队列数据(priority_queue)类型

    在数据结构课程设计中,优先队列数据类型(priority_queue)是核心概念之一,常用于实现高效的调度、搜索和优化问题。在本项目中,我们将讨论如何实现这种数据结构以及其主要操作。 **一、优先队列的定义** 优先...

    数据结构栈和队列解决迷宫问题

    数据结构栈和队列解决迷宫问题 本文档详细介绍了利用栈和队列解决迷宫问题的步骤,对于初学者学习数据结构能很好的进行辅导。本文档主要涉及到数据结构的两个重要概念:栈和队列,并介绍了如何使用这两个数据结构来...

    数据结构基于链表实现的优先队列

    数据结构 基于链表实现的优先队列 Cpp文件

    用堆实现优先队列

    优先队列是一种特殊的数据结构,它允许我们按照优先级顺序处理元素。在计算机科学中,尤其是在算法和数据结构领域,优先队列常用于解决需要快速访问最高优先级元素的问题,如Dijkstra算法或Prim算法。在C语言中,...

    priority_queue_1.0_excitingfbh_matlab优先队列_matlab优先队列_优先队列_

    优先队列是一种特殊的数据结构,它允许用户以特定的优先级进行元素的插入和删除操作。在MATLAB中实现优先队列,可以帮助我们处理需要快速访问最高优先级元素的问题,例如在任务调度、图形渲染或者搜索算法中。...

    数据结构队列C++

    在众多的数据结构中,队列是一种基础且重要的结构,尤其在处理任务调度、消息传递等场景中有着广泛的应用。本项目是关于数据结构中队列的实现,使用C++编程语言进行开发。 队列是一种线性数据结构,遵循“先进先出...

    优先队列-java可以选择属性和升序降序

    优先队列在Java编程中是一种特殊的数据结构,它遵循特定的出队顺序,通常是最小元素(最小优先队列)或最大元素(最大优先队列)先出队。这种数据结构在解决各种问题时非常有用,例如任务调度、事件驱动编程、搜索...

    优先队列课程设计代码

    优先队列是一种特殊的数据结构,它支持两种主要的操作:插入元素和删除最小(或最大)元素。在实际应用中,优先队列常用于任务调度、事件驱动模拟以及各种排序算法等场景。 ### 二、优先队列的实现 #### 1. 数据...

    C语言-数据结构-栈队列实现

    本主题关注的是如何使用C语言来实现数据结构中的栈和队列,这是两种基础但非常重要的抽象数据类型(ADT)。 栈(Stack)是具有后进先出(LIFO)特性的数据结构。它类似于一个堆叠的盘子,最新的元素被放在顶部,...

    用数组实现的优先队列(JAVA)

    总之,`PriorityQ.java`文件可能是一个简单的数组实现优先队列的示例,通过分析这个文件,我们可以学习到如何利用数组数据结构实现优先队列,以及理解其核心的插入、删除和查找操作。同时,这也能帮助我们更好地掌握...

    C语言优先队列

    优先队列的数据结构由两个部分组成:元素数组和队列信息。元素数组用于存储优先队列中的元素,每个元素由数据和优先权值组成。队列信息包括队列的长度、队列的已分配存储空间大小和队列的当前元素个数。 知识点三:...

    简单的优先队列

    综上所述,这个“简单的优先队列”主题涵盖了许多基础数据结构和算法,包括平衡树、背包策略、图的表示以及队列接口。通过理解和应用这些知识,我们可以设计和实现高效的优先级队列系统,用于解决各种实际问题。

    优先队列算法实现(Java)

    优先队列是一种特殊的数据结构,它允许我们按照优先级顺序处理元素。在计算机科学中,尤其是在算法设计中,优先队列常被用于解决各种问题,如任务调度、事件驱动模拟和图形学等。本实现是用Java编程语言完成的,Java...

Global site tag (gtag.js) - Google Analytics