【堆】堆排

文章目录

  • 前言:
  • 如何实现堆排
    • 什么是堆排?
    • 那我们如何自己实现一个堆排呢(以降序为例)?
    • 思想及步骤(以 17,20,10,13,19,15为例)
  • 注意:推荐大家使用向下建表法,因为向下建表法时间复杂度为O(n),向上建堆法时间复杂度为O(n*logn),想知道为什么下期博客揭晓。


前言:

相信看到这篇文章的柚柚们对于堆这个数据结构有啦一定的了解,至少清除堆是什么啦,当然可能有些柚柚们还不了解堆,可以去看博主之前写的关于堆(Heap)的博客喔链接在这里点击即可~


如何实现堆排

什么是堆排?

堆排:顾名思义是利用堆这种数据结构所设计的排序算法。

那我们如何自己实现一个堆排呢(以降序为例)?

  • 我相信肯定会有柚柚们想到把数据都放在一个大堆里,然后每次取堆顶元素放到数组里面,再把堆顶元素删掉,进行向下调整,_size–,重复该操作,直到_size<=0。
  • 代码如下:
void test()
{
	Heap hp;
	HeapInit(&hp);
	//建立一个数组对数组进行排序
	int arr[] = { 17,20,10,13,19,15 };
	//将数组元素放进小堆
	for (int i = 0; i < 6; i++)
	{
		HeapPush(&hp, arr[i]);
	}

	int i = 0;
	//每次取堆顶元素依次放入数组中,再把堆顶元素删除
	while (!HeapEmpty(&hp))
	{
		arr[i++] = HeapTop(&hp);
		HeapPop(&hp);
	}
	//输出数组
	for (int i = 0; i < 6; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	//销毁堆
	HeapDestroy(&hp);
}

注意:用这种方法空间复杂度为O(n),因为建堆需要额外开辟空间,那我们如何把空间复杂度降为O(1)呢,也就是说我们如何在原数组的基础之上完成排序,其实我们只需要利用堆的插入和删除中的向上调节法或者向下调节法,就可以做到~

思想及步骤(以 17,20,10,13,19,15为例)

思想:我们想要在原数组的基础上建堆然后排序的话,就只能采用这种方法,在原数组的基础上建好小堆(大堆)后,重复进行删除堆顶的操作,直到堆为空,此时数组的顺序则为降序(升序)。
删除堆顶的代码:

void HeapPop(Heap* php)
{
	assert(php && php->size);
	
	Swap(&php->arr[0], &php->arr[php->size - 1]);

	--php->size;

	AdjustDown(php->arr, 0, php->size);
}

步骤:
1.我们就在原数组上利用向上调节法(也可以用向下调节法建堆)建大堆,看文字可能不太理解,那就看看几张图叭。

第一步:插入17,此时为根节点不需要调整,插入成功。在这里插入图片描述
第二步:插入20,此时其有父结点,与父节点比较大小,比父节点大,不需要交换,插入成功。
在这里插入图片描述
第三步:插入10,有父节点,则跟父节点比大小,比父节点小,与父节点交换,此时孩子结点指向根节点,不需要进行其它操作,插入成功。
在这里插入图片描述
第四步到第六步我就不赘述啦,会堆的插入就会啦。这里举例子也只是让大家知道在原数组如何建堆,其实和建堆思想是一样哒。

2.建完堆啦我们就可以排序啦,排序的思想其实和这个我们刚开始的思想是一样哒,用一个变量end储存剩下的数据最后一个的下标,然后让堆顶数据与arr[end]进行交换,end–,再对堆顶元素进行向下调整,一直重复直到end<=0,这样我们就完成啦排序。看文字太枯燥,那就看看图片叭~

第一步:堆顶元素10与arr[end]交换,此时end为5,然后end–,end = 4,再对堆顶元素进行向下调整,调整后如第二个图所示。
在这里插入图片描述
在这里插入图片描述
第二步:堆顶元素13与arr[end]交换,此时end为4,然后end–,end = 3,再对堆顶元素进行向下调整,调整后如第二个图所示。
在这里插入图片描述
在这里插入图片描述
后面过程也差不多都是一直重复这个步骤,所以博主也不多赘述,直接上代码啦

代码如下:

void HeapSort(int* arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		AdjustUp(arr, i);
	}

	//向下调整算法建堆
	//for (int i = (n-1-1)/2; i >= 0; i--)
	//{
	//	AdjustDown(arr, i , n);
	//}

	//循环将堆顶数据跟最后位置的数据进行交换
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, 0, end);
		end--;
	}
}

注意:推荐大家使用向下建表法,因为向下建表法时间复杂度为O(n),向上建堆法时间复杂度为O(n*logn),想知道为什么下期博客揭晓。

### 回答1: : ``` import heapq def sort_k_messed_array(arr, k): n = len(arr) heap = arr[:k+1] heapq.heapify(heap) ans = [] for i in range(k+1, n): ans.append(heapq.heappop(heap)) heapq.heappush(heap, arr[i]) while heap: ans.append(heapq.heappop(heap)) return ans ``` 这是一个将长度为 `n` 的数组排序的代码,其中 `k` 是排序前数组中的最大错排数。它使用了 Python 的 `heapq` 库,该库实现了最小。 整个代码的思路是:首先将前 `k+1` 个数存储在中,然后在剩余的数中逐个弹出顶元素,并将当前元素推入中。最后,当为空时,将所有剩余元素弹出并将其添加到答案数组中。 ### 回答2: 堆排序(Heap Sort)是一种基于比较的排序算法,使用二叉数据结构来实现。 以下是一个Python实现的堆排序代码: ```python def heapify(arr, n, i): largest = i # 将当前节点设为最大值 left = 2 * i + 1 # 左子节点的索引 right = 2 * i + 2 # 右子节点的索引 # 如果左子节点存在且大于根节点,则将其设为最大节点 if left < n and arr[i] < arr[left]: largest = left # 如果右子节点存在且大于根节点和左子节点,则将其设为最大节点 if right < n and arr[largest] < arr[right]: largest = right # 如果最大节点不是根节点,则交换它们 if largest != i: arr[i], arr[largest] = arr[largest], arr[i] # 对交换后的子节点递归调用heapify函数 heapify(arr, n, largest) def heap_sort(arr): n = len(arr) # 构建最大 for i in range(n//2 - 1, -1, -1): heapify(arr, n, i) # 依次取出顶元素,并重新构建最大 for i in range(n-1, 0, -1): arr[i], arr[0] = arr[0], arr[i] heapify(arr, i, 0) return arr ``` 上述代码中,`heapify`函数用于将数组调整为一个最大,`heap_sort`函数用于对数组进行堆排序。首先,`heapify`函数通过递归的方式将当前节点与其子节点相比较,如果发现子节点比当前节点大,则交换两者,在交换后需要对子节点进行递归调用以确保调整后的仍然满足最大的条件。 在`heap_sort`函数中,首先构建一个最大,从树的倒数第二层开始(即`n//2 - 1`),往上逐层调用`heapify`函数进行调整。然后,通过循环依次取出最大顶元素(即根节点),并将其与数组最后一个元素进行交换。交换后,需要对交换后的顶元素重新进行调整,以保证剩余元素仍然满足最大的条件。最后得到的数组就是按照从小到大排序的结果。 堆排序的时间复杂度是O(nlogn),其中n是数组的长度。在实际应用中,堆排序常用于需要稳定排序的场景,以及需要部分排序的场景(如找出前k个最大/最小元素)。 ### 回答3: 堆排序(Heap Sort)是一种使用最大(Max Heap)或最小(Min Heap)数据结构进行排序的算法。下面是一个使用Python实现的堆排序代码: ```python # 堆排序函数 def heap_sort(arr): n = len(arr) # 构建最大 for i in range(n // 2 - 1, -1, -1): heapify(arr, n, i) # 逐个将最大元素移到末尾 for i in range(n-1, 0, -1): arr[i], arr[0] = arr[0], arr[i] # 交换根节点和最后一个节点的值 heapify(arr, i, 0) # 调整函数 def heapify(arr, n, i): largest = i left = 2 * i + 1 right = 2 * i + 2 # 检查左子节点是否存在并大于根节点 if left < n and arr[largest] < arr[left]: largest = left # 检查右子节点是否存在并大于根节点 if right < n and arr[largest] < arr[right]: largest = right # 如果根节点不是最大值,则交换根节点和最大子节点的值 if largest != i: arr[i], arr[largest] = arr[largest], arr[i] # 递归调整 heapify(arr, n, largest) # 测试用例 arr = [12, 11, 13, 5, 6, 7] heap_sort(arr) print("排序后的数组:") for i in range(len(arr)): print(arr[i]) ``` 这段代码中,首先构建一个最大,然后进行堆排序。构建的操作是从数组中的中间位置往前遍历,每个节点都进行调整的操作,保证每个父节点的值都大于等于其子节点的值。然后,将顶元素与末尾元素交换,再对剩余元素进行调整的操作。重复这个过程,直到整个数组排序完成。最后,打印排序后的结果。运行结果为:5 6 7 11 12 13。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值