堆排序

1、前言:选择排序

void Selection_Sort(ElementType A[], int N)
{
	for (i = 0; i < N; i++)
	{
		MinPosition = ScanForMin(A, i, N–1);
		//从A[i]到A[N–1]中找最小元,并将其位置赋给MinPosition
		Swap(A[i], A[MinPosition]);
		//将未排序部分的最小元换到有序部分的最后位置
	}
}

无论如何: T = θ(N2)

问题:如何快速找到最小元???

2、堆排序

在堆排序中,元素下标从0开始。则对于下标为i的元素,其左、右孩子的下标分别为:2i+1, 2i+2

算法1
void Heap_Sort(ElementType A[], int N)
{
	BuildHeap(A);			//O(N)
	for (i = 0; i<N; i++)
		TmpA[i] = DeleteMin(A); //O(logN)
	for (i = 0; i<N; i++)		//O(N)
		A[i] = TmpA[i];
}

时间复杂度:T(N) = O(N log N)
缺点:需要额外O(N)空间,并且复制元素需要时间。

算法2

把元素组织成一个大顶锥,取出最大元素与最后一个元素交换,再将最后一个元素移除大顶锥,剩下的元素再组织成大顶锥,取最大值与锥最后一个元素交换,如此重复。

void Heap_Sort(ElementType A[], int N)
{
	for (i = N / 2 - 1; i >= 0; i--)//BuildHeap
		PercDown(A, i, N);
	for (i = N - 1; i>0; i--)
	{
		Swap(&A[0], &A[i]);	//DeleteMax
		PercDown(A, 0, i);
	}
}
  • 定理:堆排序处理N个不同元素的随机排列的平均比较次数是
    2N logN - O(Nlog logN) 。
  • 虽然堆排序给出最佳平均时间复杂度,但实际效果不如用Sedgewick增量序列的希尔排序。

完整c++代码

#include<iostream>
using namespace std;
typedef int ElementType;
//A存放堆的数组,P要调整的根节点位置,N,整个堆的大小
void PercDown(ElementType*A,int P,int N)//P 为下标,从 0 开始,N:整个堆的大小,3 个元素就是 3
{
	int parent, child;
	ElementType tmp = A[P];//保存根节点的值
	for (parent = P; (parent * 2 + 1) < N; parent = child)//根节点为P,从P开始向下
	{//父节点的左孩子为parent*2+1
		child = parent * 2 + 1;
		if (child != N - 1 && A[child + 1] > A[child])
			child++;		//Child指向左右子结点的较大者
		if (tmp > A[child])		//找到了合适位置
			break;
		else				//下滤
			A[parent] = A[child];
	}
	A[parent] = tmp;
}

void Heap_Sort(ElementType *A, int N)
{
	for (int i = N/2-1; i >= 0; i--)//最后一个节点的父节点为N/2-1
		PercDown(A,i,N);

	for (int i = N - 1; i > 0; i--)
	{
		swap(A[0],A[i]);
		PercDown(A,0,i);
	}
}

int main()
{
	int a[] = { 4, 6, 1, 8, 9, 3, 7, 0 };
	int len = sizeof(a) / sizeof(a[0]);
	Heap_Sort(a, len);
	for (int i = 0; i < len; i++)
		cout << a[i] << " ";
	cout << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值