堆的相关操作

堆的定义

堆(Heap)是一种数据结构,堆通常是可以被看做一棵完全二叉树的数组对象。

  • 堆的特性
  1. 结构性:用数组表示的完全二叉树
  2. 有序性:任一节点的关键字是其子树所有节点的最大值(或最小值)

堆的类型

最大堆(MaxHeap):也称“大顶堆”,有序性表示为根节点存储的值为子树所有节点的最大值
最小堆(MinHeap):也称“小顶堆”,有序性表示为根节点存储的值为子树所有节点的最小值

堆结构的创建

//定义堆结构
typedef struct HNode{
    int* Data;	//存储数据的数组
    int Size;	//当前堆中的元素个数
    int capacity;	//最大容量
    HNode()	//构造函数进行初始化
    {
        Data = new int[100];
        Size = 0;
        Data[0] = 1000;//   哨兵
        capacity = 100;//  可存入100个数据
    }
}HNode,*Heap;

大顶堆的操作

插入操作

  • 在进行插入时,首先判断堆是否已满,堆满则不进行插入,堆未满,进行插入;
  • 先将元素存入堆尾(Size + 1)的位置,再进行向上比较,如果大于其父节点,则向上替换,直到替换至根节点
//大顶堆插入操作
void Insert_MaxHeap(Heap H,int x)
{
    if(H->Size == H->capacity)  //检查堆是否已满
        return;
    ++H->Size;  //  插入元素,首先插入到堆尾
    int position = H->Size;
    for(;H->Data[position / 2] < x;position /= 2)
        H->Data[position] = H->Data[position / 2];
    H->Data[position] = x;
}

删除操作

  • 在进行删除时,首先检查堆是否为空,为空,则不进行删除,不为空,执行删除操作
  • 将堆尾元素保存至堆的第一个元素,从上而下,判断该元素是否大于其孩子节点的值,如果大于,则直接返回,小于,则进行替换,直到最后一个元素
//大顶堆删除堆顶元素
void Delete_MaxHeap(Heap H)
{
    int tmp = H->Data[H->Size]; //先存储堆中最后一个元素
    H->Size--;
    int parent = 1;
    int child = 0;
    for(;parent * 2 <= H->Size;)
    {
        child = parent * 2;
        if(child < H->Size && H->Data[child] < H->Data[child + 1])	//在孩子节点中寻找最大的
            child++;
        if(tmp > H->Data[child])
            break;
        else
            H->Data[parent] = H->Data[child];
        parent = child;
    }
    H->Data[parent] = tmp;
}

创建大顶堆

创建一个大顶堆有两种思路:

  1. 进行一组循环插入,把所有元素进行插入操作,完成创建,但是这种方式,效率较低,时间复杂度为O(n logn)
  2. 将要创建的数据无序插入堆中,然后对堆中的元素进行调整,从最后的一棵树开始,使得每棵树都是一个大顶堆
    方法一
//创建大顶堆:方法一(O(N logN))
void Build_MaxHeap_1(Heap H,vector<int> data)
{
    for(int i = 0;i < data.size();i++)
        Insert_MaxHeap(H,data[i]);
}

方法二

//创建大顶堆:方法二(O(N))
void Build_MaxHeap_2(Heap H,vector<int> data)
{
    for(int i = 0;i < data.size();i++)	//无序存入堆中
        H->Data[i + 1] = data[i];
    H->Size = data.size();
    int judge = H->Size / 2;
    for(;judge > 0;judge--)	//从最后一棵右孩子节点的树开始调整
    {
        int tmp = H->Data[judge];
        int parent = judge;
        int child = judge;
        while(parent*2 <= H->Size)	//进行调整
        {
            child = parent * 2;
            if(child < H->Size && H->Data[child] < H->Data[child + 1])
                child++;
            if(tmp > H->Data[child])
                break;
            else
                H->Data[parent] = H->Data[child];
            parent = child;
        }
        H->Data[parent] = tmp;
    }
}

取堆顶元素

//大顶堆取堆顶元素
int Top_MaxHeap(Heap H)
{
    if(H->Size == 0)	//判断堆是否为空
	return -1;
    return H->Data[1];
}

小顶堆的操作

插入操作

  • 在进行插入时,首先判断堆是否已满,堆满则不进行插入,堆未满,进行插入;
  • 先将元素存入堆尾(Size + 1)的位置,再进行向上比较,如果小于其父节点,则向上替换,直到替换至根节点
//小顶堆插入操作
void Insert_MinHeap(Heap H,int x)
{
    if(H->Size == H->capacity)  //检查堆是否已满
        return;
    H->Data[0] = -999;  //哨兵
    ++H->Size;
    int position = H->Size;
    for(;H->Data[position / 2] > x;position /= 2)
        H->Data[position] = H->Data[position/2];
    H->Data[position] = x;
}

删除操作

  • 在进行删除时,首先检查堆是否为空,为空,则不进行删除,不为空,执行删除操作
  • 将堆尾元素保存至堆的第一个元素,从上而下,判断该元素是否小于其孩子节点的值,如果小于,则直接返回,大于于,则进行替换,直到最后一个元素
//小顶堆删除堆顶元素
void Delete_MinHeap(Heap H)
{
    if(H->Size == 0)    //检查堆是否为空
        return;
    int tmp = H->Data[H->Size];
    H->Size--;
    int parent = 1;
    int child = 0;
    while(parent*2 <= H->Size)
    {
        child = parent*2;
        if(child < H->Size && H->Data[child] > H->Data[child + 1])
            child++;
        if(tmp > H->Data[child])
            H->Data[parent] = H->Data[child];
        else
            break;
        parent = child;
    }
    H->Data[parent] = tmp;
}

创建小顶堆

创建一个小顶堆有两种思路:

  1. 进行一组循环插入,把所有元素进行插入操作,完成创建,但是这种方式,效率较低,时间复杂度为O(n logn)
  2. 将要创建的数据无序插入堆中,然后对堆中的元素进行调整,从最后的一棵树开始,使得每棵树都是一个小顶堆
    方法一
//创建小顶堆:方法一(O(N logN))
void Build_MinHeap_1(Heap H,vector<int> data)
{
    for(int i = 0;i < data.size();i++)
        Insert_MinHeap(H,data[i]);
}

方法二

//创建小顶堆:方法二(O(N))
void Build_MinHeap_2(Heap H,vector<int> data)
{
    for(int i = 0;i < data.size();i++)
        H->Data[i + 1] = data[i];
    H->Size = data.size();
    int judge = H->Size / 2;
    for(;judge > 0;judge--)
    {
        int tmp = H->Data[judge];
        int parent = judge;
        int child = 0;
        while(parent*2 <= H->Size)
        {
            child = parent*2;
            if(child < H->Size && H->Data[child] > H->Data[child + 1])
                child++;
            if(tmp > H->Data[child])
                H->Data[parent] = H->Data[child];
            else
                break;
            parent = child;
        }
        H->Data[parent] = tmp;
    }
}

取堆顶元素

//小顶堆取堆顶元素
int Top_MinHeap(Heap H)
{
    if(H->Size == 0)
        return -1;
    return H->Data[1];
}

打印堆

//打印堆
void Print(Heap H)
{
    for(int i = 1;i < H->Size + 1;i++)
        cout << H->Data[i] << " ";
    cout << endl;
}

堆排序

这里给出了4中排序方式:
方式一:将最大堆堆顶元素依次出堆,存入一个数组中,最后返回数组,这样实现了元素从大到小的排序,但是会额外消耗O(n)的空间
方式二:将最小堆堆顶元素依次出堆,存入一个数组中,最后返回数组,这样实现了元素从小到大的排序,但是会额外消耗O(n)的空间
方式三:将最大堆堆顶元素与堆尾元素进行替换,再调整最大堆,重复n次,即可实现升序排序
方式四:将最小堆堆顶元素与堆尾元素进行替换,再调整最大堆,重复n次,即可实现降序排序
方式一:

//堆排序1:从大到小,借助额外空间,利用大顶堆
vector<int> HeapSort_1(Heap H)
{
    vector<int> Sort;
    int Size = H->Size;
    for(int i = 0;i < Size;i++)
    {
        Sort.push_back(Top_MaxHeap(H));
        Delete_MaxHeap(H);
    }
    return Sort;
}

方式二:

//堆排序2:从小到大,借助额外空间,利用小顶堆
vector<int> HeapSort_2(Heap H)
{
    vector<int> Sort;
    int Size = H->Size;
    for(int i = 0;i < Size;i++)
    {
        Sort.push_back(Top_MinHeap(H));
        Delete_MinHeap(H);
    }
    return Sort;
}

方式三:

//堆排序3:从小到大,不借助额外空间,利用大顶堆
void HeapSort_3(Heap H)
{
    int Rear = H->Size;
    for(;Rear > 1;)
    {
        int tmp = H->Data[Rear];	//保存堆尾元素,与删除操作类似
        H->Data[Rear] = H->Data[1];
        Rear--;
        int parent = 1;
        int child = 0;
        while(parent * 2 <= Rear)
        {
            child = parent * 2;
            if(child < Rear && H->Data[child] < H->Data[child + 1])
                child++;
            if(tmp > H->Data[child])
                break;
            else
                H->Data[parent] = H->Data[child];
            parent = child;
        }
        H->Data[parent] = tmp;
    }
}

方式四:

//堆排序4:从大到小,不借助额外空间,利用小顶堆
void HeapSort_4(Heap H)
{
    int Rear = H->Size;
    for(;Rear > 1;)
    {
        int tmp = H->Data[Rear];
        H->Data[Rear] = H->Data[1];
        Rear--;
        int parent = 1;
        int child = 0;
        while(parent*2 <= Rear)
        {
            child = parent * 2;
            if(child < Rear && H->Data[child] > H->Data[child + 1])
                child++;
            if(tmp > H->Data[child])
                H->Data[parent] = H->Data[child];
            else
                break;
            parent = child;
        }
        H->Data[parent] = tmp;
    }
}

测试数据

生成给定长度的一组不重复的随机数

//测试数据
vector<int> randVector(int num) {
    vector<int> result;
    result.clear();
    result.reserve(num);
    srand((int)time(0));
    for (int i = 0; i < num; i++)
    {
        result.push_back(i);
    }
    int p1;
    int p2;
    int temp;
    while (--num)
    {
        p1 = num;
        p2 = rand() % num;
        temp = result[p1];
        result[p1] = result[p2];
        result[p2] = temp;
    }
    return result;
}

完整程序

#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;

//定义堆结构
typedef struct HNode{
    int* Data;
    int Size;
    int capacity;
    HNode()
    {
        Data = new int[100];
        Size = 0;
        Data[0] = 1000;//   哨兵
        capacity = 1000;//  可存入1000个数据
    }
}HNode,*Heap;

//大顶堆插入操作
void Insert_MaxHeap(Heap H,int x)
{
    if(H->Size == H->capacity)  //检查堆是否已满
        return;
    ++H->Size;  //  插入元素,首先插入到堆尾
    int position = H->Size;
    for(;H->Data[position / 2] < x;position /= 2)
        H->Data[position] = H->Data[position / 2];
    H->Data[position] = x;
}

//小顶堆插入操作
void Insert_MinHeap(Heap H,int x)
{
    if(H->Size == H->capacity)  //检查堆是否已满
        return;
    H->Data[0] = -999;  //哨兵
    ++H->Size;
    int position = H->Size;
    for(;H->Data[position / 2] > x;position /= 2)
        H->Data[position] = H->Data[position/2];
    H->Data[position] = x;
}

//大顶堆取堆顶元素
int Top_MaxHeap(Heap H)
{
    return H->Data[1];
}

//小顶堆取堆顶元素
int Top_MinHeap(Heap H)
{
    if(H->Size == 0)
        return -1;
    return H->Data[1];
}

//大顶堆删除堆顶元素
void Delete_MaxHeap(Heap H)
{
    int tmp = H->Data[H->Size]; //先存储堆中最后一个元素
    H->Size--;
    int parent = 1;
    int child = 0;
    for(;parent * 2 <= H->Size;)
    {
        child = parent * 2;
        if(child < H->Size && H->Data[child] < H->Data[child + 1])
            child++;
        if(tmp > H->Data[child])
            break;
        else
            H->Data[parent] = H->Data[child];
        parent = child;
    }
    H->Data[parent] = tmp;
}

//小顶堆删除堆顶元素
void Delete_MinHeap(Heap H)
{
    if(H->Size == 0)    //检查堆是否为空
        return;
    int tmp = H->Data[H->Size];
    H->Size--;
    int parent = 1;
    int child = 0;
    while(parent*2 <= H->Size)
    {
        child = parent*2;
        if(child < H->Size && H->Data[child] > H->Data[child + 1])
            child++;
        if(tmp > H->Data[child])
            H->Data[parent] = H->Data[child];
        else
            break;
        parent = child;
    }
    H->Data[parent] = tmp;
}

//创建大顶堆:方法一(O(N logN))
void Build_MaxHeap_1(Heap H,vector<int> data)
{
    for(int i = 0;i < data.size();i++)
        Insert_MaxHeap(H,data[i]);
}

//创建小顶堆:方法一(O(N logN))
void Build_MinHeap_1(Heap H,vector<int> data)
{
    for(int i = 0;i < data.size();i++)
        Insert_MinHeap(H,data[i]);
}

//创建大顶堆:方法二(O(N))
void Build_MaxHeap_2(Heap H,vector<int> data)
{
    for(int i = 0;i < data.size();i++)
        H->Data[i + 1] = data[i];
    H->Size = data.size();
    int judge = H->Size / 2;
    for(;judge > 0;judge--)
    {
        int tmp = H->Data[judge];
        int parent = judge;
        int child = judge;
        while(parent*2 <= H->Size)
        {
            child = parent * 2;
            if(child < H->Size && H->Data[child] < H->Data[child + 1])
                child++;
            if(tmp > H->Data[child])
                break;
            else
                H->Data[parent] = H->Data[child];
            parent = child;
        }
        H->Data[parent] = tmp;
    }
}

//创建小顶堆:方法二(O(N))
void Build_MinHeap_2(Heap H,vector<int> data)
{
    for(int i = 0;i < data.size();i++)
        H->Data[i + 1] = data[i];
    H->Size = data.size();
    int judge = H->Size / 2;
    for(;judge > 0;judge--)
    {
        int tmp = H->Data[judge];
        int parent = judge;
        int child = 0;
        while(parent*2 <= H->Size)
        {
            child = parent*2;
            if(child < H->Size && H->Data[child] > H->Data[child + 1])
                child++;
            if(tmp > H->Data[child])
                H->Data[parent] = H->Data[child];
            else
                break;
            parent = child;
        }
        H->Data[parent] = tmp;
    }
}

//打印堆
void Print(Heap H)
{
    for(int i = 1;i < H->Size + 1;i++)
        cout << H->Data[i] << " ";
    cout << endl;
}

//堆排序1:从大到小,借助额外空间,利用大顶堆
vector<int> HeapSort_1(Heap H)
{
    vector<int> Sort;
    int Size = H->Size;
    for(int i = 0;i < Size;i++)
    {
        Sort.push_back(Top_MaxHeap(H));
        Delete_MaxHeap(H);
    }
    return Sort;
}

//堆排序2:从小到大,借助额外空间,利用小顶堆
vector<int> HeapSort_2(Heap H)
{
    vector<int> Sort;
    int Size = H->Size;
    for(int i = 0;i < Size;i++)
    {
        Sort.push_back(Top_MinHeap(H));
        Delete_MinHeap(H);
    }
    return Sort;
}

//堆排序3:从小到大,不借助额外空间,利用大顶堆
void HeapSort_3(Heap H)
{
    int Rear = H->Size;
    for(;Rear > 1;)
    {
        int tmp = H->Data[Rear];
        H->Data[Rear] = H->Data[1];
        Rear--;
        int parent = 1;
        int child = 0;
        while(parent * 2 <= Rear)
        {
            child = parent * 2;
            if(child < Rear && H->Data[child] < H->Data[child + 1])
                child++;
            if(tmp > H->Data[child])
                break;
            else
                H->Data[parent] = H->Data[child];
            parent = child;
        }
        H->Data[parent] = tmp;
    }
}

//堆排序4:从大到小,不借助额外空间,利用小顶堆
void HeapSort_4(Heap H)
{
    int Rear = H->Size;
    for(;Rear > 1;)
    {
        int tmp = H->Data[Rear];
        H->Data[Rear] = H->Data[1];
        Rear--;
        int parent = 1;
        int child = 0;
        while(parent*2 <= Rear)
        {
            child = parent * 2;
            if(child < Rear && H->Data[child] > H->Data[child + 1])
                child++;
            if(tmp > H->Data[child])
                H->Data[parent] = H->Data[child];
            else
                break;
            parent = child;
        }
        H->Data[parent] = tmp;
    }
}

//打印排序数组
void Print_Vector(vector<int> num)
{
    for(int i = 0;i < num.size();i++)
        cout << num[i] << " ";
    cout << endl;
}

//测试数据
vector<int> randVector(int num) {
    vector<int> result;
    result.clear();
    result.reserve(num);
    srand((int)time(0));
    for (int i = 0; i < num; i++)
    {
        result.push_back(i);
    }
    int p1;
    int p2;
    int temp;
    while (--num)
    {
        p1 = num;
        p2 = rand() % num;
        temp = result[p1];
        result[p1] = result[p2];
        result[p2] = temp;
    }
    return result;
}

int main()
{
    vector<int> test = randVector(20);
    vector<int> Sort1;
    vector<int> Sort2;
    //vector<>
    Heap H1 = new HNode();
    Heap H2 = new HNode();
    Heap H3 = new HNode();
    Heap H4 = new HNode();
    cout << "----堆的相关操作----" << endl;
    Build_MaxHeap_1(H1,test);
    cout << endl << "方式一创建的大顶堆:" << endl;
    Print(H1);
    Build_MaxHeap_2(H2,test);
    cout << endl << "方式二创建的大顶堆:" << endl;
    Print(H2);
    Build_MinHeap_1(H3,test);
    cout << endl << "方式一创建的小顶堆:" << endl;
    Print(H3);
    Build_MinHeap_2(H4,test);
    cout << endl << "方式二创建的小顶堆:" << endl;
    Print(H4);
    Sort1 = HeapSort_1(H1);
    cout << endl << "堆排序1:从大到小,借助额外空间,利用大顶堆" << endl;
    Print_Vector(Sort1);
    Sort2 = HeapSort_2(H3);
    cout << endl << "堆排序2:从小到大,借助额外空间,利用小顶堆" << endl;
    Print_Vector(Sort2);
    HeapSort_3(H2);
    cout << endl << "堆排序3:从小到大,不借助额外空间,利用大顶堆" << endl;
    Print(H2);
    HeapSort_4(H4);
    cout << endl << "堆排序4:从大到小,不借助额外空间,利用小顶堆" << endl;
    Print(H4);
    return 0;
}

程序运行结果

堆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值