堆(Heap)的基本操作

堆分为最大堆和最小堆,本文以最大堆为例。其实主要就是adjustDown()和adjustUp()这两个操作。一个删除时调整堆,一个插入时调整堆。

#include <bits/stdc++.h>
#define MAX_SIZE 1010
#define INF 99999999 
using namespace std;
/*
    堆:
        1)堆中某个节点的值总是不大于(不小于)其父节点的值
        2)堆总是一棵完全二叉树

    索引为 0的的地方存放的是哨兵:INF
    设孩子结点为 i,父亲结点为 i/2 
    设父亲结点为 j,孩子结点为 i * 2 和 i * 2 + 1
*/
/*
    操作:
        0)建堆
        1)插入
        2)删除
        3)获取最大值 
*/
class MaxHeap
{
    public:
        int heap[MAX_SIZE];
        int size = 0;
        MaxHeap(){ heap[0] = INF; }
};

/*
    向下调整:
        调整时保证此次调整的根结点的左右孩子都是最大堆
        循环:求出孩子中的较大者,和父亲结点比较
            父亲结点大,退出; 
            孩子结点大,孩子结点覆盖父亲结点(向上覆盖)。然后父亲下降到此孩子结点
        退出后用最初的父亲结点覆盖现在的父亲结点 
*/
void adjustDown(MaxHeap *mh, int index)
{
    int p, c, data = mh->heap[index];
    for(p = index; p * 2 <= mh->size; p = c)
    {
        c = p * 2;
        if(c != mh->size && mh->heap[c] < mh->heap[c + 1])
            c++;
        if(data >= mh->heap[c])
            break;
        else
            mh->heap[p] = mh->heap[c]; 
    }
    mh->heap[p] = data;
}
/*
    向上调整:
        此结点为平衡二叉树的最后结点,除去此结点剩下的堆为最大堆
        循环:此结点的值和其父结点比较
            大于父节点,父结点覆盖此结点(向下覆盖) 
            不大于父节点,退出
        推出后用被调整的结点替换当前结点 
*/
void adjustUp(MaxHeap *mh)
{
    int c, data = mh->heap[mh->size];
    for(c = mh->size; mh->heap[c/2] < data; c = c/2)
        mh->heap[c] = mh->heap[c/2];
    mh->heap[c] = data;
}
MaxHeap* create()
{
    MaxHeap *mh = new MaxHeap();
    int n, i;
    cin >> n;
    mh->size = n;
    for(i = 1; i <= n; i++)
        cin >> mh->heap[i];
    for(i = n / 2; i > 0; i--)
        adjustDown(mh, i);
    return mh;
}

/*
    插入:
        size增加、数据插入,向上调整 
*/
void insert(MaxHeap *mh, int x)
{
    mh->heap[++mh->size] = x;
    adjustUp(mh);
}

/*
    返回第一个之后,用最后一个覆盖第一个,size--
    向下调整第一个,adjustDown(mh, 1); 
*/
int getTop(MaxHeap *mh)
{
    int max = mh->heap[1];
    mh->heap[1] = mh->heap[mh->size--];
    adjustDown(mh, 1);
    return max;
}
int main()
{
    MaxHeap *mh = create();
    for(int i = 1; i <= mh->size; i++)
         cout << mh->heap[i] << " ";
    cout << endl;
    cout << getTop(mh) << endl;
    for(int i = 1; i <= mh->size; i++)
         cout << mh->heap[i] << " ";
    cout << endl;
    insert(mh, 10);
    for(int i = 1; i <= mh->size; i++)
         cout << mh->heap[i] << " ";
    return 0;
} 
### 排序算法的基本操作步骤 排序是一种基于比较的排序算法,它利用了二叉的数据结构。排序的核心思想是将待排序的数组构造成一个最大(或最小),然后通过交换顶元素与最后一个元素的位置,并调整剩余部分为新的,从而实现排序。 #### 1. 构建最大 构建最大的过程是排序的第一步。通过自底向上的方式,从最后一个非叶子节点开始,依次进行“下滤”操作,确保每个子树都满足最大的性质[^2]。 #### 2. 下滤操作 下滤操作是指将顶元素与它的子节点进行比较,并与较大的子节点交换位置,直到该元素位于正确的位置,使得整个重新满足最大的性质[^2]。 #### 3. 排序过程 在构建最大后,顶元素即为当前中的最大值。将其与末尾元素交换位置,然后减少的大小,对剩余部分重新执行下滤操作,重复这一过程,直到中只剩下一个元素[^1]。 --- ### Java 实现排序 以下是排序的完整 Java 实现代码: ```java public class HeapSort { public static void heapSort(int[] arr) { int n = arr.length; // 构建初始的最大 for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } // 提取元素并重建 for (int i = n - 1; i > 0; i--) { // 将当前顶元素与最后一个元素交换 swap(arr, 0, i); // 对剩余进行调整 heapify(arr, i, 0); } } // 调整的函数 private static void heapify(int[] arr, int heapSize, int rootIndex) { int largest = rootIndex; int leftChild = 2 * rootIndex + 1; int rightChild = 2 * rootIndex + 2; // 如果左子节点大于根节点 if (leftChild < heapSize && arr[leftChild] > arr[largest]) { largest = leftChild; } // 如果右子节点大于当前最大值 if (rightChild < heapSize && arr[rightChild] > arr[largest]) { largest = rightChild; } // 如果最大值不是根节点,则交换并递归调整 if (largest != rootIndex) { swap(arr, rootIndex, largest); heapify(arr, heapSize, largest); } } // 交换数组中的两个元素 private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static void main(String[] args) { int[] arr = {12, 11, 13, 5, 6, 7}; heapSort(arr); System.out.println("排序后的数组:"); for (int value : arr) { System.out.print(value + " "); } } } ``` --- ### C++ 实现排序 以下是排序的完整 C++ 实现代码: ```cpp #include <iostream> using namespace std; void heapify(int arr[], int n, int i) { int largest = i; int left = 2 * i + 1; int right = 2 * i + 2; if (left < n && arr[left] > arr[largest]) { largest = left; } if (right < n && arr[right] > arr[largest]) { largest = right; } if (largest != i) { swap(arr[i], arr[largest]); heapify(arr, n, largest); } } void heapSort(int arr[], int n) { for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } for (int i = n - 1; i > 0; i--) { swap(arr[0], arr[i]); heapify(arr, i, 0); } } void printArray(int arr[], int n) { for (int i = 0; i < n; ++i) { cout
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值