堆排序(最大堆)

一.排序分析

堆排序快速排序归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。

二叉堆的定义:

二叉堆是完全二叉树或者是近似完全二叉树。

二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。下图展示一个最小堆:

由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。

堆的存储

一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。

 

二.代码(C++):

// heapify.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<iostream>
using namespace std;


int heap_size;//保存堆的大小
void build_max_Heap(int *a,int n);
void max_heapify(int *a,int i);
void exchange(int &a,int &b);
void heap_sort(int *a,int n);
int _tmain(int argc, _TCHAR* argv[])
{
	int a[10]={4,1,3,2,16,9,10,14,8,7};
	heap_sort(a,10);
	for (int i = 0; i < 10; i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
	return 0;
}
//建立一颗最大堆
void build_max_Heap(int *a,int n)
{
	heap_size=n;
	for (int i = n/2; i >=1; i--)//从数组中的中间记录开始,不断的调整堆
	{
		max_heapify(a,i);
	}
}
//堆调整
void max_heapify(int *a,int i)
{
	int l=2*i;//i的左孩子下标
	int r=2*i+1;//i的右孩子下标
	int largest=0;//记录i,i的左孩子,i的右孩子中的最大值的下标
	if (l<=heap_size && a[l-1]>a[i-1])
	{
		largest=l;
	}
	else
	{
		largest=i;
	}
	if (r<=heap_size && a[r-1]>a[largest-1])
	{
		largest=r;
	}
	if (largest!=i)//如果最大值的下标不是双亲节点,则需要调整
	{
		exchange(a[i-1],a[largest-1]);
		max_heapify(a,largest);
	}
}
void exchange(int &a,int &b)
{
	int temp=a;
	a=b;
	b=temp;
}
//最大堆排序
void heap_sort(int *a,int n)
{
	build_max_Heap(a,n);
	for (int i = n; i >=2; i--)
	{
		exchange(a[0],a[i-1]);//将第一个记录,即最大的记录与数组的最后一个记录交换位置
		heap_size--;//将堆大小减一
		max_heapify(a,1);//不断的调整最大堆的第一个记录
	}
}


三.结果截屏:

四.时间、空间复杂度及稳定性

时间复杂度:O(nlgn)

空间复杂度:O(1)

不稳定排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最大堆排序的基本操作包括以下几个步骤: 1. 构建最大堆:将待排序的数组构造成一个最大堆最大堆是一种满足父节点大于等于子节点的完全二叉树。构建最大堆的方法是从最后一个非叶子节点开始,依次向上调整每个节点,使其满足最大堆的性质。 2. 交换堆顶元素和最后一个元素:将最大堆的堆顶元素与最后一个元素交换位置,即将最大的元素放到数组的末尾。 3. 调整堆:将剩下的元素重新调整为最大堆。从堆顶开始,比较左右子节点的值,将较大的子节点与父节点交换位置,然后再对交换后的子节点进行调整,直到整个堆重新满足最大堆的性质。 4. 重复步骤2和步骤3,直到所有元素都被排序。 下面是一个用C++实现基于最大堆堆排序的示例: ```cpp #include <iostream> using namespace std; // 调整堆 void adjustHeap(int arr[], int n, int i) { int largest = i; // 初始化最大值为根节点 int left = 2 * i + 1; // 左子节点 int right = 2 * i + 2; // 右子节点 // 如果左子节点大于根节点,更新最大值 if (left < n && arr[left] > arr[largest]) { largest = left; } // 如果右子节点大于根节点,更新最大值 if (right < n && arr[right] > arr[largest]) { largest = right; } // 如果最大值不是根节点,交换根节点和最大值 if (largest != i) { swap(arr[i], arr[largest]); // 递归调整交换后的子节点 adjustHeap(arr, n, largest); } } // 堆排序 void heapSort(int arr[], int n) { // 构建最大堆 for (int i = n / 2 - 1; i >= 0; i--) { adjustHeap(arr, n, i); } // 交换堆顶元素和最后一个元素,并调整堆 for (int i = n - 1; i > 0; i--) { swap(arr[0], arr[i]); adjustHeap(arr, i, 0); } } int main() { int arr[] = {91, 84, 72, 63, 55, 46, 37, 29, 20, 11}; int n = sizeof(arr) / sizeof(arr[0]); heapSort(arr, n); cout << "Sorted array: "; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值