八大排序学习之七堆排序

我们学习堆排序之前需要弄清堆的概念,计算机常说的堆有两种一种是操作系统上的堆内存,还有一种是数据结构上的堆,今天我们来讲数据结构上的堆,数据结构上的堆也有几种,二叉堆,二项堆,斐波那契堆,通常我们把二叉堆成为简称为堆。

堆排序也是一种效率很高的排序,平均时间复杂度为:O(nlogn)

二叉堆是一种完全二叉树,其中非叶结点与父节点的关系总满足,i<=2*1+1&&i<=2*(i+1)或者i>=2*1+1&&i>=2*(i+1)的关系,i为父节点

其中,i<=2*1+1&&i<=2*(i+1)称为小顶堆,i>=2*1+1&&i>=2*(i+1)称为大顶堆。

堆排序的思想如下:

首先将指定的一组数转化成大顶堆或者小顶堆,通过父节点与子节点的比较进行前后替换,通过递归遍历所有节点,每次从顶部取出未排序的最大值跟未排序的最后一个交换, 例如:堆A[0,n-1],先交换a[0]和A[n-1],调整堆,交换A[0]和A[n-2],调整堆......,交换A[0]和a[1],交换完毕。

得出排序结果。

(初始化堆,循环(交换顶部和未排序的最后一个,调整堆)。

举个例子:

第一步、给个数组a[4]={3,1,2,4}

转换得一二叉树

   3

1    2

4

第二步、堆化,从第一个非叶结点开始调整,左子节点,1和4交换得

   3

4    2

1

第三步继续堆化,3跟4交换得初始大顶堆

   4

3    2

1

下面为关键步骤:

第四步,将最顶的与最后的交换,把最大的放到最后面的节点。

  1 

3  2

4

交换了之后,明显1和3不符合堆的概念,因为需要继续调整

  3

1  2

最顶的和未排序的最后一个交换,3和2交换得

  2

1  3

4

2和1交换得

  1

2   3

节点访问完毕,得结果。

 关键代码:

void max_heapify(int*arr,int index,int len)
{
  int l=2*index+1;
  int r=2*(index+1);
  int largest;
  if(l<len&&arr[l]>arr[index])
    largest=l;
  else
    largest=index;
  if(r<len&&arr[r]>arr[largest])
    largest=r;
  if(largest!=index)
  {
    //将最大元素提升,并递归
    myswap(&arr[largest],&arr[index]);
    max_heapify(arr,largest,len);
  }
}
下面给出完整代码:

// List.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<stdlib.h>
#include <time.h> 
#define NUMLEN 20000

 
inline void myswap(int*a,int*b)
{
  *a=*a^*b;  
  *b=*a^*b;  
  *a=*a^*b;  
}

void max_heapify(int*arr,int index,int len)
{
  int l=2*index+1;
  int r=2*(index+1);
  int largest;
  if(l<len&&arr[l]>arr[index])
    largest=l;
  else
    largest=index;
  if(r<len&&arr[r]>arr[largest])
    largest=r;
  if(largest!=index)
  {
    //将最大元素提升,并递归
    myswap(&arr[largest],&arr[index]);
    max_heapify(arr,largest,len);
  }
}
void build_maxheap(int*arr,int len)
{
	//建立大顶堆
  int i;
  if(arr==NULL||len<=1)
    return;
  for(i=len/2+1;i>=0;--i)
    max_heapify(arr,i,len);
}
void heap_sort(int*arr,int len)
{
  int i;
  if(arr==NULL||len<=1)
    return;
  build_maxheap(arr,len);
 
  for(i=len-1;i>=1;--i){
    myswap(&arr[0],&arr[i]);
    max_heapify(arr,0,--len);
  }
}

int main(int argc, char* argv[])
{
	int a[NUMLEN];

	srand((int)time(NULL));
	for(int i=0;i<NUMLEN;i++)
		a[i]=rand()%NUMLEN;
		float nstart=clock();
	heap_sort(a,NUMLEN);
	for(i=0;i<NUMLEN;i++)
		printf("%d\n",a[i]);
	float nend=clock();
	printf("共用时%.3fs\n",(nend-nstart)/1000);
	return 0;
}
20000个数据的时间情况:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值