【数据结构系列】堆(C、C++实现)

文章目录

  • 一、堆的基本概念
  • 二、C 实现
    • 1、数据结构及函数声明(.h)
    • 2、功能函数(.m)
    • 3、Example
  • 三、C++实现
    • 0、STL库调用
    • 1、数据结构及函数声明(.h)
    • 2、功能函数(.m)
    • 3、Example(git)

一、堆的基本概念

1、定义:最小堆,是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。
2、特性(2个)
(1)结构性:它是能用数组表示的完全二叉树
(2)堆序性:任一结点的关键字是其子树所有结点的最大值(最大堆)或最小值(最小堆),即任意子树也应该是个堆。

3、适用

4、实现:使用含有哨兵元素的数组实现了最小堆的创建、插入和删除,完全二叉树之所以用数组的方式存在,在于他的一个特性 若子节点为i,则父节点为(i-1)/2,若父节点为j,则子节点必为2*j+1;则在数组里面可以非常方便的通过下标去获取。

二叉堆一般使用数组来表示。请回忆一下二叉树的性质,其中有一条性质:
如果对一棵有n个节点的完全二叉树的节点按层序编号,对任一节点i有:
如果i=1 ,则节点为根节点,没有双亲。
如果2 * i > n ,则节点i没有左孩子 ;否则其左孩子节点为2i . (n为节点总数)
如果2 * i+1>n ,则节点i没有右孩子;否则其右孩子节点为2
1+1.

二、C 实现

https://blog.csdn.net/qq_30163461/article/details/78681931

1、数据结构及函数声明(.h)

#include 
#include 

#define MinData -100//哨兵元素的值
typedef struct HeapStruct{
    int *p;
    int size;
    int capacity; //容量
} *MinHeap;

//初始化
MinHeap Init_MinHeap(int MaxSize);
//是否装满
int IsFull(MinHeap H);
//是否为空
int IsEmpty(MinHeap H);
//插入
void Insert(MinHeap H, int data);
//删除
int Delete(MinHeap H);
//创建
void BuildMinHeap(MinHeap H, int N);
//打印
void PrintValue(MinHeap H);

2、功能函数(.m)

#include "HeapFun.h"
//创建最小堆
void BuildMinHeap(MinHeap H, int N){
    int i, num, parent, child, root, lastvalue;
    if(N>H->capacity)return;
    for (ing i = 1; i<= N ; i++) {
        scanf_s("%d", &num);
        H->p[i] = num;
    }
    H->size = N;
    root = N/2;
    while (root) {
        lastvalue = H->p[root];
        for (parent = root; 2 * parent <= H->size; parent = child)
        {
            child = 2 * parent;/*默认左结点的元素值更小*/
            if (child != H->size && H->p[child + 1] < H->p[child])/*右结点元素值更小*/
                child++;
            if (lastvalue < H->p[child])
                break;
            else
                H->p[parent] = H->p[child];
        }
        H->p[parent] = lastvalue;
        --root;
    }
}

//初始化最小堆:该函数给最小堆分配了内存空间并完成初始化操作,此时最小堆中元素为空。
MinHeap Init_MinHeap(int MaxSize){
    MinHeap H = (MinHeap) malloc(sizeof(HeapStruct));
    H->capacity = MaxSize;
    H->p = (int*)malloc((MaxSize+1)*sizeof(int));
    H->size = 0;
    H->p[0] = MinData;
    return  H;
}

//插入最小堆
void Insert(MinHeap H, int data){
    if(IsFull(H))return;
    for (int i = ++H->size; data < H->p[i/2]; i/=2) {
        H->p[i] = H->p[i/2];
    }
    H->p[i] = data;
}

//删除最小堆中最小元素
int Delete(MinHeap H){
    if(IsEmpty(H))return ;

    int minvalue , lastvalue, child, parent;
    minvalue = H->p[1];
    lastvalue = H->p[H->size--];
    for (parent = 1; 2 * parent <= H->size; parent = child)
    {
        child = 2 * parent;/*默认左结点的元素值更小*/
        if (child != H->size && H->p[child + 1] < H->p[child])/*若右节点的元素值更小,则调整child*/
            child++;
        if (lastvalue < H->p[child])
            break;
        else
            H->p[parent] = H->p[child];
    }
    H->p[parent] = lastvalue;
    return minvalue;
}

//打印
void PrintValue(MinHeap H){
    for (int i = 1; i< H->size; i++) {
        printf("%d ",H->p[i]);
    }
}

//判断是否装满
int IsFull(MinHeap H){
    return (H->capacity == H->size)?1:0;
}

//判断是否为空
int IsEmpty(MinHeap H){
    return (0 == H->size)?1:0;
}

3、Example

void main()
{
	int num;
	MinHeap H;
	H = Init_MinHeap(100);
	BuildMinHeap(H, 15);
	PrintValue(H);
 
	printf("请输入你要插入的数据:");
	scanf_s("%d", &num);
	Insert(H, num);
	PrintValue(H);
	printf("请输入你要插入的数据:");
	scanf_s("%d", &num);
	Insert(H, num);
	PrintValue(H);
 
	num = Delete(H);
	printf("删除的元素为:%d\n", num);
	PrintValue(H);

三、C++实现

0、STL库调用

STL库中实现了堆/优化队列。
priority_queue 容器适配器定义了一个元素有序排列的队列。默认队列头部的元素优先级最高。因为它是一个队列,所以只能访问第一个元素,这也意味着优先级最高的元素总是第一个被处理。

> 创建:
template , typename Compare=std::less> class priority_queue
//priority_queue 模板有 3 个参数,其中两个有默认的参数;第一个参数是存储对象的类型,第二个参数是存储元素的底层容器,第三个参数是函数对象,它定义了一个用来决定元素顺序的断言。
//函数对象类型 less 是一个默认的排序断言,即最大堆。fonction 中定义了  greater,即最小堆。

push(const T& obj):将obj的副本放到容器的适当位置,这通常会包含一个排序操作。
push(T&& obj):将obj放到容器的适当位置,这通常会包含一个排序操作。
emplace(T constructor a rgs...):通过调用传入参数的构造函数,在序列的适当位置构造一个T对象。为了维持优先顺序,通常需要一个排序操作。
top():返回优先级队列中第一个元素的引用。
pop():移除第一个元素。
size():返回队列中元素的个数。
empty():如果队列为空的话,返回true。
swap(priority_queue& other):和参数的元素进行交换,所包含对象的类型必须相同。

1、数据结构及函数声明(.h)

http://www.cnblogs.com/QG-whz/p/5173112.html

template 
class MaxHeap
{
public:
    bool insert(T val);     //往二叉堆中插入元素
    bool remove(T data);    //移除元素
    void print();           //打印堆
    T getTop();             //获取堆顶元素
    bool createMaxHeap(T a[], int size);//根据指定的数组来创建一个最大堆

    MaxHeap(int cap = 10);
    ~MaxHeap();

private:
    int capacity;   //容量,也即是数组的大小
    int size;       //堆大小,也即是数组中有效元素的个数
    T * heap;       //底层的数组
private:
    void filterUp(int index); //从index所在节点,往根节点调整堆
    void filterDown(int begin ,int end ); //从begin所在节点开始,向end方向调整堆
};

2、功能函数(.m)

/*从下到上调整堆*/
/*插入元素时候使用*/
template 
void MaxHeap::filterUp(int index)
{
    T value = heap[index];  //插入节点的值,图中的12

    while (index > 0) //如果还未到达根节点,继续调整
    {
        int indexParent = (index -1)/ 2;  //求其双亲节点
        if (value< heap[indexParent])
            break;
        else 
        {
            heap[index] = heap[indexParent];
            index = indexParent;
        }
    }
    heap[index] = value;    //12插入最后的位置
};

/*插入元素*/
template 
bool MaxHeap::insert(T val)
{
    if (size == capacity) //如果数组已满,则返回false
        return false;
    heap[size] = val;
    filterUp(size);
    size++;
    return true;
};
*从上到下调整堆*/
/*删除元素时候使用*/
template
void MaxHeap::filterDown(int current,int end)
{

    int child = current * 2 + 1; //当前结点的左孩子

    T value = heap[current];    //保存当前结点的值

    while (child <= end)
    {
        if (child < end && heap[child] < heap[child+1])//选出两个孩子中较大的孩子
            child++;
        if (value>heap[child])  //无须调整;调整结束
            break;
        else
        {
            heap[current] = heap[child];    //孩子节点覆盖当前结点
            current = child;                //向下移动
            child = child * 2 + 1;          
        }
    }
    heap[current] = value;
};

/*删除元素*/
template
bool MaxHeap::remove(T data)
{
    if (size == 0) //如果堆是空的
        return false;
    int index;
    for (index = 0; index < size; index++)  //获取值在数组中的索引
    {
        if (heap[index] == data)
            break;
    }
    if (index == size)            //数组中没有该值
        return false; 
 
    heap[index] = heap[size - 1]; //使用最后一个节点来代替当前结点,然后再向下调整当前结点。
 
    filterDown(index,size--);  
 
    return true;
};

*打印大顶堆*/
template 
void MaxHeap::print()
{
    for (int i = 0; i < size; i++)
        cout << heap[i] << " ";
};
/*获取堆顶元素*/
template 
T MaxHeap::getTop()
{
    if (size != 0)
        return heap[0];
};

/*根据指定的数组来创建一个最大堆*/
template
bool MaxHeap::createMapHeap(T a[], int size)
{
    if (size > capacity)    //  堆的容量不足以创建
        return false;
    for (int i = 0; i < size; i++)
    {
        insert(a[i]);
    }
    return true;
};

3、Example(git)

int _tmain(int argc, _TCHAR* argv[])
{
    MaxHeap heap(11);
    //逐个元素构建大顶堆
    for (int i = 0; i < 10; i++)
    {
        heap.insert(i);
    }
    heap.print();
    cout << endl;
    heap.remove(8);
    heap.print();
    cout << endl;

    //根据指定的数组创建大顶堆
    MaxHeap heap2(11);
    int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    heap2.createMaxHeap(a, 10);
    heap2.print();
    getchar();
    return 0;
}

你可能感兴趣的:(算法&数据结构)