排序算法--堆排序(大根堆实现)
堆排序的平均时间复杂度 :O(N*logN)
空间复杂度:O(1)
堆排序算法的演示。首先,将元素进行重排,以匹配堆的条件。图中排序过程之前简单的绘出了堆树的结构。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LEFT 2*nRootID+1
#define RIGHT 2*nRootID+2
//1.建初始堆
// (1)从最后一个父亲节点开始
// 1.1比较左右孩子大小
// 1.2拿大的和父亲比较
// 比父亲大:与父亲交换,被交换位置作为新的被调整节点,重复1.1和1.2
// 比父亲小:结束,进行下一个父亲节点 的调整
//2.排序
// 2.1 拿堆顶与当前数组的最后位置值交换
// 2.2最后位置元素不参与运算
//
//调整父亲节点
void Adjust(int a[],int nlen,int nRootID)
{
while (1)
{
//两个孩子
if(RIGHT<nlen)
{
//比较两个孩子大小,大的和父亲交换值
if(a[LEFT]>a[RIGHT])
{
if(a[LEFT]>a[nRootID])
{
//和父亲节点值交换
a[LEFT]^=a[nRootID];
a[nRootID]^=a[LEFT];
a[LEFT]^=a[nRootID];
nRootID=LEFT;
continue;
}
else
{
break;
}
}
else
{
if(a[RIGHT]>a[nRootID]){
a[RIGHT]^=a[nRootID];
a[nRootID]^=a[RIGHT];
a[RIGHT]^=a[nRootID];
nRootID=RIGHT;
continue;
}
else
{
break;
}
}
}
//一个孩子
else if (LEFT<nlen)
{
if(a[LEFT]>a[nRootID])
{
//大的和父亲交换
a[LEFT]^=a[nRootID];
a[nRootID]^=a[LEFT];
a[LEFT]^=a[nRootID];
nRootID=LEFT;
continue;
}
else
{
break;
}
}
else
{
//没有孩子
break;
}
}
}
void Adjust2(int a[],int nlen,int nRootID)
{
int MAX;
for(MAX=LEFT;MAX<nlen;MAX=LEFT)
{
//2个孩子
if(RIGHT<nlen)
{
if(a[RIGHT]>a[LEFT])
{
MAX=RIGHT;
}
}
//大的和父亲节点交换
if(a[MAX]>a[nRootID])
{
a[MAX]^=a[nRootID];
a[nRootID]^=a[MAX];
a[MAX]^=a[nRootID];
nRootID=MAX;
}
else
{
break;
}
}
}
void HeapSort(int a[],int nlen)
{
int i;
if(a==NULL ||nlen<=0) return ;
//从最后一个父亲节点开始调整
for(i=nlen/2-1;i>=0;i--)
{
//Adjust(a,nlen,i);
Adjust2(a,nlen,i);
}
//排序
for(i=nlen-1;i>0;i--)
{
//Adjust(a,nlen,i);
Adjust2(a,nlen,i);
}
//排序
for(i=nlen-1;i>0;i--)
{
//从最后一个父亲节点开始调整为大根堆
a[0]^=a[i];a[i]^=a[0];a[0]^=a[i];//重新调整堆顶
//Adjust2(a,i,0);
Adjust2(a,i,0);
}
}
int main()
{
int i;
int a[]={5,3,2,1,4,6,8,9,7};
int len=sizeof(a)/sizeof(a[0]);
HeapSort(a,len);
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
system("pause");
return 0;
}
//Adjust2(a,i,0);
Adjust2(a,i,0);
}
}
int main()
{
int i;
int a[]={5,3,2,1,4,6,8,9,7};
int len=sizeof(a)/sizeof(a[0]);
HeapSort(a,len);
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
system("pause");
return 0;
}
更新:C++11 实现堆排序
#include <iostream>
#include <vector>
using namespace std;
void adjust(vector<int>& nums, int len, int index)
{
// 定义左右孩子
int left = 2*index+1;
int right = 2*index+2;
int maxIndex = index;
// 判断左右孩子和index和大小
if(left < len && nums[left] > nums[maxIndex]) {
// 交换
// swap(nums[left], nums[maxIndex]);
// 更新当前最大节点位置
maxIndex = left;
}
if(right < len && nums[right] > nums[maxIndex]) {
// swap(nums[right], nums[maxIndex]);
maxIndex = right;
}
// 交换
if(maxIndex != index) {
swap(nums[maxIndex], nums[index]);
adjust(nums, len, maxIndex);
}
}
void HeapSort(vector<int>& nums, int len)
{
if (nums.size() == 0 || len <= 1) return;
// 构建一个大根堆 从最后一个非叶子节点开始向前构建
// 数组从下标0开始,父亲节点坐标范围:i = 0-- len/2-1
// 左孩子:2*i+1
// 右孩子:2*i+2
for(int i = len/2-1; i >=0; i--)
{
adjust(nums, len, i);
}
// 堆顶和最后一个元素交换,剩余堆调整
for(int i = len - 1; i > 0; i--)
{
// 拿出堆顶和最后一个元素交换
swap(nums[i], nums[0]);
// 剩余数组继续调整堆结构
adjust(nums, i, 0);
}
}
int main()
{
vector<int> a = {5,9,6,2,7,4,3};
int len = a.size();
HeapSort(a, len);
for(int i = 0; i < len; i++){
cout << a[i] << " ";
}
return 0;
}