102.【C语言】数据结构之用堆对数组排序

0.前置知识

向上调整:

向下调整:

1.对一个无序的数组排升序和降序

排升序问题

建大根堆还是小根堆?

错误想法

由小根堆的定义:树中所有的父节点的值都小于或等于孩子节点的值,这样排出来的数组时升序的,建小根堆调用向上调整函数即可(把画圈的地方改成<即可)

arr未排序时,为{2,1,5,7,6,8,0,9,4,3}

执行结果

显然不是升序

错误原因:忽略了一个严重的前提: 向上调整的前提:除了child位置,前面的数据结构构成堆

AdjustUp虽然找到了数组中最小的数,将其放到堆顶,但是堆顶的左右子树是无序的,必须将堆顶元素pop后才能选出剩余元素中最小的

解决方法

1.重新建堆:时间复杂度过高,不建议使用

2.建大根堆

代码

cpp 复制代码
typedef int HPDataType;

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (parent>=0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[parent], &a[child]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child+1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(int* arr, int n)
{
	for (int i = 1; i < n; i++)
	{
		AdjustUp(arr, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[end], &arr[0]);
		AdjustDown(arr, end, 0);
		end--;
	}
}

int main()
{
	int arr[] = {2,1,5,7,6,8,0,9,4,3};
	int size = sizeof(arr)/sizeof(arr[0]);
	HeapSort(arr,size);
	return 0;
}

运行结果

细节分析

将HeapSort的while循环删掉,在return 0;处下断点,监视窗口查看arr

建大堆后

要好好利用大堆的这一个性质**:堆顶元素的值永远是堆中元素的最大值**

用while反复调整的过程可以描述为:

大堆1=={大堆2,大堆1中最大的元素}

大堆2=={大堆3,大堆2中最大的元素} -->大堆1=={大堆3,大堆2中最大的元素,大堆1中最大的元素}

大堆3=={大堆4,大堆3中最大的元素}

...

大堆(n-1)=={大堆n,大堆(n-1)中最大的元素}

将上方的式子合并起来,有

大堆1={大堆n,大堆(n-1)中最大的元素,大堆(n-2)中最大的元素,...,大堆2中最大的元素,大堆1中最大的元素}

满足升序的要求

思考题

改动以上代码,使其对数组排降序

答案:理解上述分析的核心要点后,只需要改动几个不等号就可以了

cpp 复制代码
typedef int HPDataType;

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (parent >= 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[parent], &a[child]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(int* arr, int n)
{
	for (int i = 1; i < n; i++)
	{
		AdjustUp(arr, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[end], &arr[0]);
		AdjustDown(arr, end, 0);
		end--;
	}
}

int main()
{
	int arr[] = { 2,1,5,7,6,8,0,9,4,3 };
	int size = sizeof(arr) / sizeof(arr[0]);
	HeapSort(arr, size);
	return 0;
}

运行结果

相关推荐
钢门狂鸭2 小时前
关于rust的crates.io
开发语言·后端·rust
Lionel_SSL2 小时前
《深入理解Java虚拟机》第三章读书笔记:垃圾回收机制与内存管理
java·开发语言·jvm
Greedy Alg3 小时前
LeetCode 142. 环形链表 II
算法
睡不醒的kun3 小时前
leetcode算法刷题的第三十二天
数据结构·c++·算法·leetcode·职场和发展·贪心算法·动态规划
技术猿188702783513 小时前
PHP 与 WebAssembly 的 “天然隔阂”
开发语言·php·wasm
薄荷撞~可乐3 小时前
C#Task(Api)应用
开发语言·c#
范纹杉想快点毕业3 小时前
ZYNQ PS 端 UART 接收数据数据帧(初学者友好版)嵌入式编程 C语言 c++ 软件开发
c语言·笔记·stm32·单片机·嵌入式硬件·mcu·51单片机
先做个垃圾出来………3 小时前
残差连接的概念与作用
人工智能·算法·机器学习·语言模型·自然语言处理
SuperCandyXu5 小时前
P3205 [HNOI2010] 合唱队-普及+/提高
c++·算法·洛谷
another heaven5 小时前
【Qt VS2022调试时无法查看QString等Qt变量信息】解决方法
开发语言·qt