手写堆orz

 注意:

 手写堆的本质是一颗完全二叉树;

因为要维护堆的单调性,所以插入新数时放在数的最后,然后将树遍历一遍把插入的数放到满足单调性的位置(小根堆:根结点最小;反之则为大根堆)

在删除根结点(或任一元素)时用末尾元素将其覆盖,然后元素数减一

 堆排序

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int s;
int a[N];
void down(int u){
    int k=u;
    if(u*2<=s&&a[u*2]<a[k])k=u*2;
    if(u*2+1<=s&&a[u*2+1]<a[k])k=u*2+1;
    if(k!=u){
        swap(a[k],a[u]);
        down(k);
    }
}
int main(){
      scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++)scanf("%d", &a[i]);
    s=n;
    for(int i=n/2;i;i--)down(i);
    while(m--){
         printf("%d ", a[1]);
        a[1]=a[s];
        s--;
        down(1);
    }
    return 0;
}

模拟堆

h[x] 表示树中位置 x 的元素
ph[k] = x 表示第 k 个插入的元素在树中存放的位置 x
此时如果要交换 ph 中的两个元素需要知道树中位置 x 是第几个被插入的, 于是便引入了数组 hp
hp[x] = k 表示树中位置 x 存放的为第 k 个插入的元素

 

 

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

int cnt;
int h[N],ph[N],hp[N];
void swa(int a,int b){
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a],hp[b]);
    swap(h[a],h[b]);
}
void down(int u){
    int k=u;
    if(u*2<=cnt&&h[u*2]<h[k])k=u*2;
    if(u*2+1<=cnt&&h[u*2+1]<h[k])k=u*2+1;
    if(k!=u){
        swa(k,u);
        down(k);
    }
}
void up(int u){
    while(u/2&&h[u/2]>h[u])swa(u,u/2),u>>=1;
}
int main(){
    int n,m=0;
    scanf("%d", &n);
    while(n--){
        char op[5];
        int k,x;
        scanf("%s", op);
        if(!strcmp(op,"I")){
            scanf("%d",&x);
            cnt++;//总数
            m++;//记录第几次插入
            ph[m]=cnt,hp[cnt]=m;
            //ph[k] = x 表示第 k 个插入的元素在树中存放的位置 x,
            //hp[x] = k 表示树中位置 x 存放的为第 k 个插入的元素
            h[cnt]=x;
            up(cnt);
        }
        else if(!strcmp(op,"PM")) printf("%d\n", h[1]);
        else if(!strcmp(op,"DM")){
            swa(1,cnt);
            cnt--;
            down(1);
        }
        else if(!strcmp(op,"D")){
            cin>>k;
            k=ph[k];//找到第k个插入的数
            swa(k,cnt);
            cnt--;
            up(k);
            down(k);
        }
        else{
            cin>>k>>x;
            k=ph[k];
            h[k]=x;
            up(k);
            down(k);
        }
    }
    return 0;
}

好的,以下是Java实现的排序代码: ```java public class HeapSort { public void sort(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--) { // 将顶元素与当前未排序部分的最后一个元素交换 int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; // 重新构建最大 heapify(arr, i, 0); } } // 以根节点为i的子树为最大 void heapify(int[] arr, int n, int i) { int largest = i; int l = 2 * i + 1; // 左子节点 int r = 2 * i + 2; // 右子节点 // 如果左子节点比根节点大,则更新最大值 if (l < n && arr[l] > arr[largest]) largest = l; // 如果右子节点比最大值大,则更新最大值 if (r < n && arr[r] > arr[largest]) largest = r; // 如果最大值不是根节点,则交换根节点和最大值,并继续向下调整 if (largest != i) { int swap = arr[i]; arr[i] = arr[largest]; arr[largest] = swap; heapify(arr, n, largest); } } } ``` 在排序中,我们首先构建一个最大,然后依次将顶元素移到数组末尾,并重新构建最大。`heapify()`方法用于将以根节点为i的子树调整为最大,其中n表示当前的大小。在`heapify()`方法中,我们首先找到根节点、左子节点和右子节点中的最大值,如果最大值不是根节点,则交换根节点和最大值,并继续向下调整。在排序中,时间复杂度为O(nlogn),空间复杂度为O(1)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值