数据结构堆的实现以及堆的面试题

堆的特点

堆有大堆和小堆之分

小堆:
①任意结点的关键码均小于等于他的左右孩子的关键码
②位于堆顶的结点的关键码最小
③从根结点到每个结点的路径上数组元素组成的序列都是递增的

大堆:
①任意结点的关键码均大于等于他的左右孩子的关键码
②位于堆顶的结点的关键码最大
③从根结点到每个结点的路径上数组元素组成的序列都是递减的

这里写图片描述

堆存储在下标为0的数组中,因此在堆中给定下标为i的结点时有:
①如果i=0,结点i是根节点,没有双亲节点;否则结点i的双亲结点为
结点(i-1)/2
②如果2 * i + 1 <= n - 1(n为堆中结点个数),则结点i的左孩子为结
点2 * i + 1,否则结点i无左孩子
③如果2 * i + 2 <= n - 1(同上),则结点i的右孩子为结点2 * i + 2,
否则结点i无右孩子

堆的实现

heap.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int HPDataType;
typedef int (*PCompare)(HPDataType left, HPDataType right);//函数指针,用小堆就选Less,用大堆就选Greater
typedef struct Heap
{
    HPDataType *_hp;
    int _size;//堆中的元素个数
    int _capacity;//堆的容量
    PCompare _com;
}Heap;

// 小于比较 
int Less(HPDataType left, HPDataType right);
// 大于比较 
int Greater(HPDataType left, HPDataType right);
// 初始化堆 
void InitHeap(Heap* hp);
// 创建堆 
void CreateHeap(Heap* hp, int* array, int size, PCompare com);
//检查扩容
void _CheckCapacity(Heap* hp);
// 在堆中插入元素data 
void InsertHeap(Heap* hp, HPDataType data);
// 删除堆顶的元素 
void RemoveHeap(Heap* hp);
// 获取堆中有效元素个数 
int SizeHeap(Heap* hp);
// 检测堆是否为空 
int EmptyHeap(Heap* hp);
// 获取堆顶元素 
HPDataType TopHeap(Heap* hp);
// 销毁堆 
void DestroyHeap(Heap* hp);
// 向下调整 
void AdjustDown(Heap* hp, int parent);
// 向上调整 
void AdjustUp(Heap* hp, int child);
heap.c


#include "heap.h"


int Less(HPDataType left, HPDataType right)
{
    return left < right;
}

int Greater(HPDataType left, HPDataType right)
{
    return left > right;
}

void InitHeap(Heap* hp)
{
    assert(hp);
    hp->_hp = (HPDataType*)malloc(3 * sizeof(HPDataType));//初始化开辟多少都行
    hp->_capacity = 3;
    hp->_size = 0;
}

void Swap(HPDataType *left, HPDataType*right)
{
    HPDataType tmp = 0;
    tmp = *left;
    *left = *right;
    *right = tmp;
}

void AdjustUp(Heap* hp, int child)
{
    assert(hp);
    int parent = (child - 1) / 2;//找出父母结点下标
    while (child)//只要child还为非零,就继续循环
    {
        if (hp->_com(hp->_hp[child], hp->_hp[parent]))//是否需要父母结点
                                                      //与孩子结点交换关键码
        {
            Swap(&hp->_hp[child], &hp->_hp[parent]);
            child = parent;//此时孩子结点上移到父母结点
            parent = (child - 1) / 2;//计算新的父母结点
        }
        else
            return;
    }
}

void AdjustDown(Heap* hp, int parent)
{
    assert(hp);
    if (NULL == hp)
        return;
    int child = parent * 2 + 1;//计算左孩子结点下标
    while (child < hp->_size)//只要孩子结点下标不越界
    {
        if (child + 1 < hp->_size&&hp->_com(hp->_hp[child+1],hp->_hp[child]))
        //是否需要左右孩子交换关键码,我是以左孩子是否与父母交换关键码为前提
        {
            Swap(&hp->_hp[child], &hp->_hp[child + 1]);
        }
        if (hp->_com(hp->_hp[child], hp->_hp[parent]))//是否左孩子与父母交换关键码
        {
            Swap(&hp->_hp[child], &hp->_hp[parent]);
            parent = child;//父母结点移到孩子结点,当做下一个父母结点
            child = parent * 2 + 1;
        }
        else
            return;
    }
}

void CreateHeap(Heap* hp, int* array, int size, PCompare com)
{
    assert(hp);
    int root = (size - 2) / 2;//找到最后一个非叶子结点的结点
    int i = 0;
    hp->_hp = (HPDataType*)malloc(size * sizeof(HPDataType));
    if (hp == NULL)
        return;
    for (i = 0; i < size; i++)
    {
        hp->_hp[i] = array[i];
    }
    hp->_capacity = size;
    hp->_size = size;
    hp->_com = com;
    while (root>=0)//从当前结点一直向下调整到下标为零的结点
    {
        AdjustDown(hp,root);
        root--;
    }
}

void _CheckCapacity(Heap* hp)
{
    assert(hp);
    int i = 0;
    HPDataType *new = NULL;
    int newcapacity = hp->_capacity * 2;
    new = (HPDataType*)malloc(newcapacity * sizeof(HPDataType));
    if (new == NULL)
        return;
    for (i = 0; i < hp->_size; i++)
    {
        new[i] = hp->_hp[i];
    }
    free(hp->_hp);
    hp->_hp = new;
    hp->_capacity = newcapacity;
}

void InsertHeap(Heap* hp, HPDataType data)
{
    assert(hp);
    if (hp->_capacity == hp->_size)
        _CheckCapacity(hp);
    hp->_hp[hp->_size] = data;//一定要先插入后size++
    AdjustUp(hp, hp->_size);
    hp->_size++;
}

void RemoveHeap(Heap* hp)
{
    assert(hp);
    if (NULL == hp)
        return;
    hp->_hp[0] = hp->_hp[hp->_size - 1];
    hp->_size--;//一定要先size--,后向下调整,否则他会把删除的结点也调整了
    AdjustDown(hp, 0);
}

int SizeHeap(Heap* hp)
{
    assert(hp);
    return hp->_size;
}

int EmptyHeap(Heap* hp)
{
    assert(hp);
    return 0 == hp->_size;
}

HPDataType TopHeap(Heap* hp)
{
    assert(hp);
    return hp->_hp[0];
}

void DestroyHeap(Heap* hp)
{
    assert(hp);
    if (hp)
    {
        free(hp);
        hp->_capacity = 0;
        hp->_size = 0;
    }
}

优先级队列

heap.h


typedef struct PriorityQueue
{
    Heap hp;
}PriorityQueue;

//初始化
void InitPriorityQueue(PriorityQueue* q);

//入队列
void PushPriorityQueue(PriorityQueue* q, HPDataType data);

//出队列
void PopPriorityQueue(PriorityQueue* q);

//取队头元素
void TopPriorityQueue(PriorityQueue* q);

//队列长度
int SizePriorityQueue(PriorityQueue* q);

//判空
int EmptyPriorityQueue(PriorityQueue* q);
heap.c


void InitPriorityQueue(PriorityQueue* q)
{
    InitHeap(&q->hp);
}

void PushPriorityQueue(PriorityQueue* q, HPDataType data)
{
    InsertHeap(&q->hp, data);
}

void PopPriorityQueue(PriorityQueue* q)
{
    RemoveHeap(&q->hp);
}

void TopPriorityQueue(PriorityQueue* q)
{
    return TopHeap(&q->hp);
}

int SizePriorityQueue(PriorityQueue* q)
{
    return SizeHeap(&q->hp);
}

int EmptyPriorityQueue(PriorityQueue* q)
{
    return EmptyHeap(&q->hp);
}

堆排序(降序,用小堆)

堆排序的原理
①将堆顶元素和堆中最后一个元素交换
②此时数组最后一个元素已经排好序了,因此将堆中元素减少一个
③此时堆结构可能被破坏,再向下调整使其满足堆的性质
④将以上三个步骤循环起来,直到排序完数组中的所有元素

void _AdjustDown(int *array, int size, int parent)
{
    int child = parent * 2 + 1;
    while (child < size)
    {
        if (child + 1 < size&&array[child + 1] < array[child])
        {
            Swap(&array[child + 1], &array[child]);
        }
        if (array[parent] > array[child])
        {
            Swap(&array[parent], &array[child]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
            return;
    }
}
void MakeHeap(int *array, int size)
{
    int root = (size - 2) / 2;
    while (root >= 0)
    {
        _AdjustDown(array,size, root);
        root--;
    }
}

void HeapSort(int *array, int size)
{
    MakeHeap(array, size);//把传过来的数组创建成堆
    while (size)//调整完所有元素
    {
        Swap(&array[0], &array[size - 1]);//交换堆顶元素和堆中最后一个元素
        size--;//减少堆中元素一个
        _AdjustDown(array, size, 0);//向下调整
    }
}

测试

test.c


#include "heap.h"
int main()
{
    //Heap hp;//被注释了的是测试堆的实现的代码,没被注释的是测试堆排序的代码,优先级队列大家就自己测试吧
    int i = 0;
    int array[] = { 53,17,78,9,45,65,87,23,31 };
    //InitHeap(&hp);
    //CreateHeap(&hp, array, sizeof(array)/sizeof(array[0]), Less);
    //for (i = 0; i < hp._size; i++)
    //{
    //  printf("%d ", hp._hp[i]);
    //}
    //printf("\n");
    //printf("%d ", TopHeap(&hp));
    //printf("%d ", SizeHeap(&hp));
    //printf("\n");
    int size = sizeof(array) / sizeof(array[0]);
    HeapSort(array,size);
    for (i = 0; i < size; i++)
    {
        printf("%d ", array[i]);
    }
    printf("\n");
    //InsertHeap(&hp,11);
    //for (i = 0; i < hp._size; i++)
    //{
    //  printf("%d ", hp._hp[i]);
    //}
    //printf("\n");
    //printf("%d ", TopHeap(&hp));
    //printf("%d ", SizeHeap(&hp));
    //printf("\n");
    //RemoveHeap(&hp);
    //for (i = 0; i < hp._size; i++)
    //{
    //  printf("%d ", hp._hp[i]);
    //}
    //printf("\n");
    //printf("%d ", TopHeap(&hp));
    //printf("%d ", SizeHeap(&hp));
    system("pause");
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值