【算法笔记】- 堆


(一)存储

堆是一棵完全二叉树 :使用数组存储结点
结点按层序存储在数组中,
第一个结点存储在1号位,i号位结点的左右孩子分别存储在2i2i+1号位


(二)基本操作实现 (以大顶堆为例)
1、建堆 (数据提前保存在数组中,只需调整为大顶堆即可)
  • 思路:由于完全二叉树的叶节点个数为 【n / 2】(取上限),所以数组下标下1 ~ 【n / 2】(取下限)中都是非叶节点;因此从n/2号开始向上枚举节点,对每一个节点向下调整;
  • 时间复杂度:O(n) <算法导论有证>
int heap[maxn], n = 100; //堆,元素个数

//对heap[low, high]范围内进行向下调整 时间复杂度O(logn)-树高
//low和high分别为欲调整结点和最后结点的下标
void downAdjust(int low, int high) {
    //向下调整
    int i = low, j = i * 2;
    while(j <= high) {
        if(j + 1 <= high && heap[j] < heap[j + 1]) { //选择较大的子结点
            j = j + 1;
        }
        //父节点 < 子结点
        if(heap[i] < heap[j]) {
            swap(heap[i], heap[j]); //换位
            i = j;     //继续向下调整
            j = i * 2;
        }
        else {
            break;
        }

    }//while
}//downAdjust

//建堆(数据已经保存在数组中,调整就行)- O(n) <算法导论有证>
void create_heap() { //
    for(int i = n / 2; i >= 1; i--)  //从第一个非叶节点开始
        downAdjust(i, n);
}
2、删除堆顶元素
void delete_top() {
    heap[1] = heap[n--]; //尾结点覆盖即可
    downAdjust(1, n); //调整
}
3、插入元素
  • 思路:将要插入的结点放在数组最后,然后向上调整即可
//向上调整(根节点下标为low,欲调整结点下标为high)
void upAdjust(int low, int high) {
    //low设置为1,high表示欲调整结点的数组下标
    int i = high, j = i / 2; //i为欲调整结点,j为其父结点
    while(j >= low) {
        if(heap[i] > heap[j]){
            swap(heap[i], heap[j]);
            i = j; //不断向上回溯即可
            j = i / 2;
        } else {
            break;
        }
    }
}
void intsert(int x) {
    heap[n++] = x; //先加在数组最后
    upAdjust(1, n); //向上调整
}
4、堆排序
  • 思路: 不断摘取堆顶元素放在数组末尾即可,最后数组按递增排序
void heapSort() {
    create_heap(); //建堆
    for(int i = n; i > 1; i--) { //直到堆中只剩一个元素
        swap(heap[i], heap[1]);
        downAdjust(1, i - 1);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_26398495/article/details/81707813