冰糖葫芦 阅读(78) 评论(0)

写在之前

1.自定义实现采用数组作为内部数据结构

2.内部数组通过grow方法进行扩容,每次只是简单的扩展为原来的2倍

3.集中实现方式的主要区别在于siftDown方法

4.以下给出关键代码,更多详细信息请看附件源码

 

实现方式一(递归实现)

关键代码:

   @Override
    protected void siftDown(int index)
    {
        int len = totalCount - 1;
        int left = left(index);
        int right = right(index);
        if(left > len)
        {
            return;
        }
        int currentMin = left;
        if(right <= len && arr[currentMin] > arr[right])
        {
            currentMin = right;
        }
        if(arr[currentMin] < arr[index])
        {
            swap(arr, currentMin, index);
            siftDown(currentMin);
        }
    }

  

实现方式二(循环实现)

关键代码:

   @Override
    protected void siftDown(int index)
    {
        int len = totalCount - 1;
        while(left(index) <= len)
        {
            int left = left(index);
            int right = right(index);
            if(left > len)
            {
                break;
            }
            int currentMin = left;
            if(right <= len && arr[currentMin] > arr[right])
            {
                currentMin = right;
            }
            if(arr[currentMin] >= arr[index])
            {
                break;
            }
            swap(arr, currentMin, index);
            index = currentMin;
        }
    }

 

实现方式三(直接构建堆)

关键代码:

   @Override
    protected void siftDown(int index)
    {
        int len = totalCount - 1;
        while(left(index) <= len)
        {
            int left = left(index);
            int right = right(index);
            if(left > len)
            {
                break;
            }
            int currentMin = left;
            if(right <= len && arr[currentMin] > arr[right])
            {
                currentMin = right;
            }
            if(arr[currentMin] < arr[index])
            {
                swap(arr, currentMin, index);
            }
            //进入下一个非叶子节点
            index++;
            
        }
    }

 

实现方式四(JDK中的实现)

1.siftUp方法:

protected void siftUp(int k, int x) 
    {
        while (k > 0) 
        {
            int parent = parent(k);
            int e = arr[parent];
            if (x >= e)
                break;
            arr[k] = e;
            k = parent;
        }
        arr[k] = x;
    }

 2.siftDown方法:

   /**
     * 指定index位置的值为x,并为x在堆中找到合适位置
     * @param index
     * @param x
     */
    private void siftDown(int index, int x) 
    {
        int half = totalCount >>> 1;        
        while (index < half) 
        {
            int currentMin = left(index);
            int right = right(index);
            if (right < totalCount && arr[currentMin] > arr[right])
                currentMin = right;
            if (x <= arr[currentMin])
                break;
            //将index位置设置为最小节点值
            arr[index] = arr[currentMin];
            //迭代
            index = currentMin;
        }
        //将最终值放入合适位置
        arr[index] = x;
    }

 

其他的一下关键方法

1.siftUp方法:

   @Override
    protected void siftUp(int index)
    {
        int parent = parent(index);
        while(index > 0 && arr[index] < arr[parent])
        {
            swap(arr, index, parent);
            index = parent;
            parent = parent(index);
        }
    }

 2.add方法:

   @Override
    public boolean add(int ele)
    {
        if(totalCount == arr.length)
        {
            //扩容
            grow();
        }
        
        int i = totalCount;
        arr[i] = ele;
        if(totalCount == 1)
        {
            return true;
        }
        
        //调整元素位置确保为小根堆
        siftUp(i);
        totalCount++;
        return true;
    }

 3.poll方法:

   @Override
    public int poll()
    {
        int result = arr[0];
        arr[0] = arr[--totalCount];
        siftDown(0);
        
        return result;
    }

 5.remove方法:

   @Override
    public int remove(int ele)
    {
        //内部数据为空
        if(totalCount < 1)
        {
            return -1;
        }
        
        //计算元素位置
        int index = indexOf(ele);
        if(index < 0)
        {
            return -1;
        }
        
        return removeAt(index);
    }

 6.removeAt方法:

   @Override
    protected int removeAt(int idx)
    {
        if(idx < 0 || idx >= totalCount)
        {
            return -1;
        }
        int result = arr[idx];
        
        //将删除元素与最后一个元素交换位置
        if(idx != totalCount -1)
        {
            arr[idx] = arr[totalCount - 1];
        }
        //位置交换之后队列长度减一
        totalCount--;
        //如果队列长度大于1,而且删除的元素位置不在队尾则重新调整堆
        if(totalCount > 1 && idx != totalCount)
        {
            siftDown(idx);
        }
        return result;
    }