堆和堆排序的实现

目录

一,堆的实现

1.结构

2,函数接口

3,接口实现

4,代码链接

二,堆排序的实现

1.建堆

2,选择排序思想,只不过是用堆来选择。


一,堆的实现

1.结构

//堆的底层是一个完全二叉树,所以说我们用数组实现是不会有空间的浪费的。
//物理上是一个数组,但是逻辑上可以把他想象成一颗二叉树。

typedef  int HPDataType;
typedef struct Heap
{
    HPDataType* a;
    size_t size;
    size_t capacity;
}Heap;

2,函数接口

void swap(HPDataType* pa, HPDataType* pb);
void HeapInit(Heap* php);
void HeapDestroy(Heap* php);
void HeapPrint(Heap* php);

// 插入x以后,保持他依旧是(大/小)堆
void HeapPush(Heap* php, HPDataType x);

// 删除堆顶的数据。(最小/最大)
void HeapPop(Heap* php);
bool HeapEmpty(Heap* php);
size_t HeapSize(Heap* php);
HPDataType HeapTop(Heap* php);
//向上调整算法
void Adjustup(HPDataType* a,size_t child);
//向下调整算法。
void Adjustdown(HPDataType* a, size_t size,size_t root);

3,接口实现

void swap(HPDataType* pa, HPDataType* pb)
{
    HPDataType tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}
void Adjustup(HPDataType* a, size_t child)
{
    //假设我们这里搞一个小堆。大堆的话也是对应的。
    assert(a);
    size_t parent = (child - 1) / 2;
    while (child > 0)
    {
        //if (a[child] > a[parent])  大堆
            if (a[child] < a[parent])   //小堆
        {
            swap(&a[child], &a[parent]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
        {
            //走到这里那就是已经是堆了,可以提前结束了。
            break;
        }
    }
}

void Adjustdown(HPDataType* a, size_t size, size_t root)
{
    assert(a);
    //假设我们这里还是建小堆
    size_t parant = root;
    size_t child = parant*2+1;  //这里默认是左孩子,要算有孩子加一就是了。
    while (child<size)
    {
        //选出左右孩子中的较小的那个
        if (child+1<size && a[child + 1] < a[child])
        {
            child++;
        }
        //小堆,大堆相反就行。
        if (a[child] < a[parant])
        {
            swap(&a[child], &a[parant]);
            parant = child;
            child = parant*2+1;
        }
        else
        {
            //已经是堆了,不需要调整了,提前结束。
            break;
        }
    }
}
void HeapInit(Heap* php)
{
    assert(php);  //给我传的结构体一定不能为空吧。
    php->a = NULL;
    php->capacity = php->size = 0;
}
void HeapDestroy(Heap* php)
{
    assert(php);
    free(php->a);
    php->a = NULL;
    php->capacity = php->size = 0;
    //这里不可以释放php。
}
void HeapPrint(Heap* php)
{
    assert(php);
    for (size_t i = 0; i < php->size; i++)
        printf("%d ", php->a[i]);
        printf("\n");
}

// 插入x以后,保持他依旧是(大/小)堆
void HeapPush(Heap* php, HPDataType x)
{
    assert(php);
    if (php->capacity == php->size)
    {
        //扩容。
        int nwecapacity = php->capacity == 0 ? 4 : php->capacity * 2;
        HPDataType* tmp = realloc(php->a, nwecapacity * sizeof(HPDataType));
        //检查开空间是否成功。
        if (tmp == NULL)
        {
            printf("realloc  fail\n");
            exit(-1);
        }
            php->a = tmp;
            php->capacity = nwecapacity;   //容易忘记
    }

    php->a[php->size++] = x;  //在最后插入。
    //插入之后堆的结构就可能不能保持了,需要向上调整,因为我们是在最后插入。
    Adjustup(php->a, php->size - 1);  //第二个参数传的是从那个位置开始调整。
}

// 删除堆顶的数据。(最小/最大)
void HeapPop(Heap* php)
{
    assert(php);
    assert(php->size > 0);
    swap(&php->a[0], &php->a[php->size - 1]);
    php->size--;
    //Adjustdown(php->a, php->size - 1, 0);   size前面已经减过了,不需要在减了。
    Adjustdown(php->a, php->size, 0);
}
bool HeapEmpty(Heap* php)
{
    assert(php);
    return php->size == 0;
}
size_t HeapSize(Heap* php)
{
    assert(php);
    return php->size;
}
HPDataType HeapTop(Heap* php)
{
    assert(php);
    assert(php->size > 0);
    return php->a[0];
}

4,代码链接

data structure: 数据解构练习 - Gitee.com

二,堆排序的实现

本质其实是一种选择排序,排降序建小堆,排升序,建大堆。

选出一个数之后,在不破换结构的基础上把他放到该有的位置

上。

1.建堆

建堆    向上调整建堆  或  向下调整建堆。   比较时间复杂度发现向下调整是更优秀的。所以我们用向下调整来建堆,向下调整算法,向上调整算法在堆的实现里面都是有的,就是那个Adjustup()和Adjustdowm()看函数名字因该就可以区分那个是那个了。

for (int i = (n - 2) / 2; i >=0; i--)
	{
		Adjustdown(a,n, i);  //第二个参数是数据个数,限制了最多向下到哪里。
	}

2,选择排序思想,只不过是用堆来选择。

	//这里其实本质上是用来选择排序的思想,选出一个数,放到他该有的位置上。
	size_t end = n - 1;
	while (end > 0)
	{
		swap(&a[end], &a[0]);
		Adjustdown(a, end, 0);
		end--;   //--之后代表最后一个元素的位置,没减之前代表需要调整的元素个数。
	}

选好一个数之后就放到该有的位置上,然后调整剩下的,使之还是一个堆,用向下调整算法去调整。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LYH_1_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值