• 完全二叉堆和堆排序


    一,优先级队列

        数据集合中,各元素的访问顺序取决于元素自身的优先级(call-by-priority)。

    二,拥有的操作接口

    1.插入操作,inisert();

    2.获取优先级最高的元素,getMax();

    3.删除优先级最高的元素,deleteMax();

     三,构造优先级队列

        但是为什么使用堆来表示优先级队列呢,在实现优先级对列时,我们既要考虑效率,也要兼顾成本。所以最好的实现方式应该是这两个要求的综合体。

     1.使用普通线性数组(无序)来表示优先级队列。

    • 执行插入操作时,直接将元素插入到数组末端,需要的成本为O(1),
    • 获取优先级最高元素,我们需要遍历整个线性队列,匹配出优先级最高元素,需要的成本为Θ(n)
    • 删除优先级最高元素,我们需要两个步骤,第一找出优先级最高元素,第二步删除优先级最高元素,然后将后面的元素依次迁移,填补空缺,需要的成本为Θ(n)+Θ(n)=Θ(n)

    2.使用一个按顺序排列的有序向量实现优先级队列

    • 获取优先级最高元素,O(1)
    • 删除优先级最高元素,O(1)
    • 插入一个元素,需要两个步骤,第一步我们需要找出要插的位置,这里我们可以使用二分查找,成本为O(logn),第二步是插入元素之后,将

            其所有后继进行后移操作,成本为O(n),所有总成本为O(logn)+O(n)=O(n)

    3.使用BBST(AVL,伸展书,红黑树)实现优先级对列,从BBST的特性我们可以得出不管是插入,获取最高优先级元素,或者删除最高优先级元素其需要的成本都为O(log n)。这是个不错的效果。但是我们发现我们使用BBST来表示优先级队列时,在查找和删除操作时却只是用作最高优先级元素,这样就显得有些大材小用。

    综上,我们发现,对于表示优先级对列,我们就需要去维护优先级最高的元素,而无需维护整个元素。

    上面,我们使用基本的向量(数组)来表示时,效率不是很高,但是采用BBST时虽然效率很高,但是却有杀鸡用牛刀。所以我们考虑使用向量+树的结合体来表示优先级队列--完全二叉堆。

    三,完全二叉树

    在完全二叉树中,除了最后一层可能不满之外其他层都是满的,最后一层如果缺少的话。只缺少右边若干节点。

     

     

    四,向量与二叉树结合

    逻辑上:为二叉树

    物理上:使用向量实现

                      图中的数值为它们的秩

    我们看出,向量里的元素为完全二叉树按广度优先遍历的结果.

    性质

    1.对于节点i,如果其左孩子存在,则其左孩子为i*2+1

    2.如果其右孩子存在,则其右孩子为(i+1)*2

    3.如果其父节点存在,则其父节点为(i-1)/2

    4.堆序性:堆有大顶堆和小顶堆,这里我们只考虑大顶堆,则对于大顶堆:

    在数值上,如果i>0,则必有,H[i]≤H[Parent(i)],既任何一个节点在任何情况下的值都不会超过它的父亲

    三,考虑大的元素(最高优先级)

    根据上面的堆序性不难看出,最大的元素必然在堆顶,而堆顶的元素的秩为0,既getMax()操作只需返回内部数组中的首元素

    这种优先级队列的表现方式在逻辑上借助了完全二叉树,人们有时也称它为完全二叉堆。 

    三,二叉堆的实现

    在实现优先级队列的插入,删除和获取最高优先级元素时,我们需要借助几个方法

    1.下虑

    void percolateDown(int heap[],int start,int end)
    {
    
        int temp = heap[start];
     
        for (int j = 2 * start + 1 ; j < end ; j = 2 * j + 1) {
            
            while (j<end-1 && heap[j] <heap[j+1]) {
                j++;
            }
            
            if(temp >=heap[j])
                break;
            
            heap[start] = heap[j];
            start = j;
            
        }
        heap[start] = temp;
        
      
    }

    2.上虑

    void percolateUp(int heap[],int start)
    {
        int temp=0;
        int j = 0;
       
        
        while (start>0) {
        
             temp = heap[start];
             j = (start - 1)/2;
            
            if (heap[start]>heap[j]) {
                heap[start]=heap[j];
                heap[j]=temp;
                start=j;
        
            }else{
                break;
            }
            
        }
    
    }

    3.Floyed建堆算法

    int createHeap(int heap[],int length)
    {
        if (heap == NULL || length == 0) {
            return 0;
        }
      
        for (int i = length / 2 -1; i>=0; i--) {
            percolateDown(heap, i, length);
        }
        
        return 1;
    
    }
    int delete(int heap[],int *length)
    {
        if (heap == NULL) {
            return 0;
        }
        
        heap[0] = heap[*length-1];
        (*length)--;
        percolateDown(heap, 0, *length);
        return 1;
        
    }

    4.在堆顶插入元素

    int insert(int heap[],int value,int * length)
    {
        if (heap == NULL) {
            return 0;
        }
        
        heap[*length] = value;
       
        percolateUp(heap, *length);
        (*length)++;
        return 1;
    
    
    }
  • 相关阅读:
    PHPCMS快速建站系列之添加单页模版
    func_num_args(),func_get_arg(),func_get_args()
    34 个使用 Raspberry Pi 的酷创意
    解决sublime text 2总是在新窗口中打开文件
    帝国cms后台不停的登录成功
    PHP正则表达式的逆向引用与子模式 php preg_replace应用
    【采集】php str_replace
    如何设置让SFTP的用户限制在某个目录下
    win2008修改最大远程桌面连接数
    mysql查询差集
  • 原文地址:https://www.cnblogs.com/ufreedom/p/4046950.html
Copyright © 2020-2023  润新知