一.排序分析
堆排序与快速排序,归并排序一样都是时间复杂度为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)
不稳定排序