通俗点聊聊算法 - 二叉堆与堆排序

何为二叉堆?

二叉堆嘛,就是特化的二叉树而已。

二叉堆又分为最大堆和最小堆。


何为最大堆

最大堆嘛,任意父节点大等于任何一个子节点的堆。


何为最小堆

最小堆嘛,参考最大堆。


恶补基础文章推荐

好,闲话不多说,如果对二叉树还不了解的话,建议先了解一下
以下内容引起极度舒适,建议先把基础打好。

拥抱STL - 树的导览

二叉树的前中后序遍历


二叉堆的插入

下面皆以最大堆说事儿

插入完全二叉树的最后一个位置,然后不断和父节点比较,不断上浮,指导小于父节点为止。


二叉堆的删除

删除是删除堆顶,别问为什么,就是删堆顶。

删完之后,为了完全二叉树的完整性,将最后一个元素放到堆顶,然后不断比较下沉。(往大的那边沉)


构建二叉堆

本质就是将一棵无序的二叉树通过浮沉构建一棵有序的堆树。

还是说最大堆,从最后一个非叶子节点开始,依次下沉。

再说一下最小堆,从最后一个非叶子节点开始,依次上浮。


堆排序代码

#include<stdio.h>

void swap(int a[],int i,int j)
{
	int temp;
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}
//调整顶堆 使之变成大顶堆或小顶堆
//n是堆中个数 i是根节点
void heapify(int tree[], int n,int i)
{
	if(i>=n)
	{
		return;
	}
	int c1 = 2 * i + 1;//左节点
	int c2 = 2 * i + 2;//右节点
	int max = i;

	if ((c1<n) && (tree[c1] > tree[max]))
	{
		max = c1;
	}
	if ((c2<n) && (tree[c2] > tree[max]))
	{
		max = c2;
	}

	//如果最大值不是在根节点
	if (max != i)
	{
		swap(tree, max, i);
		heapify(tree, n, max);
	}
}

//建造堆
void build_heap(int tree[], int n)
{
	//找到堆中最后一个根结点
	int  last_node = n - 1;
	int parent = (last_node - 1) / 2;
	int i;
	//将这个堆每个根结点进行堆排,则可实现变成一个堆
	for (i = parent; i >= 0; i--)
	{
		heapify(tree, n, i);
	}
}

//堆排序分类
void heap_sort(int tree[], int n)
{
	build_heap(tree, n);
	int i;
	//i是最后一个结点
	for (i = n - 1; i >= 0; i--)
	{
		//将最后一个结点和第一个结点进行交换
		swap(tree, i, 0);
		heapify(tree, i, 0);
	}
}

int main05()
{
	int tree[] = {2,5,3,1,10,4};
	int n = 6;

	printf_s("堆排序后\n");
	//heapify(tree, n, 0);
	//build_heap(tree, n);
	heap_sort(tree,n);
	for (int i = 0; i < n; i++) {
		printf("%d\n", tree[i]);
	}
	return 0;
}



时空复杂度

空:O(1)
时:O(logn)
平均时间复杂度O(nlogn)


堆排序VS快速排序

要是对快速排序不熟,别怕,我也有:通俗点聊聊算法 - 快速排序(亲测)

堆排序和快速排序的平均时间复杂度都是 O(nlogn),且都是不稳定排序。
不过,堆排序的最坏时间复杂度稳定在O(nlogn),快速排序的最坏时间复杂度为O(n^2)。
此外,快速排序的空间复杂度更高,为O(nlogn)。


为什么我更倾向于快速排序?

因为上面的比对是基于堆建立完的情况下。如果一次排序多次取最值,我会考虑堆排序。注意,多次、最值!


是不是感觉节奏太快啦,我也觉着快了点。小场面,没事

原创文章 153 获赞 719 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_43762191/article/details/105849980
今日推荐