堆排序算法分析

堆排序算法分析

一、简介

  • 堆排序算法是利用堆进行排序的方法,基本思想为:将待排序的序列构造成一个小(大)堆,此时,堆顶的元素就是整个序列的最小值(最大值),然后,将它移走(和堆数组末尾元素交换),然后将剩下的n-1个元素重新构建成一个堆,得到n个元素中的次小(大)堆,反复执行,就会得到一个有序序列了。
  • 堆性质:
    • 它是一个完全二叉树
    • 小堆:每个结点的值都小于或等于其左右孩子的结点值
    • 大堆:每个结点的值都大于或等于其左右孩子的结点值
  • 排升序:建立大堆
  • 排降序:建立小堆

二、复杂度计算

  • 构建堆时间复杂度分析:从完全二叉树的最下层最右边的非叶子结点开始构建,将它与其他孩子进行比较和是否有必要交换。
    假设高度为h的完全二叉树,有n个结点,第i层的高度为hi,第i层的元素个数ni = 2^(i-1),则第i层最坏的调整次数为:t(ni) = ni·hi,因此总时间复杂度t(n) = 1×(h-1) + 2 × (h-2)+…2^(h-2) ×1,该数列和为差比数列,运用错位相减法,可得到其和为:t(n) = 2^h - h - 1 = n - log(n+1)。因此:

    建堆的时间复杂度为:O(N)

  • 堆排序时间复杂度分析:因为需要n-1次堆重建,每次循环的比较次数为log(i)—与高度相关,t(n) = log2+log3+…+log(n-1)+log(n) ≈ log(n!)。因为log(n!)和nlog(n)是同阶函数,因此:

    堆排序的时间复杂度为:O(N*logN)

三、代码实现(c语言)

该代码旨在排降序(小堆)。

  • heap.h
//heap.h
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

typedef int HPDataType;
typedef struct Heap {
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;

//堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n);
//向下调整
void AdjustDown(HPDataType* a, int n, int root);
//向上调整
void AdjustUp(HPDataType* a,int n, int child);
//堆的销毁
void HeapDestory(Heap* hp);
//堆的插入
void HeapPush(Heap* hp, HPDataType x);
//堆的删除
void HeapPop(Heap* hp);
//取堆顶的数据
HPDataType HeapTop(Heap* hp);
//堆数据个数
int HeapSize(Heap* hp);
//堆的判空
int HeapEmpty(Heap* hp);
//交换数据
void Swap(HPDataType* t1, HPDataType* t2);
//堆数组进行堆排序
void HeapSort(int* a, int n);
//TopK问题
void TestTopK(Heap* hp, int k);
void PrintTopK(Heap* hp, int n, int k);
  • heap.c
//heap.c
#include"Heap.h"

//堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n)
{
	hp->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	//void *memcpy(void *destin, void *source, unsigned n);
	assert(hp->_a);
	memcpy(hp->_a, a, sizeof(HPDataType) * n);
	hp->_size = n;
	hp->_capacity = n;
	//向下调整法,从非叶子结点开始,建立小堆
	for (int i = (n - 2) / 2; i >= 0; --i) {
		AdjustDown(hp->_a,hp->_size,i);
	}
}
//向下调整
void AdjustDown(HPDataType* a, int n, int root) {
	int parent = root;
	int child = parent * 2 + 1;
	while (child < n) {
		//找出最小的孩子
		if (child + 1 < n && a[child] > a[child + 1]) {
			child++;
		}
		//判断父节点是否需要调整
		if (a[parent] > a[child]) {
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else {
			break;
		}
	}
}
//向上调整
void AdjustUp(HPDataType* a, int n, int child) {
	int parent = (child - 1) / 2;
	//parent > 0 是错的
	while (child > 0) {
		if (a[parent] > a[child]) {
			Swap(&a[parent], &a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else {
			break;
		}
	}
}
//堆的销毁
void HeapDestory(Heap* hp) {
	assert(hp);
	free(hp->_a);
	hp->_a = NULL;
	hp->_capacity = hp->_size = 0;
}
//堆的插入
void HeapPush(Heap* hp, HPDataType x) {
	assert(hp);
	if (hp->_size == hp->_capacity) {
		HPDataType* temp = (HPDataType*)realloc(hp->_a, sizeof(HPDataType) * hp->_capacity * 2);
		assert(temp);
		hp->_a = temp;
		hp->_capacity *= 2;
	}
	hp->_a[hp->_size++] = x;
	//调整堆--向上调整
	AdjustUp(hp->_a, hp->_size, hp->_size - 1);
}
//堆的删除
void HeapPop(Heap* hp) {
	assert(hp);
	assert(hp->_size);
	Swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
	hp->_size--;
	AdjustDown(hp->_a, hp->_size, 0);
}
//取堆顶的数据
HPDataType HeapTop(Heap* hp) {
	assert(hp);
	assert(hp->_size);
	return hp->_a[0];
}
//堆数据个数
int HeapSize(Heap* hp) {
	assert(hp);
	return hp->_size;
}
//堆的判空
int HeapEmpty(Heap* hp) {
	assert(hp);
	return hp->_size == 0 ? 1 : 0;
}
//交换数据
void Swap(HPDataType* t1, HPDataType* t2) {
	HPDataType temp = *t1;
	*t1 = *t2;
	*t2 = temp;
}
//堆数组进行堆排序
void HeapSort(int* a, int n) {
	
	//建堆
	for (int i = (n - 2) / 2; i >= 0; --i) {
		AdjustDown(a, n, i);
	}
	//时间复杂度:O(N*logN)
	//重建堆一共需要n-1次循环,每次循环的比较次数为log(i)
	//向下调整,堆排序
	int end = n - 1;
	while (end > 0) {
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}
//TopK问题
void TestTopK(Heap* hp, int k) {
	//前k小的数字
	//时间复杂度 O (K*logN)
	while (k) {
		HeapPop(hp);
		k--;
	}
}
void PrintTopK(Heap* hp, int n, int k) {
	while (k) {
		printf("%d ",hp->_a[n - k]);
		k--;
	}
}
  • 测试代码
//test.c
#include"Heap.h"


int main() {
	int a[] = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
	//HeapSort(a, sizeof(a) / sizeof(HPDataType));

	Heap hp;
	HeapCreate(&hp, a, sizeof(a) / sizeof(HPDataType));
	//HeapPush(&hp, 13);
	TestTopK(&hp, 5);
	PrintTopK(&hp, sizeof(a) / sizeof(HPDataType), 5);

	HeapDestory(&hp);
	return 0;
}

github链接 https://github.com/Xiaowei7858/Code-notes.git

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值