重学数据结构系列之——堆及堆排序

19 篇文章 0 订阅
9 篇文章 0 订阅

学习来源:计蒜客

1.定义

满足一下两个条件
1.首先它是一颗完全二叉树(就是除了最后一层,每个结点都有两个孩子,最后一层只缺少右边的若干结点。)看看这个就明白: http://baike.baidu.com/pic/完全二叉树/7773232/0/906289ddefbfa4745882dd18?fr=lemma&ct=single#aid=0&pic=906289ddefbfa4745882dd18

2.越是顶端,结点的权值越大,并且它的权值大于等于它 所在子树的所有结点的权值。(注意这里是所有结点,但不是所有结点之和啦)

2.分类


根结点权值大于等于树中结点权值的堆称为 大根堆
根结点权值小于等于树中结点权值的堆称为 小根堆

3.储存

用数组储存就好,当然我们计算机里面是从0开始编起的



4.实现

#include <iostream>

using namespace std;

class Heap{
private:
	int *data, size;
public:
	//length_input:堆的最大容量
	Heap(int length_input){
		data = new int[length_input];
		size = 0;
	}
	~Heap(){
		delete[] data;
	}
	//插入
	void push(int value){
		//先放在堆中最后一个元素的后一个位置,注意这里的size是堆暂时的大小,跟堆的最大容量是不一样的
		data[size] = value;
		//用current储存插入元素的索引
		int current = size;
		//父亲结点的数组索引
		int	father = (current-1)/2;
		//如果插入的值大于父亲,就交换,注意索引值也要更新
		while (data[current] > data[father]) {
			//值交换
			swap(data[current], data[father]);
			//插入元素的索引,更新为父亲的索引
			current = father;
			//同时也计算出新的父亲的索引
			father = (current-1)/2;
		}
		//插入后,堆的大小+1
		size++;
	}
	//遍历输出
	void output(){
		//就像数组一样就行了
		for (int i = 0; i < size; i++) {
			cout<<data[i]<<" ";
		}
		cout<<endl;
	}
	//返回堆顶元素
	int top(){
		return data[0];
	}
	//自上而下调整堆
	//pos:当前要调整的位置
	//n:当前堆中的元素个数
	void update(int pos, int n){
		//计算出左右孩子的索引值,等下比较pos位置的元素跟其左右孩子元素的大小
		int lchild = 2 * pos + 1, rchild = 2 * pos + 2;
		//初始化这三个的最大值的索引为pos
		int max_value = pos;
		//首先索引要小于堆的大小,其次要值大于max_value位置的值,那么就更新max_value
		if (lchild < n && data[lchild] > data[max_value]) {
			max_value = lchild;
		}
		if (rchild < n && data[rchild] > data[max_value]) {
			max_value = rchild;
		}
		//经过上面的两个if,max_value绝对是三个中最大值得索引了,
		//如果不等于pos,那大的值就往上走,等于pos的话就不用再做任何操作了
		if (max_value != pos) {
			//进入到这里max_value肯定是左右孩子的值了,但我们不用管,有索引值就好
			swap(data[pos], data[max_value]);
			//两个元素值交换后,再递归调整
			update(max_value, n);
		}
	}
	//删除堆顶元素
	void pop(){
		//先将最后一个元素与堆顶元素的值交换
		swap(data[0], data[size-1]);
		//堆的大小减1,就相当于将最后的元素删除了
		size--;
		//再自上而下调整位置0,即新的堆顶的位置,size为堆的大小
		update(0, size);
	}
	//堆排序
	//注:本数据结构的堆为大根堆
	void heap_sort(){
		//从最后一个元素开始,将它与根值交换,再自上而下调整堆
		for (int i = size -1; i >= 1; i--) {
			//与堆顶元素交换,那么交换后最后一个元素data[size-1]的值是最大的,因为是大根堆
			swap(data[i], data[0]);
			//再自上而下调整堆,注意第i+1个及以后已经是升序排列,所以只需调整前i个
			//其实这里是将前i个中最大的值调整到堆顶,即data[0]
			update(0, i);
		}
	}
};

int main(){
	int arr[10] = { 12, 9, 30, 24, 30, 4, 55, 64, 22, 37 };
	Heap heap(100);
	for (int i = 0; i < 10; i++) {
		heap.push(arr[i]);
	}
	//输出
	heap.output();
	cout<<heap.top()<<endl;
	heap.pop();
	heap.output();
	//堆排序
	heap.heap_sort();
	heap.output();
	return 0;
}

5.运行结果





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值