HeapSort堆排序原理与实现

HeapSort堆排序原理与实现

  堆排序是比较重要的数据结构,其主要优点是通过排序二叉树的特性能够记录每个数之间的大小关系,以至于不需要重复比较,对于海量数据排序问题可以减少时间复杂度。

一、基本概念

(1)大根堆(大顶堆):对于一个堆(完全二叉树),根结点的值是比所有结点的值都大,其子树中根结点的值也比子树中其他值都大。大根堆可以获得由小到大的递增序列;其定义为:
A [ i ] ≥ A [ 2 ∗ i ] A[i]\ge A[2*i] A[i]A[2i] A [ i ] ≥ A [ 2 ∗ i + 1 ] A[i]\ge A[2*i+1] A[i]A[2i+1]
(2)小根堆(小顶堆):与大根堆正好相反,定义为:
A [ i ] ≤ A [ 2 ∗ i ] A[i]\le A[2*i] A[i]A[2i] A [ i ] ≤ A [ 2 ∗ i + 1 ] A[i]\le A[2*i+1] A[i]A[2i+1]
例如:下图中,根结点是最大值,且所有子树中的根结点也都是最大值,所以这是一个大根堆
在这里插入图片描述

二、算法原理

  我们以大根堆为例。进行堆排序时,主要分为两步:构建大根堆和调整大根堆。构建大根堆时我们是自底向上的进行比较,使得每次构建的堆都是大根堆;当构建完毕后,每次则是自顶向下的进行比较,保证形成新的大根堆。给定一个无序数列,基本流程为:

一、构建大根堆
(1)按照完全二叉树的层序顺序,插入叶子结点;
(2)比较该叶子结点与其父结点,如果比父结点大,则与父结点交换,此时可以保证当前的子树是大根堆;
(3)如果(2)执行过交换,则再与上一层父结点比较,以此类推,直到不交换为止;
(4)重复(1)-(3),直到所有数都添加至这个树中;
二、调整大根堆
(5)此时根结点时最大值,将其与树中最后一个结点进行交换,并将这个最大值剔除这个树;
(6)对剩下的n-1个数进行调整,自顶向下的进行判断,如果根结点比两个孩子结点的最大值要小,则把最大值与根结点交换;
(7)重复(6),直到不交换为止,此时形成了新的大根堆;
(8)重复步骤(5)-(7),直到这个树为空,此时我们可以得到一个有序的数列。

  我们给出一个例子:使用堆排序对数列 4 1 16 9 10 8 7 进行递增排序。

一、构建大根堆

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
此时,所有数都插入到大根堆里
在这里插入图片描述
二、调整大根堆
自顶向下的保证每个子树都是大根堆,蓝色表示已经剔除的结点。
在这里插入图片描述

根结点与树中最后一个节点交换,并剔除
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们可以得到一个有序序列: 1 4 7 8 9 10 16;
事实上,如果想获得递减序列,除了使用小根堆方法,也可以对大根堆的序列做反置。

伪代码如下图:
(1)构建大根堆
在这里插入图片描述
(2)调整大根堆
在这里插入图片描述

(3)算法的整体(先自底向上构建,再自顶向下调整)
在这里插入图片描述

三、例题

给出n个坐标点<x1,y1>, <x2, y2>……<xn, yn>,请对他们进行堆排序。坐标点的大小关系是:如果 xi> xj, 则
<xi,yi> 大于 <xj, yj>;若 xi=xj 且 yi >yj, 那么同样有<xi,yi> 大于 <xj, yj>。

在这里插入图片描述

思路:只用大根堆对坐标排序,这里只需要将上述的算法中做一点微调,即重写一下比较函数。

(1)定义结点(数据类型):

class Node {
	public:
		int x; //x坐标 
		int y; //y坐标
	public:
		int getX(){
			return x;
		}
		int getY(){
			return y;
		}
		int setXY(int x, int y){
			this->x = x;
			this->y = y;
		}
};

(2)定义堆排序类,这里面包含上述伪代码包括的三个方法。

class Heap {
	public:
		int size;
		void heapSort(Node a[], int n); //排序 
		void maxHeap(Node a[], int n); //调整大根堆 
		void buildMaxHeap(Node a[], int n); //构建大根堆 
}; 


void Heap::heapSort(Node a[], int n){
	int i;
	buildMaxHeap(a, n);
	for (i = size; i>1; i--)
	{
		swap(a[0], a[i-1]); //交换 
	    size = size - 1;
		maxHeap(a, 1);
 
 
	}
 
}
void Heap::buildMaxHeap(Node a[], int n){
	int i = n / 2;
	for (i; i > 0; i--)
		maxHeap(a, i);
 
}
void Heap::maxHeap(Node a[], int n){
	int leftChild, rightChild, largest;
	leftChild = 2 * n;
	rightChild = 2 * n + 1;
//	int q = sizeof(a);
	if (leftChild <= size && compare(a[leftChild-1], a[n-1]))
		largest = leftChild;
	else
		largest = n;
	if (rightChild <= size && compare(a[rightChild-1], a[largest-1]))
		largest = rightChild;
	if (largest != n){
		
		swap(a[n-1], a[largest-1]);
		maxHeap(a, largest);
	}
}

(3)比较函数

int compare(Node A, Node B){
	if(A.x > B.x){
		return true;
	}else if(A.x == B.x && A.y > B.y){
		return true;
	}
	return false;
}

(4)入口函数

int main(){
	Node a[100];
	Heap t;
	int size = 0;
	cin>>size;
	t.size = size;
	for(int i=0;i<size;i++){
		int x, y;
		cin>>x>>y;
		a[i].setXY(x,y);
	} 
	t.heapSort(a, size);
	int yes = 0;
	for (int i = 0; i < size; i++){
		if(yes == 0){
			yes = 1;
		}else {
			cout<<'\n';
		}
		cout << "(" << a[i].getX() << "," << a[i].getY() << ")";
	}
	return 0;
}

运行效果

在这里插入图片描述


  博客记录着学习的脚步,分享着最新的技术,非常感谢您的阅读,本博客将不断进行更新,希望能够给您在技术上带来帮助。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

华师数据学院·王嘉宁

$感谢支持$

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值